Open rjsalem opened 6 years ago
Within your code you are using require()
function which is meant to include JS-files. Whereas electronPath
points to binary linux executable (ELF - Executable and Linking Format).
If you use use it without require it should work:
var nightmare = Nightmare({
show: true,
electronPath: electronPath
});
In order to make Electron run on lambda, you would need to follow very precisely the steps outlined in the README
I would recommend to scaffold your project with this code:
cd nightmare-tut-hello
npm init -y
npm install nightmare
mkdir -p lib/bootstrap
wget -O lib/bootstrap/nightmare-lambda-pack.js https://raw.githubusercontent.com/dimkir/nightmare-lambda-tutorial/master/lib/bootstrap/nightmare-lambda-pack.js
wget -O lib/bootstrap/xvfb.js https://raw.githubusercontent.com/dimkir/nightmare-lambda-tutorial/master/lib/bootstrap/xvfb.js
And later create your main script index.js
using EXACTLY THIS structure:
Within this code, your
electronPath
is provided by thebinaryPack
module, which is responsible for downloading electron binary version for Lambda. And also you have flagisOnLambda
which allows you to run the same script both on labmda and local machine (for debugging) without extra modifications.
var
binaryPack = require('./lib/bootstrap/nightmare-lambda-pack'), // WIP: should be `require('nightmare-lambda-pack')`
Xvfb = require('./lib/bootstrap/xvfb'), // WIP: should be `require('xvfb')`
Nightmare = require('nightmare')
;
var isOnLambda = binaryPack.isRunningOnLambdaEnvironment;
var electronPath = binaryPack.installNightmareOnLambdaEnvironment();
exports.handler = function(event, context){
var xvfb = new Xvfb({
xvfb_executable: '/tmp/pck/Xvfb', // Xvfb executable will be at this path when unpacked from nigthmare-lambda-pack
dry_run: !isOnLambda // in local environment execute callback of .start() without actual execution of Xvfb (for running in dev environment)
});
xvfb.start((err, xvfbProcess) => {
if (err) context.done(err);
function done(err, result){
xvfb.stop((err) => context.done(err, result));
}
// ...
// Main logic with call to done() upon completion or error
// ...
var nightmare = Nightmare({
show: true, // show actual browser window as Nightmare clicks through
electronPath: electronPath // you MUST specify electron path which you receive from installation
});
nightmare
.goto('https://duckduckgo.com')
.type('#search_form_input_homepage', 'github nightmare')
.click('#search_button_homepage')
.wait('#r1-0 a.result__a')
.evaluate(function () {
return document.querySelector('#r1-0 a.result__a').href;
})
.end()
.then(function (result) {
console.log(result);
done(null, result); // done() instead of context.done()
})
.catch(function (error) {
console.error('Search failed:', error);
done(error); // done() instead of context.done()
});
});
};
I followed all the steps with your example. No problem happened. But I never get a response and the timeout limit is always reach even if i put 2 minutes for the timeout.
It would be helpful if you can post additional details of your problem:
aws lambda get-function-configuration --function-name your-funciton
would be helpful)those will help me understand your problem better and come up with solutions.
ps. and additional question - does your script run correctly on local machine?
Hi, I found what is the cause but I dont know how I can make it work.
In Index.js I initialize everything and I have a package named Test. I call test.scrap to execute nightmare. If the nightmare code is in the index file it will work, but if I use my Test package it won't.
Index.js :
// index.js
var binaryPack = require('./lib/bootstrap/nightmare-lambda-pack');
var Xvfb = require('./lib/bootstrap/xvfb');
var Nightmare = require('nightmare');
var test = require('./test');
var isOnLambda = binaryPack.isRunningOnLambdaEnvironment;
var electronPath = binaryPack.installNightmareOnLambdaEnvironment();
exports.handler = function(event, context, callback) {
var xvfb = new Xvfb({
xvfb_executable: '/tmp/pck/dist/Xvfb',
dry_run: !isOnLambda
});
xvfb.start((err, xvfbProcess) => {
if (err) callback(err);
function done(err, result){
xvfb.stop((err) => callback(err, result));
}
// ...
// Main logic with call to done() upon completion or error
// ...
var nightmare = Nightmare({
show: false, // show actual browser window as Nightmare clicks through
electronPath: electronPath // you MUST specify electron path which you receive from installation
});
test.scrap(nightmare, done);
});
};
Test module:
// test.js
function Test() { }
Test.prototype.scrap = function (nightmare, done) {
nightmare
.goto('https://duckduckgo.com')
.type('#search_form_input_homepage', 'github nightmare')
.click('#search_button_homepage')
.wait('#r1-0 a.result__a')
.evaluate(function () {
return document.querySelector('#r1-0 a.result__a').href;
})
.end()
.then(function (result) {
console.log(result);
done(null, result);
})
.catch(function (error) {
console.error('Search failed:', error);
done(error);
});
}
modules.export = new Test();
I have tried running your code locally (not on lambda). And there's typo:
modules.export = new Test();
// ^ no need for 's' here
module.exports = new Test();
// ^ must have 's' at the end of exports
I would recommend always testing functions locally before pushing them to lambda. Getting logs and reasonable error messages from there is much harder than on local machine.
You can use the script below to run lambda locally
//
// index-runner.js
//
const
handler = require('./index').handler;
;
handler({}, { done }, done);
function done(err, result){
if ( err ) console.error(err);
else console.log(`Result: `, result);
process.exit(1);
}
Finally I repaired the error. The lambda wasn't working because I was using Download package. If I was doing var download = require('download') it was not working, when I removed the require it worked. So I decided to change the download package for miniget.
Thanks for your help :)
Hi,
When I am using your packages to make work nightmare on aws lambda, I get this error :
This error is provoked when we require electron for nightmare :
let nightmare = Nightmare({ show: false, electronPath: require(electronPath) });