我下载了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如何浏览框架内容,因为在线文档和示例不清楚该主题。
答案 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()
更改回来。