使用PhantomJS检索完全填充的动态内容

时间:2015-09-11 20:46:17

标签: javascript web-scraping phantomjs

我下载了pjscrape(在幕后运行PhantomJS),实际上,页面查询返回了完全填充的内容,包括动态内容。不幸的是,pjscrape只发出JSON或CSV。我需要HTML。

单独使用PhantomJS,我有这个脚本(调用my-query.js):

var page = require('webpage').create();
page.open('http://www.sonoma.edu/calendar/groups/clubs.html', function (status) {
    console.log("status: " + status);
    if (status !== "success") {
      console.log("Unable to access network");
    } else {
      page.includeJs("http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js", function() {
          console.log("Got jQuery...");
          var fullyPopulatedContent = null;
          page.evaluate(function() {
              $(document).ready(function() {
                  fullyPopulatedContent = $("html").html();
                });
          });
          window.setTimeout(function() {
              console.log(fullyPopulatedContent);
            }, 10000);
      });
    }
  });

但是这个逻辑在fullyPopulatedContent完成后从未设置page.evaluate。 IE,fullyPopulatedContent只是null

这看起来像是一个微不足道的应用程序,你会认为PhantomJS可以免费开箱即用。

当目标网址包含通过Ajax / javascript或框架动态填充的内容时,如何使这些查询有效?如果涉及到框架,您还可以解释PhantomJS如何浏览框架内容,因为在线文档和示例不清楚该主题。

1 个答案:

答案 0 :(得分:1)

PhantomJS有两个上下文。 page.evaluate()是唯一提供对DOM /页面上下文的访问的函数。该函数是沙箱化的,这就是为什么你需要明确地传入和传出数据的原因。

另一个问题是,在$(...).ready()内拨打$.ready()之前很久就会触发page.evaluate()侦听的事件。如果这是您想加载jQuery的唯一原因,那么您就不应该这样做。

您只需等待一段时间:

var page = require('webpage').create();
page.open('http://www.sonoma.edu/calendar/groups/clubs.html', function (status) {
    console.log("status: " + status);
    if (status !== "success") {
      console.log("Unable to access network");
    } else {
        window.setTimeout(function() {
            console.log(page.content);
            phantom.exit();
        }, 10000); // adjust time for every page
    }
});

问题当然是,您无法轻易确定页面是否已满载。通常好的方法是waitFor(来自示例的函数)出现最终元素之类的特定条件,或者页面中至少存在x个相同类型的元素。这通常使用document.querySelector()page.evaluate()的CSS选择器来完成。

另一种方法是计算所请求的资源和已完成的资源,以查看在短时间内没有任何待处理请求,并希望适当选择资源请求之间的时间。

<强>帧:

PhantomJS会自动提取(i)帧作为页面加载的一部分。但是,它们可能比主/父帧更晚完成加载。这就是为什么你可能需要额外的等待期。

当您使用page.render()截取屏幕截图时,您将看到完整的页面,包括已加载(或当前正在加载)的框架。

由于框架是具有自己的文档根目录的单独文档,因此当您尝试使用page.content打印主/父页面的页面源时,PhantomJS不会包含它们。您首先需要更改其上下文以打印其DOM表示。

您可以按名称(如果框架具有名称)或索引(取决于当前(父)框架中的框架数量)执行此操作。请使用page.switchToFrame()。然后,您可以使用page.frameContent检索框架内容。由于您切换到帧上下文,现在您可以执行以前在主框架中执行的所有交互,例如自由更改DOM或单击内容。完成框架后,您可以使用page.switchToParentFrame()更改回来。