打开网页并截图。
仅使用 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 替换为:“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 真的 super 慢吗?我对此表示怀疑,但无论如何还是让我们测试一下..
var page = require('webpage').create();
page.open('http://github.com', function (status) {
/* irrelevant */
window.setTimeout(function () {
page.render('github.png');
phantom.exit();
}, 3000);
});
结果仍然是bupkis。所以不,这不是时间问题。
- 像 github 这样的网站如何阻止 phantomjs?
- 我们如何可靠地截取所有网页的屏幕截图?要求速度快,而且 headless 。
最佳答案
经过一段时间的反复思考,我能够缩小问题的范围。显然 PhantomJS 使用默认的 ssl sslv3
这会导致 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: '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,因此我看不到使用它来完成此特定任务的值(value)。
如果您想补充我的答案,请分享您的发现。对完美的 PhantomJS 解决方案非常感兴趣
更新 #1:删除 TypeError
@ArtjomB 指出 Phantomjs 在本次更新 (1.9.7) 的当前版本中不支持 js bind
。为此,他解释道:ArtjomB: PhantomJs Bind Issue Answer
The TypeError: 'undefined' is not a function refers to bind, because PhantomJS 1.x doesn't support it. PhantomJS 1.x uses an old fork of QtWebkit which is comparable to Chrome 13 or Safari 5. The newer PhantomJS 2 will use a newer engine which will support bind. For now you need to add a shim inside of the page.onInitialized event handler:
好的,很好,所以下面的代码将处理上面的 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
,因此从表面上看,一切似乎都有效。已经取得了进展。
不幸的是,所有图像图标[ Logo 等]仍然无法正确加载。我们看到某种 3W 图标,不确定它来自哪里。
感谢@ArtjomB的帮助
关于javascript - 获取可靠的网站屏幕截图? Phantomjs 和 Casperjs 在某些网站上都返回空屏幕截图,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26517852/