使用zombie.js进行网站抓取的问题

时间:2011-09-07 15:50:47

标签: javascript facebook node.js screen-scraping zombie.js

我需要做一些网页抓取。在玩了不同的网络测试框架之后,其中大多数地方要么太慢(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这样的浏览器远程控制解决方案的情况下已经实现了类似的复杂刮刀吗?
  • 是否对基于Javascript的复杂页面的加载过程有一些参考?
  • 有人可以提供有关如何调试真实浏览器的建议,以了解我可能需要执行哪些操作来触发Facebook事件处理程序吗?
  • 关于此主题的任何其他想法?

同样,请不要指出涉及控制像Selenium这样的真实浏览器的解决方案,正如我所知道的那样。然而,对于可以从Ruby脚本语言访问的真实内存渲染器(如WebKit)的建议是值得欢迎的,但最好能够设置cookie,并且最好还加载原始HTML而不是触发真正的HTTP请求。

1 个答案:

答案 0 :(得分:13)

出于数据提取的目的,运行“无头浏览器”并手动触发javascript事件并不是最容易的事情。虽然并非不可能,但有更简单的方法可以做到。

大多数网站,甚至是AJAX重的网站,都可以在不执行单行Javascript代码的情况下进行抓取。实际上通常比试图找出网站的Javascript代码更容易,这通常是模糊的,缩小的,并且难以调试。如果您对HTTP有充分的了解,您将理解为什么:(几乎)与服务器的所有交互都被编码为HTTP请求,因此无论它们是由Javascript启动,还是用户单击链接,或者是机器人程序中的自定义代码,这与服务器没有区别。 (我说几乎是因为当Flash或小程序介入时,无法确定哪些数据在哪里飞行;它们可能是特定于应用程序的。但是在Javascript中完成的任何操作都将通过HTTP进行。)

话虽如此,可以使用自定义软件模仿任何网站上的用户。首先,您必须能够看到发送到服务器的原始HTTP请求。您可以使用代理服务器将真实浏览器发出的请求记录到目标网站。您可以使用许多工具:CharlesFiddler非常方便,最专注的screen-scraper tools内置基本代理,Firefox的Firebug扩展名和Chrome有类似的工具来查看AJAX请求......你明白了。

一旦您可以看到由于网站上的特定操作而产生的HTTP请求,就可以轻松编写程序来模仿这些请求;只需将相同的请求发送到服务器,它就会像执行特定操作的浏览器一样处理您的程序。

对于提供不同功能的不同语言,存在不同的库。对于ruby,我见过很多人使用mechanize for ruby

如果数据提取是您唯一的目标,那么您几乎总能通过这种方式模仿HTTP请求来获得所需内容。不需要Javascript。

注意 - 自从你提到Facebook之后,我应该提一下,特别难以抓取Facebook(虽然并非不可能),因为Facebook已采取措施来检测自动访问(他们使用的不仅仅是验证码);如果他们看到来自该帐户的可疑活动,他们将停用该帐户。毕竟,它是针对他们的terms of service(第3.2节)。