获取可靠的网站截图?Phantomjs和Casperjs都在一些网站上返回空屏幕截图

fab*_*bbb 24 javascript screen-scraping phantomjs casperjs

打开网页并截取屏幕截图.

只使用phantomjs:(这是一个简单的脚本,实际上它是在他们的文档中使用的示例脚本.http://phantomjs.org/screen-capture.html

var page = require('webpage').create();
page.open('http://github.com/', function() {
  page.render('github.png');
  phantom.exit();
});
Run Code Online (Sandbox Code Playgroud)

问题是,对于一些网站(如github),足够有趣的是以某种方式检测并且不提供phantomjs并且没有任何东西被渲染.结果是github.png一个空白的白色png文件.

用说:"google.com"替换github,你会得到一个很好的(正确的)截图.

起初我认为这是一个Phantomjs问题所以我尝试通过Casperjs运行它:

casper.start('http://www.github.com/', function() {
    this.captureSelector('github.png', 'body');
});

casper.run();
Run Code Online (Sandbox Code Playgroud)

但我得到与Phantomjs相同的行为.

所以我认为这很可能是用户代理问题.如:Github嗅出Phantomjs并决定不显示页面.所以我设置用户代理如下,但仍然无法正常工作.

var page = require('webpage').create();
page.settings.userAgent = 'Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2049.0 Safari/537.36';
page.open('http://github.com/', function() {
  page.render('github.png');
  phantom.exit();
});
Run Code Online (Sandbox Code Playgroud)

所以我试图解析页面,显然有些网站(再次像github)似乎没有发送任何网络.

使用casperjs我试图打印标题.对于google.com我回来了Google但是对于github.com我回来了bupkis.示例代码:

var casper = require('casper').create();

casper.start('http://github.com/', function() {
    this.echo(this.getTitle());
});

casper.run();  
Run Code Online (Sandbox Code Playgroud)

与上述相同也在纯粹的幻影中产生相同的结果.

更新:

这可能是一个时间问题吗?github只是超级慢吗?我怀疑它,但无论如何都要测试..

var page = require('webpage').create();
page.open('http://github.com', function (status) {
    /* irrelevant */
   window.setTimeout(function () {
            page.render('github.png');
            phantom.exit();
        }, 3000);
});
Run Code Online (Sandbox Code Playgroud)

结果仍然是bupkis.所以不,这不是时间问题.

  1. 一些网站如何像github阻止phantomjs?
  2. 我们如何可靠地截取所有网页的屏幕截图?要求快速,无头.

fab*_*bbb 26

经过一段时间的反复,我能够缩小问题的范围.显然,PhantomJS使用默认的ssl sslv3,导致github由于ssl握手错误而拒绝连接

phantomjs --debug=true github.js
Run Code Online (Sandbox Code Playgroud)

显示输出:

. . .
2014-10-22T19:48:31 [DEBUG] WebPage - updateLoadingProgress: 10 
2014-10-22T19:48:32 [DEBUG] Network - Resource request error: 6 ( "SSL handshake failed" ) URL: "https://github.com/" 
2014-10-22T19:48:32 [DEBUG] WebPage - updateLoadingProgress: 100 
Run Code Online (Sandbox Code Playgroud)

因此,我们可以得出结论,没有采用屏幕,因为github拒绝连接.伟大的,完美的感觉.所以让我们设置SSL标志,--ssl-protocol=any并让我们也忽略ssl-errors--ignore-ssl-errors=true

phantomjs --ignore-ssl-errors=true --ssl-protocol=any --debug=true github.js
Run Code Online (Sandbox Code Playgroud)

巨大的成功!屏幕截图现在正在呈现并正确保存,但调试器向我们显示了TypeError:

TypeError: 'undefined' is not a function (evaluating 'Array.prototype.forEach.call.bind(Array.prototype.forEach)')

  https://assets-cdn.github.com/assets/frameworks-dabc650f8a51dffd1d4376a3522cbda5536e4807e01d2a86ff7e60d8d6ee3029.js:29
  https://assets-cdn.github.com/assets/frameworks-dabc650f8a51dffd1d4376a3522cbda5536e4807e01d2a86ff7e60d8d6ee3029.js:29
2014-10-22T19:52:32 [DEBUG] WebPage - updateLoadingProgress: 72 
2014-10-22T19:52:32 [DEBUG] WebPage - updateLoadingProgress: 88 
ReferenceError: Can't find variable: $

  https://assets-cdn.github.com/assets/github-fa2f009761e3bc4750ed00845b9717b09646361cbbc3fa473ad64de9ca6ccf5b.js:1
  https://assets-cdn.github.com/assets/github-fa2f009761e3bc4750ed00845b9717b09646361cbbc3fa473ad64de9ca6ccf5b.js:1
Run Code Online (Sandbox Code Playgroud)

我手动检查了github主页,看看是否存在TypeError,而不是.

我的下一个猜测是资产加载速度不够快.Phantomjs比速度更快的子弹更快!

所以让我们尝试人为地减慢它,看看我们是否可以摆脱那种TypeError ......

var page = require('webpage').create();
page.settings.userAgent = 'Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2049.0 Safari/537.36';
page.open('http://github.com', function (status) {
   window.setTimeout(function () {
            page.render('github.png');
            phantom.exit();
        }, 3000);
});
Run Code Online (Sandbox Code Playgroud)

这不起作用......仔细检查图像后 - 很明显有些元素缺失了.主要是一些图标和徽标.

成功? 部分是因为我们现在至少在早些时候获得了一个屏幕截图,我们没有得到任何东西.

任务完成? 不完全是.需要确定是什么导致了TypeError,因为它阻止某些资产加载和扭曲图像.

额外

试图用CasperJS重新创建 - 与PhantomJS相比,debug非常难看并且难以理解:

casper.start();
casper.userAgent('Mozilla/5.0 (Macintosh; Intel Mac OS X)');
casper.thenOpen('https://www.github.com/', function() {
    this.captureSelector('github.png', 'body');
});

casper.run();
Run Code Online (Sandbox Code Playgroud)

安慰:

casperjs test --ssl-protocol=any --debug=true github.js
Run Code Online (Sandbox Code Playgroud)

此外,图像缺少相同的图标,但也在视觉上失真.由于CasperJs依赖于Phantomjs,我没有看到使用它来完成这项特定任务的价值.

如果您想添加我的答案,请分享您的发现.对完美无瑕的PhantomJS解决方案非常感兴趣

更新#1:删除 TypeError

@ArtjomB指出Phantomjs bind在此更新(1.9.7)中不支持其当前版本中的js .出于这个原因,他解释说:ArtjomB:PhantomJs绑定问题答案

TypeError:'undefined'不是函数引用bind,因为PhantomJS 1.x不支持它.PhantomJS 1.x使用QtWebkit的旧分支,可与Chrome 13或Safari 5相媲美.较新的PhantomJS 2将使用更新的引擎来支持bind.现在你需要在page.onInitialized事件处理程序中添加一个垫片:

好的,所以下面的代码TypeError将从上面照顾我们.(但功能不全,详见下文)

var page = require('webpage').create();
page.settings.userAgent = 'Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2049.0 Safari/537.36';
page.open('http://github.com', function (status) {
   window.setTimeout(function () {
            page.render('github.png');
            phantom.exit();
        }, 5000);
});
page.onInitialized = function(){
    page.evaluate(function(){
        var isFunction = function(o) {
          return typeof o == 'function';
        };

        var bind,
          slice = [].slice,
          proto = Function.prototype,
          featureMap;

        featureMap = {
          'function-bind': 'bind'
        };

        function has(feature) {
          var prop = featureMap[feature];
          return isFunction(proto[prop]);
        }

        // check for missing features
        if (!has('function-bind')) {
          // adapted from Mozilla Developer Network example at
          // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind
          bind = function bind(obj) {
            var args = slice.call(arguments, 1),
              self = this,
              nop = function() {
              },
              bound = function() {
                return self.apply(this instanceof nop ? this : (obj || {}), args.concat(slice.call(arguments)));
              };
            nop.prototype = this.prototype || {}; // Firefox cries sometimes if prototype is undefined
            bound.prototype = new nop();
            return bound;
          };
          proto.bind = bind;
        }
    });
}
Run Code Online (Sandbox Code Playgroud)

现在上面的代码将为我们提供一个与之前相同的屏幕截图,并且调试不会TypeError从表面显示,所有内容都可以正常工作.已经取得了进展.

不幸的是,所有图像图标[徽标等]仍未正确加载.我们看到某种3W图标不确定它们来自何处.

感谢@ArtjomB的帮助

在此输入图像描述

  • 谢谢你这么好的答案,对于网站的大部分内容我都是截图,但是对于一些网站来说......例如http://www.practo.com和http://www.iitr.ac.in我是仍然是白色截图或403错误.....你能帮忙吗? (2认同)