我下载了 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/