我正在尝试使用PhantomJS进行页面自动化。我的目标是能够访问网站,单击图像,并在点击加载页面后继续使用其他代码。为了测试这一点,我试图编写一个脚本,该脚本将转到PhantomJS网站上快速入门指南的网址,然后点击PhantomJS徽标将该页面带到PhantomJS主页。还要在点击之前和之后呈现网站的图片以确保点击有效。这是我目前的代码:
var page = require('webpage').create();
page.open('http://phantomjs.org/quick-start.html', function(status) {
console.log(status);
page.render('websiteBeforeClick.png');
console.log(page.frameUrl); //check url before click
var element = page.evaluate(function() {
return document.querySelector('img[alt="PhantomJS"]');
});
page.sendEvent('click', element.offsetLeft, element.offsetTop, 'left');
window.setTimeout(function () {
console.log(page.frameUrl); //check url after click
}, 3000);
console.log('element is ' + element); //check that querySelector() is returning an element
page.render('websiteAfterClick.png');
phantom.exit();
});
问题是我之前和之后的图片是一样的。这是我运行时的输出。
success
element is [object Object]
我在这里使用他们的sendEvent方法" http://phantomjs.org/api/webpage/method/send-event.html"但我不确定它是否正常工作。
另外为什么我的window.setTimeout()中的console.log(page.frameUrl)没有被执行?
我在PhantomJS网站上查看了他们的页面自动化示例。特别是这一个" https://github.com/ariya/phantomjs/blob/master/examples/imagebin.js"。 我注意到他们使用的例子
document.querySelector('input[name=disclaimer_agree]').click()
但是当我用我的代码尝试它时,我收到了一个错误。
document.querySelector('img[alt="PhantomJS"]').click();
TypeError: 'undefined' is not a function
编辑#1:
我将代码的结尾部分更改为:
page.sendEvent('click', element.offsetLeft, element.offsetTop, 'left');
window.setTimeout(function () {
console.log(page.frameUrl);
page.render('websiteAfterClick.png');
phantom.exit();
}, 3000);
console.log('element is ' + element);
});
现在我的后图像是正确的。但现在我的问题是,如果我想继续我的代码,即点击网站上的另一个元素,我的新代码是否必须全部嵌套在超时函数内?
答案 0 :(得分:5)
我在following post上解释了一个示例函数phantom.waitFor(callback)
,其内容如下:
phantom.waitFor = function(callback) {
do {
// Clear the event queue while waiting.
// This can be accomplished using page.sendEvent()
this.page.sendEvent('mousemove');
} while (!callback());
}
这可以帮助简化代码并避免对window.setTimeout()的嵌套调用,因为等待预设的时间而不是等待元素变得可见,这些调用不是很可靠。一个例子如下:
// Step 1: Open and wait to finish loading
page.open('http://localhost/');
phantom.waitFor(function() {return !page.loading;});
// Step 2: Click on first panel and wait for it to show
page.evaluate(function() { $("#activate-panel1").click(); });
phantom.waitFor(function() {
return page.evaluate(function() {return $("#panel1").is(":visible");})
});
// Step 3: Click on second panel and wait for it to show
page.evaluate(function() { $("#activate-panel2").click(); });
phantom.waitFor(function() {
return page.evaluate(function() {return $("#panel2").is(":visible");})
});
console.log('READY!');
phantom.exit();
这将连续加载每个面板(即同步),同时保持代码简单并避免嵌套回调。
希望它有意义。你也可以使用CasperJS作为替代品,它的目的是使这个东西更简单。
答案 1 :(得分:0)
是的,您的新代码将从setTimeout
回调内部调用。您可以直接嵌套代码或编写一个为您填充代码的函数,并在setTimeout
内调用该函数。
function anotherClick(){
// something
}
page.sendEvent('click', element.offsetLeft, element.offsetTop, 'left');
window.setTimeout(function () {
console.log(page.frameUrl);
page.render('websiteAfterClick.png');
anotherClick();
phantom.exit();
}, 3000);
还有另一种方式。您也可以使用多个setTimeout
完全编写它,但之后您无法对之前调用中的突发情况作出反应。
page.sendEvent('click', element.offsetLeft, element.offsetTop, 'left');
window.setTimeout(function () {
console.log(page.frameUrl);
page.render('websiteAfterClick.png');
}, 3000);
window.setTimeout(function () {
// some more actions
}, 6000); // you cannot know if this delay is sufficient
window.setTimeout(function () {
phantom.exit();
}, 9000); // you cannot know if this delay is sufficient
如果您想要执行许多操作/导航步骤,我建议您使用CasperJS。