【问题标题】:Taking reliable screenshots of websites? Phantomjs and Casperjs both return empty screen shots on some websites拍摄可靠的网站截图? Phantomjs 和 Casperjs 在某些网站上都返回空屏幕截图
【发布时间】:2014-12-18 12:24:13
【问题描述】:

打开一个网页并截图。

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

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

问题是,对于某些网站(如 github)来说,有趣的是,它们以某种方式检测到而不是提供 phantomjs,并且没有呈现任何内容。结果是github.png是一个空白的白色png文件。

将 github 替换为 say:“google.com”,你会得到一个不错的(正确的)屏幕截图。

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

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

casper.run();

但我得到与 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();
});

然后我尝试解析页面,显然某些网站(再次像 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();  

与上述相同,在纯 phantomjs 中也会产生相同的结果。

更新:

这可能是时间问题吗? github只是超级慢吗?我对此表示怀疑,但无论如何让我们测试一下..

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

结果还是布基斯。所以不,这不是时间问题。

  1. github 之类的网站如何阻止 phantomjs?
  2. 我们如何才能可靠地截取所有网页的屏幕截图?要求速度快且无头。

【问题讨论】:

  • 最可靠的可能是无头 Firefox 解决方案(watir/webdriver?)
  • @pguardiario,谢谢我看到你的帖子。 Watir 网络驱动程序过去对我来说效果很好,但通常速度较慢。我已经将它用于测试和小型抓取工作......它们是在 Heroku 上部署 watir 或在生产应用程序上部署 ec2 的简单方法吗?
  • 所以,我用--ssl-protocol=tlsv1 尝试了this,它产生了this image。现在我看不出图片有什么问题。您还有其他问题吗?
  • github上的图片是webfonts。他们过去有问题。你在linux上吗?您使用当前稳定的 PhantomJS 版本(1.9.7)吗?您可能想要编译 PhantomJS 2 或尝试 SlimerJS。

标签: javascript phantomjs screen-scraping casperjs


【解决方案1】:

在反复讨论了一段时间后,我能够缩小问题的范围。显然 PhantomJS 使用sslv3 的默认 ssl,这会导致 github 由于错误的 ssl 握手而拒绝连接

phantomjs --debug=true github.js

显示输出:

. . .
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 

因此,我们可以得出结论,因为 github 拒绝连接,所以没有截屏。太好了,这很有意义。因此,让我们将 SSL 标志设置为 --ssl-protocol=any 并使用 --ignore-ssl-errors=true 忽略 ssl 错误

phantomjs --ignore-ssl-errors=true --ssl-protocol=any --debug=true github.js

大获成功!现在正在正确渲染和保存屏幕截图,但调试器向我们显示 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

我手动检查了 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);
});

那没有用...在仔细检查图像后 - 很明显有些元素丢失了。主要是一些图标和标志。

成功了吗? 部分是因为我们现在至少得到了一个屏幕截图,而之前我们什么也没得到。

工作完成了吗? 不完全是。需要确定导致该 TypeError 的原因,因为它阻止了某些资产加载和扭曲图像。

附加

尝试使用 CasperJS 重新创建 --debug 与 PhantomJS 相比非常丑陋且难以遵循:

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();

控制台:

casperjs test --ssl-protocol=any --debug=true github.js

此外,图像缺少相同的图标,但在视觉上也变形了。由于 CasperJs 依赖于 Phantomjs,因此我看不出将它用于此特定任务的价值。

如果您想补充我的答案,请分享您的发现。对完美的 PhantomJS 解决方案非常感兴趣

更新 #1:删除 TypeError

@ArtjomB 指出 Phantomjs 在本次更新 (1.9.7) 的当前版本中不支持 js bind。出于这个原因,他解释说:ArtjomB: PhantomJs Bind Issue Answer

TypeError: 'undefined' is not a function 指的是绑定,因为 PhantomJS 1.x 不支持它。 PhantomJS 1.x 使用旧的 fork 与 Chrome 13 或 Safari 5 相当的 QtWebkit。较新的 PhantomJS 2 将使用支持绑定的更新引擎。目前 您需要在 page.onInitialized 事件处理程序中添加一个 shim:

好的,所以下面的代码将从上面处理我们的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;
        }
    });
}

现在上面的代码将为我们提供与之前相同的屏幕截图,并且调试不会显示TypeError,因此从表面上看,一切似乎都正常。已经取得了进展。

很遗憾,所有图像图标 [徽标等] 仍未正确加载。我们看到某种 3W 图标,不知道是从哪里来的。

感谢@ArtjomB 的帮助

【讨论】:

  • 您也遇到了绑定问题。以下是CasperPhantomJS 的解决方案。
  • 嘿,谢谢,我怀疑绑定问题与 https 相关。使用 SetTimeout 测试到 10 秒,结果相同...
  • page.onInitialized 内部的代码添加了bind shim,这样您就不会在页面上收到 TypeError 并且页面 JS 可以正常运行(如果您还需要在页面上做一些事情)。
  • 那些标志是图标字体,看起来它们有问题。参考github.com/ariya/phantomjs/issues/10592
  • 感谢您提供如此出色的答案,对于大多数网站,我正在获取屏幕截图,但对于某些网站,例如 .... practo.comiitr.ac.in 我仍然得到白色屏幕截图或 403错误.....你能帮忙吗?
猜你喜欢
  • 2021-08-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-14
  • 2011-05-27
相关资源
最近更新 更多