我需要做一些网页抓取。在玩了不同的网络测试框架之后,其中大多数地方要么太慢(Selenium)或太多我的需求(env.js),我认为zombie.js看起来最有希望,因为它使用了一组固体用于HTML解析和DOM操作的库。但是,在我看来它甚至不支持基本的基于事件的Javascript代码,如下面的网页:
<html>
<head>
<title>test</title>
<script type="text/javascript">
console.log("test script executing...");
console.log("registering callback for event DOMContentLoaded on " + document);
document.addEventListener('DOMContentLoaded', function(){
console.log("DOMContentLoaded triggered");
}, false);
function loaded() {
console.log("onload triggered");
}
</script>
</head>
<body onload="loaded();">
<h1>Test</h1>
</body>
</html>
然后我决定像这样手动触发这些事件:
zombie = require("zombie");
zombie.visit("http://localhost:4567/", { debug: true }, function (err, browser, status) {
doc = browser.document;
console.log("firing DOMContentLoaded on " + doc);
browser.fire("DOMContentLoaded", doc, function (err, browser, status) {
body = browser.querySelector("body");
console.log("firing load on " + body);
browser.fire("load", body, function (err, browser, status) {
console.log(browser.html());
});
});
});
适用于此特定测试页面。我的问题是一个更普遍的问题:我希望能够抓住更复杂,基于AJAX的网站,比如Facebook上的朋友列表(类似http://www.facebook.com/profile.php?id=100000028174850&sk=friends&v=friends)。使用zombie登录网站没有问题,但是像这些列表这样的内容似乎是使用AJAX动态完全加载的,我不知道如何触发启动加载的事件处理程序。
我对这个问题有几个问题:
同样,请不要指出涉及控制像Selenium这样的真实浏览器的解决方案,正如我所知道的那样。然而,对于可以从Ruby脚本语言访问的真实内存渲染器(如WebKit)的建议是值得欢迎的,但最好能够设置cookie,并且最好还加载原始HTML而不是触发真正的HTTP请求。
答案 0 :(得分:13)
出于数据提取的目的,运行“无头浏览器”并手动触发javascript事件并不是最容易的事情。虽然并非不可能,但有更简单的方法可以做到。
大多数网站,甚至是AJAX重的网站,都可以在不执行单行Javascript代码的情况下进行抓取。实际上通常比试图找出网站的Javascript代码更容易,这通常是模糊的,缩小的,并且难以调试。如果您对HTTP有充分的了解,您将理解为什么:(几乎)与服务器的所有交互都被编码为HTTP请求,因此无论它们是由Javascript启动,还是用户单击链接,或者是机器人程序中的自定义代码,这与服务器没有区别。 (我说几乎是因为当Flash或小程序介入时,无法确定哪些数据在哪里飞行;它们可能是特定于应用程序的。但是在Javascript中完成的任何操作都将通过HTTP进行。)
话虽如此,可以使用自定义软件模仿任何网站上的用户。首先,您必须能够看到发送到服务器的原始HTTP请求。您可以使用代理服务器将真实浏览器发出的请求记录到目标网站。您可以使用许多工具:Charles或Fiddler非常方便,最专注的screen-scraper tools内置基本代理,Firefox的Firebug扩展名和Chrome有类似的工具来查看AJAX请求......你明白了。
一旦您可以看到由于网站上的特定操作而产生的HTTP请求,就可以轻松编写程序来模仿这些请求;只需将相同的请求发送到服务器,它就会像执行特定操作的浏览器一样处理您的程序。
对于提供不同功能的不同语言,存在不同的库。对于ruby,我见过很多人使用mechanize for ruby。
如果数据提取是您唯一的目标,那么您几乎总能通过这种方式模仿HTTP请求来获得所需内容。不需要Javascript。
注意 - 自从你提到Facebook之后,我应该提一下,特别难以抓取Facebook(虽然并非不可能),因为Facebook已采取措施来检测自动访问(他们使用的不仅仅是验证码);如果他们看到来自该帐户的可疑活动,他们将停用该帐户。毕竟,它是针对他们的terms of service(第3.2节)。