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。

对于 referencecasper.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 的页面时,原始脚本将被破坏。