【问题标题】:Casperjs click() doesn't trigger click event correctlyCasperjs click() 没有正确触发点击事件
【发布时间】:2015-08-13 04:12:49
【问题描述】:

我正在使用 CasperJS 进行网页抓取,但在抓取下面描述的页面时遇到了一些问题。

页面的html是这样的:

<img id="trigger">
<img id="cur_img_xxx" class="show">
<img id="cur_img_yyy" class="cache">

所有&lt;img&gt; 元素共享相同的尺寸,"#trigger" 位于最顶层。当图像有.show 类时,它将显示在页面上;当它是.cache 类时,它将被下载但隐藏。这样,当用户点击图片时,实际上是触发器,将显示下一张图片,并通过 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" 后,最后一个条目会有所不同,即从&lt;img id="cur_img_yyy"&gt; 变为&lt;img id="cur_img_zzz"&gt;。但是,next 仍然持有&lt;img id="cur_img_yyy"&gt;。我做错什么了吗?

【问题讨论】:

标签: javascript ajax click casperjs image-loading


【解决方案1】:

您如何验证没有任何事情发生?所有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() 的包装):

注意:evaluate 函数的参数和返回值必须是简单的原始对象。经验法则:如果可以通过 JSON 序列化就可以了。

闭包、函数、DOM 节点等将起作用!

【讨论】:

  • 我已经编辑了上面的问题,以显示我如何验证没有发生任何事情。我会采纳你的建议试试看:)
  • 我用一个例子扩展了我的答案,并修复了一个我以前没有注意到的问题。
  • 哦,是我的错,没有表达清楚。在代码中应该是$("img[id^='cur_img_']").last().attr("href")。对此感到抱歉:`(
【解决方案2】:

好像是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 的页面时,原始脚本将被破坏。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-07-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-02
    • 2015-12-06
    • 2012-10-10
    相关资源
    最近更新 更多