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

标签 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);
      });
    }
  });

但在 page.evaluate 完成后,此逻辑永远不会设置 completePopulatedContent。 IE,completePopulatedContent 始终为 null

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

当目标 URL 包含通过 Ajax/javascript 或框架动态填充的内容时,有什么线索可以让此类查询发挥作用吗?如果涉及到框架,您能否解释一下 PhantomJS 如何浏览框架内容,因为在线文档和示例在该主题上不清楚。

最佳答案

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() 更改回来。

关于javascript - 使用 PhantomJS 检索完全填充的动态内容,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32531881/

相关文章:

javascript - 无法从列表项内提交的表单中获取表单值

html - 代码中的 trs 导致运行时错误

php - PHP 中的 PhantomJS 调用 - 性能

ruby - 使用 Ruby 在 Selenium Webdriver 中为 PhantomJS 设置自定义用户代理

javascript - 用于减少要编写的 javascript 行数的技术

javascript - SocketIO 发送带有参数的事件?

Javascript 检查日期是否在过去 24 小时内

python - python 网络抓取期间索引超出范围错误(漂亮的汤)

python - 导入错误 : cannot import name ScrapyFileLogObserver

symfony - 如何使用 phantomjs + behat + mink 处理确认弹出窗口