javascript PhantomJS 点击图片并等待加载
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/24684698/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
PhantomJS click on an image and wait for load
提问by user3803788
I'm trying to do page automation with PhantomJS. My goal is to be able to go to a website, click an image, and continue with other code once the page has loaded from the click. To test this I'm trying to write a script that will go to the url of the quick start guide on the PhantomJS website and then click on the PhantomJS logo bringing the page to the PhantomJS homepage. Also to render a picture of the website before and after the click to make sure the click worked. This is my current code:
我正在尝试使用 PhantomJS 进行页面自动化。我的目标是能够访问网站,单击图像,并在单击加载页面后继续执行其他代码。为了测试这一点,我正在尝试编写一个脚本,该脚本将转到 PhantomJS 网站上快速入门指南的 url,然后单击 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();
});
Problem is my before and after pictures are the same. This is my output when I run it.
问题是我之前和之后的照片是一样的。这是我运行时的输出。
success
element is [object Object]
Im using their sendEvent method from here "http://phantomjs.org/api/webpage/method/send-event.html" but I'm not sure if its working.
我从这里使用他们的 sendEvent 方法“ http://phantomjs.org/api/webpage/method/send-event.html”,但我不确定它是否有效。
Also why doesnt the console.log(page.frameUrl) in my window.setTimeout() get executed?
另外为什么我的 window.setTimeout() 中的 console.log(page.frameUrl) 没有被执行?
I was looking at their page automation examples on the PhantomJS website. Particularly this one "https://github.com/ariya/phantomjs/blob/master/examples/imagebin.js". I noticed their examples used
我正在 PhantomJS 网站上查看他们的页面自动化示例。特别是这个“ https://github.com/ariya/phantomjs/blob/master/examples/imagebin.js”。我注意到他们使用的例子
document.querySelector('input[name=disclaimer_agree]').click()
But when I tried it with my code I got an error.
但是当我用我的代码尝试它时,我得到了一个错误。
document.querySelector('img[alt="PhantomJS"]').click();
TypeError: 'undefined' is not a function
EDIT#1:
编辑#1:
I changed the end section of my code to this:
我将代码的结尾部分更改为:
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);
});
Now my after image is correct. But now my question is, If I want to continue on with my code i.e. click on another element on the site, will my new code have to be all nested inside of the timeout function?
现在我的后图像是正确的。但现在我的问题是,如果我想继续使用我的代码,即单击站点上的另一个元素,我的新代码是否必须全部嵌套在超时函数内?
回答by Steven de Salas
There is an example function phantom.waitFor(callback)
that I explain on the following post, it goes as follows:
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());
}
This can help streamline your code and avoid nested calls to window.setTimeout(), which are not very reliable anyway as you are waiting for a pre-set amount of time instead of waiting for the element to become visible. An example would be as follows:
这可以帮助简化您的代码并避免对 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();
This will load each panel in succession (ie synchronously) while keeping your code simple and avoiding nested callbacks.
这将连续(即同步)加载每个面板,同时保持您的代码简单并避免嵌套回调。
Hope it makes sense. You could also use CasperJS as an alternative, its aimed at making this stuff simpler.
希望这是有道理的。您也可以使用 CasperJS 作为替代方案,它旨在使这些东西更简单。
回答by Artjom B.
Yes, your new code will be called from inside of the setTimeout
callback. You can nest the code directly or write a function which capsules the code for you and call that function inside setTimeout
.
是的,您的新代码将从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);
There is another way. You can also write it completely with multiple setTimeout
, but then you cannot react to sudden conditions in previous calls.
还有另一种方法。您也可以使用 multiple 完全编写它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
I would suggest using CasperJS, if you want to do many actions/navigation steps.
如果您想做许多操作/导航步骤,我建议使用CasperJS。