Casperjs click() 没有正确触发点击事件
Casperjs click() doesn't trigger click event correctly
我正在使用 CasperJS 进行网页抓取,但我在抓取下面描述的页面时遇到了一些问题。
页面的 html 如下所示:
<img id="trigger">
<img id="cur_img_xxx" class="show">
<img id="cur_img_yyy" class="cache">
所有 <img>
元素共享相同的维度,并且 "#trigger"
在最顶层。当一张图片有.show
class时,会显示在页面上;当它是 .cache
class 时,它将被下载但隐藏。这样,当用户点击图片时,这实际上是触发器,将显示下一张图片,并通过 AJAX 下载新图片。结果 html 变为:
<img id="trigger">
<img id="cur_img_xxx" class="cache">
<img id="cur_img_yyy" class="show">
<img id="cur_img_zzz" class="cache">
我想这是增加用户体验的好策略,也有助于避免网页抓取,但我还是想抓取 :P
我在 Web 控制台中尝试 $("#trigger").click()
,图像得到导航和下载更正。然而,当我尝试使用 CasperJS 模拟这个过程时,导航和图像下载都不起作用。请参考代码:
var casper = require ("casper").create({
clientScripts: [
'include/jquery.js'
],
pageSettings: {
loadImages: false, // this won't affect since this will only forbid
loadPlugins: false // inline imgs from loading, but all imgs in this
}, // page are loaded dynamically
verbose: true
});
casper.start("http://www.example.com/1234.html");
casper.then(function () {
console.log("Connected! Current Url = " + this.getCurrentUrl());
});
casper.then(function () {
// findInitialImgs will find imgs that have already been loaded
imgs = this.evaluate(findInitialImgs);
this.waitForSelector("#image_trigger").thenClick("#image_trigger");
var next = this.evaluate(function () {
return $("img[id^='cur_img_']").last().attr("href");
});
console.log(next);
});
casper.run(function () {
this.echo('End').exit();
});
对了,点击"#trigger"
后,最后的条目会不一样,即从<img id="cur_img_yyy">
变成<img id="cur_img_zzz">
。但是,next
仍然保持 <img id="cur_img_yyy">
。我做错了什么吗?
你如何验证没有发生任何事情? wait*()
和then*()
函数都是异步步进函数,但evaluate
不是,所以先于其他两个函数执行。您需要将最后一个 evaluate
调用包装在 then
块中,以确保包含它的步骤在单击后执行。
由于图像加载可能是异步执行的,因此您需要将最后一个 evaluate
调用包装在一个 wait
块中,等待时间很短:
casper.then(function () {
// findInitialImgs will find imgs that have already been loaded
imgs = this.evaluate(findInitialImgs);
this.waitForSelector("#image_trigger")
.thenClick("#image_trigger")
.wait(1000, function(){
var next = this.evaluate(function () {
return $("img[id^='cur_img_']").last()[0].id;
});
console.log(next);
});
});
请注意,您不能将 DOM 节点传递到页面上下文 (evaluate()
) 之外,因此您需要使用某种表示形式。这里我用的是最后一个元素的id。
对于 reference(casper.evaluate()
只是 PhantomJS 的包装器 page.evaluate()
):
Note: The arguments and the return value to the evaluate
function must be a simple primitive object. The rule of thumb: if it can be serialized via JSON, then it is fine.
Closures, functions, DOM nodes, etc. will not work!
好像是JQuery
的问题。在我删除 JQuery
注入后,将 $("img[id^='cur_img_']").last().attr("href")
更改为
var imgs = document.querySelectorAll("img[id^='cur_img_']");
return imgs[imgs.length - 1].getAttribute("href");
一切正常。
然后我发现这个答案很强大:CasperJS click event having AJAX call
因此确认当您将 JQuery
注入到使用 $
作为 JQuery
的页面时,原始脚本将被破坏。
我正在使用 CasperJS 进行网页抓取,但我在抓取下面描述的页面时遇到了一些问题。
页面的 html 如下所示:
<img id="trigger">
<img id="cur_img_xxx" class="show">
<img id="cur_img_yyy" class="cache">
所有 <img>
元素共享相同的维度,并且 "#trigger"
在最顶层。当一张图片有.show
class时,会显示在页面上;当它是 .cache
class 时,它将被下载但隐藏。这样,当用户点击图片时,这实际上是触发器,将显示下一张图片,并通过 AJAX 下载新图片。结果 html 变为:
<img id="trigger">
<img id="cur_img_xxx" class="cache">
<img id="cur_img_yyy" class="show">
<img id="cur_img_zzz" class="cache">
我想这是增加用户体验的好策略,也有助于避免网页抓取,但我还是想抓取 :P
我在 Web 控制台中尝试 $("#trigger").click()
,图像得到导航和下载更正。然而,当我尝试使用 CasperJS 模拟这个过程时,导航和图像下载都不起作用。请参考代码:
var casper = require ("casper").create({
clientScripts: [
'include/jquery.js'
],
pageSettings: {
loadImages: false, // this won't affect since this will only forbid
loadPlugins: false // inline imgs from loading, but all imgs in this
}, // page are loaded dynamically
verbose: true
});
casper.start("http://www.example.com/1234.html");
casper.then(function () {
console.log("Connected! Current Url = " + this.getCurrentUrl());
});
casper.then(function () {
// findInitialImgs will find imgs that have already been loaded
imgs = this.evaluate(findInitialImgs);
this.waitForSelector("#image_trigger").thenClick("#image_trigger");
var next = this.evaluate(function () {
return $("img[id^='cur_img_']").last().attr("href");
});
console.log(next);
});
casper.run(function () {
this.echo('End').exit();
});
对了,点击"#trigger"
后,最后的条目会不一样,即从<img id="cur_img_yyy">
变成<img id="cur_img_zzz">
。但是,next
仍然保持 <img id="cur_img_yyy">
。我做错了什么吗?
你如何验证没有发生任何事情? wait*()
和then*()
函数都是异步步进函数,但evaluate
不是,所以先于其他两个函数执行。您需要将最后一个 evaluate
调用包装在 then
块中,以确保包含它的步骤在单击后执行。
由于图像加载可能是异步执行的,因此您需要将最后一个 evaluate
调用包装在一个 wait
块中,等待时间很短:
casper.then(function () {
// findInitialImgs will find imgs that have already been loaded
imgs = this.evaluate(findInitialImgs);
this.waitForSelector("#image_trigger")
.thenClick("#image_trigger")
.wait(1000, function(){
var next = this.evaluate(function () {
return $("img[id^='cur_img_']").last()[0].id;
});
console.log(next);
});
});
请注意,您不能将 DOM 节点传递到页面上下文 (evaluate()
) 之外,因此您需要使用某种表示形式。这里我用的是最后一个元素的id。
对于 reference(casper.evaluate()
只是 PhantomJS 的包装器 page.evaluate()
):
Note: The arguments and the return value to the
evaluate
function must be a simple primitive object. The rule of thumb: if it can be serialized via JSON, then it is fine.Closures, functions, DOM nodes, etc. will not work!
好像是JQuery
的问题。在我删除 JQuery
注入后,将 $("img[id^='cur_img_']").last().attr("href")
更改为
var imgs = document.querySelectorAll("img[id^='cur_img_']");
return imgs[imgs.length - 1].getAttribute("href");
一切正常。
然后我发现这个答案很强大:CasperJS click event having AJAX call
因此确认当您将 JQuery
注入到使用 $
作为 JQuery
的页面时,原始脚本将被破坏。