如果它挂在page.open上,如何退出幻像(带示例)

时间:2016-09-07 13:31:46

标签: javascript phantomjs

 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 from output
      page.onError = function(msg, trace) {};

      // 5 seconds
      page.settings.resourceTimeout = 5000;

      // page.settings.javascriptEnabled = false;

      page.open(myurl, function(status) {

          //hack for page.open not hooking into phantom.onError
          setTimeout(function() {
              if (status !== "success") {
                  console.log(myurl);
                  phantom.exit();
                  throw new Error("Unable to 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);
      });

使用上面的代码截取屏幕截图适用于大多数网页。 但是,通过控制台或带有网址“https://waffles.ch/”的网络应用程序运行脚本会导致它在page.open上无限挂起(我相信)。

我假设的原因是因为这个URL包含一些不停止运行的JS动画(一架飞机飞过屏幕),它导致Phantom锁定。这是一个已知的错误吗?

我非常确定JS会导致挂起,因为如果我使用page.settings.javascriptEnabled = false;将其关闭,那么页面的屏幕截图会毫无问题地呈现。

由于显而易见的原因(page.evaluate,重定向等),我无法实际关闭javascript来截取屏幕截图,所以这是我的2个问题。

1。)有没有办法为包含waffles.ch等动画的网页呈现屏幕截图,而无需关闭javascript?

2。)如果一个网页挂起,在page.open如何退出幻像并可能还会返回错误?)

非常感谢任何帮助/建议。

幻影版:2.1.1 操作系统:Windows 7 64位。

我尝试过的其他事情。(但仍然挂在上面的网址)

使用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 to access network");
            phantom.exit();
        } else {
            //do some stuff with the 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();
        for (var p in ex) {
            fullMessage += "\n" + p.toUpperCase() + ": " + ex[p];
        }
        console.log(fullMessage);
    }
});


// ******************************

使用waitfor()功能。 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 from 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 for page load success
    if (status !== "success") {
        console.log("Unable to access network");
        phantom.exit();
    } else {
        waitFor(function() {
            // Check in the page if a specific element is now visible
            return page.evaluate(function() {

                return $("body").is(":visible");
            });
        }, function() {
           console.log("body is visible");
           phantom.exit();
        });
    }
});

1 个答案:

答案 0 :(得分:1)

事实证明在这种情况下无法终止幻影,至少不是自己,但有一种方法可以避免这个问题。

根本原因是phantomJs中requestAnimationFrame的实现对tweenJs不起作用。通过幻像返回回调的数字是一个UNIX纪元号(但是小数秒),而tweenJs需要一个DOMHighResTimeStamp(就像你从performance.now()得到的那样,从进程开始时的零开始)。纪元号始终远高于补间结束时间,因此每次更新都被视为补间的结束,这会导致TWEEN.update进入下一个循环,从而导致其阻塞。

修复它的方法是使用performance.now注入polyfill,包括requestAnimationFrame pollyfil,以覆盖幻像的page.injectJs实施。

以下是需要注入的代码(或更好)...

请求动画frame.js

// Include a performance.now polyfill
var now = (function () {
    // In node.js, use process.hrtime.
    if (this.window === undefined && this.process !== undefined) {
      now = function () {
        var time = process.hrtime();

        // Convert [seconds, microseconds] to milliseconds.
        return time[0] * 1000 + time[1] / 1000;
      };
    }
    // In a browser, use window.performance.now if it is available.
    else if (this.window !== undefined &&
      window.performance !== undefined &&
      window.performance.now !== undefined) {

      // This must be bound, because directly assigning this function
      // leads to an invocation exception in Chrome.
      now = window.performance.now.bind(window.performance);
    }
    // Use Date.now if it is available.
    else if (Date.now !== undefined) {
      now = Date.now;
    }
    // Otherwise, use 'new Date().getTime()'.
    else {
      now = function () {
        return new Date().getTime();
      };
    }
    return now
  })();

// http://paulirish.com/2011/requestanimationframe-for-smart-animating/
// http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating

// requestAnimationFrame polyfill by Erik Möller. fixes from Paul Irish and Tino Zijdel

// MIT license

// Adapted to shim floating point milliseconds since the page was 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

}());

这里是放入幻像外部上下文以注入它的代码......

page.onInitialized = function() {
  page.injectJs('request-animation-frame.js');
};

在你的问题的背景下......

/**
 * Adjusted by 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 from 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 for page.open not hooking into phantom.onError
  setTimeout(function() {
    if (status !== "success") {
      exitPhantom('Error: ' + status);
      throw new Error("Unable to 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);

});

在这种情况下,resourceTimeout功能将按照宣传的方式工作,并防止过长的加载时间,任何使用类似动画技术的页面都可以正常工作。