javascript - How to exit phantom if it hangs on page.open (with example) -
var system = require("system"); var page; // user supplied url var myurl = system.args[1]; // var myurl = 'https://waffles.ch/'; page = require('webpage').create(); // suppress errors output page.onerror = function(msg, trace) {}; // 5 seconds page.settings.resourcetimeout = 5000; // page.settings.javascriptenabled = false; page.open(myurl, function(status) { //hack page.open not hooking phantom.onerror settimeout(function() { if (status !== "success") { console.log(myurl); phantom.exit(); throw new error("unable access network"); } else { var pagetitle = myurl.replace(/http.*\/\//g, "").replace("www.", "").split("/")[0]; var filepath = "img/" + pagetitle + '.jpg'; page.render(filepath, {format: 'jpeg', quality: '75'}); console.log(filepath); phantom.exit(); } }, 0); });
using above code take screenshots works fine webpages. running script through console or web app url "https://waffles.ch/", however, causes hang infinitely on page.open (i believe).
the reason assume because url contains js animation doesn't stop running (an aeroplane flying across screen), , causes phantom lock up. known bug??
i'm quite sure js causes hang because if switch off page.settings.javascriptenabled = false;
screenshot page rendered without problems.
i can't realistically switch off javascript take screenshots obvious reasons (page.evaluate, redirects etc), here's 2 questions.
1.) there way render screenshot webpage containing animation waffles.ch
without having switch off javascript??
2.) if webpage hang, on page.open
how can exit phantom , possibly return errror??)
any help/advice appreciated.
phantom version: 2.1.1 os: windows 7 64 bit.
other thing i've tried.(but still hangs above url)
with try/catch
var system = require("system"); var page; // user supplied url var myurl = system.args[1]; var page = require('webpage').create(); page.open(myurl, function (status) { try { if (status !== "success") { console.log("unable access network"); phantom.exit(); } else { //do stuff dom var pagetitle = myurl.replace(/http.*\/\//g, "").replace("www.", "").split("/")[0]; var filepath = "img/" + pagetitle + '.jpg'; page.render(filepath, {format: 'jpeg', quality: '75'}); console.log(filepath); phantom.exit(); } } catch (ex) { var fullmessage = "\njavascript exception"; fullmessage += "\nmessage: " + ex.tostring(); (var p in ex) { fullmessage += "\n" + p.touppercase() + ": " + ex[p]; } console.log(fullmessage); } }); // ******************************
using waitfor()
function. https://github.com/ariya/phantomjs/blob/master/examples/waitfor.js
var system = require("system"); var page; // user supplied url var myurl = system.args[1]; var page = require('webpage').create(); // suppress errors output page.onerror = function(msg, trace) { console.log("error occurred" + msg); phantom.exit(); }; // 5 seconds page.settings.resourcetimeout = 5000; page.open(myurl, function (status) { // check page load success if (status !== "success") { console.log("unable access network"); phantom.exit(); } else { waitfor(function() { // check in page if specific element visible return page.evaluate(function() { return $("body").is(":visible"); }); }, function() { console.log("body visible"); phantom.exit(); }); } });
turns out there no way terminate phantom in situation, @ least not but, there way avoid problem.
the root cause implementation of requestanimationframe
in phantomjs doesn't play nice tweenjs. number returned callback phantom unix epoch number (but fractional seconds) , tweenjs expects domhighrestimestamp (like performance.now(), starting 0 when process starts). epoch number higher tween end time, every update seen end of tween , causes tween.update
slam through next cycle, causing block.
the way fix inject polyfill, including performance.now
pollyfil, overwrite phantom's requestanimationframe
implimentation, using page.injectjs
.
here code needs injected (or st better)...
request-animation-frame.js
// include performance.now polyfill var = (function () { // in node.js, use process.hrtime. if (this.window === undefined && this.process !== undefined) { = function () { var time = process.hrtime(); // convert [seconds, microseconds] milliseconds. return time[0] * 1000 + time[1] / 1000; }; } // in browser, use window.performance.now if available. else if (this.window !== undefined && window.performance !== undefined && window.performance.now !== undefined) { // must bound, because directly assigning function // leads invocation exception in chrome. = window.performance.now.bind(window.performance); } // use date.now if available. else if (date.now !== undefined) { = date.now; } // otherwise, use 'new date().gettime()'. else { = function () { return new date().gettime(); }; } return })(); // http://paulirish.com/2011/requestanimationframe-for-smart-animating/ // http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating // requestanimationframe polyfill erik möller. fixes paul irish , tino zijdel // mit license // adapted shim floating point milliseconds since page opened // https://developers.google.com/web/updates/2012/05/requestanimationframe-api-now-with-sub-millisecond-precision?hl=en (function() { var lasttime = 0; var raf = window.requestanimationframe; window.requestanimationframe = function(callback) { var currtime = now(); var timetocall = math.max(0, 1000/60 - (currtime - lasttime)); var tcb = currtime + timetocall; var cbprxy = (function (cb, t) { return function (discard) { cb(t) } })(callback, tcb); var id = raf ? raf.call(window, cbprxy) : window.settimeout(function() { callback(tcb); }, timetocall); lasttime = currtime + timetocall; return id; }; if(!window.cancelanimationframe) window.cancelanimationframe = cleartimeout }());
and here code put in phantoms outer context inject it...
page.oninitialized = function() { page.injectjs('request-animation-frame.js'); };
in context of question...
/** * adjusted cool.blue on 08-sep-16. */ var system = require('system'); var page; // user supplied url var myurl = system.args[1] || 'https://waffles.ch/'; page = require('webpage').create(); // suppress errors output page.onerror = function(msg, trace) {}; function exitphantom (message) { console.log(message) phantom.exit(message.match("error:") ? 1 : 0) } page.onconsolemessage = function(message) { system.stdout.write('> ' + message + '\n') }; page.oninitialized = function() { page.injectjs('request-animation-frame.js'); }; // 5 seconds page.settings.resourcetimeout = 10000; // page.settings.javascriptenabled = false; page.open(myurl, function(status) { //hack page.open not hooking phantom.onerror settimeout(function() { if (status !== "success") { exitphantom('error: ' + status); throw new error("unable access network"); } else { var pagetitle = myurl.replace(/http.*\/\//g, "").replace("www.", "").split("/")[0]; var filepath = "img/" + pagetitle + '.jpg'; page.render(filepath, {format: 'jpeg', quality: '75'}); console.log(filepath); exitphantom(status); } }, 1000); });
in case, resourcetimeout
feature work advertised , protect against over-long load times , page uses similar animation techniques work fine.
Comments
Post a Comment