Casperjs使用casper.each迭代链接列表

时间:2016-11-03 23:08:14

标签: javascript phantomjs casperjs

我正在尝试使用Casperjs从页面获取链接列表,然后打开每个链接,并从这些页面向数组对象添加特定类型的数据。

我遇到的问题是在每个列表项上执行的循环。

首先我从原始页面获得listOfLinks。这部分工作和使用长度,我可以检查这个列表是否已填充。

但是,使用如下所示的循环语句this.each,没有任何控制台语句出现,并且casperjs似乎跳过此块。

用标准的for循环替换this.each,执行只能通过第一个链接的一部分,作为语句"在x.html"的对象中创建新数组出现一次然后代码停止执行。使用IIFE不会改变这种情况。

编辑:在详细调试模式下会发生以下情况:

Creating new array object for https://example.com 
[debug] [phantom] Navigation requested: url=about:blank, type=Other, willNavigate=true, isMainFrame=true

因此,由于某种原因,传递给thenOpen函数的URL变为空白...

我觉得Casperjs的异步性质有些让我感到不舒服,并希望能够指出一个有效的例子。

casper.then(function () {

  var date = Date.now();
  console.log(date);

  var object = {};
  object[date] = {}; // new object for date

  var listOfLinks = this.evaluate(function(){
    console.log("getting links");
    return document.getElementsByClassName('importantLink');
  });

  console.log(listOfLinks.length);

  this.each(listOfLinks, function(self, link) {

    var eachPageHref = link.href;

    console.log("Creating new array in object for " + eachPageHref);

    object[date][eachPageHref] = []; // array for page to store names

    self.thenOpen(eachPageHref, function () {

      var listOfItems = this.evaluate(function() {
        var items = [];
        // Perform DOM manipulation to get items
        return items;
      });
    });

    object[date][eachPageHref] = items;

  });
  console.log(JSON.stringify(object));

});

3 个答案:

答案 0 :(得分:4)

我决定使用我们自己的Stackoverflow.com作为演示站点来运行您的脚本。我在代码中纠正了一些小问题,结果就是从PhantomJS赏金问题中获得评论。

public class TestInterrupt
{
    public static volatile boolean shouldTerminate = false;

    public static void main(final String[] args) throws InterruptedException
    {
        int i = 0;
        while (++i < 100)
        {
            Thread.sleep(1000);

            if(shouldTerminate) {
                break;
            }
        }

        // write data to file here.
    }
}

更改内容:var casper = require('casper').create(); casper .start() .open('http://stackoverflow.com/questions/tagged/phantomjs?sort=featured&pageSize=30') .then(function () { var date = Date.now(), object = {}; object[date] = {}; var listOfLinks = this.evaluate(function(){ // Getting links to other pages to scrape, this will be // a primitive array that will be easily returned from page.evaluate var links = [].map.call(document.querySelectorAll("#questions .question-hyperlink"), function(link) { return link.href; }); return links; }); // Now to iterate over that array of links this.each(listOfLinks, function(self, eachPageHref) { object[date][eachPageHref] = []; // array for page to store names self.thenOpen(eachPageHref, function () { // Getting comments from each page, also as an array var listOfItems = this.evaluate(function() { var items = [].map.call(document.getElementsByClassName("comment-text"), function(comment) { return comment.innerText; }); return items; }); object[date][eachPageHref] = listOfItems; }); }); // After each links has been scraped, output the resulting object this.then(function(){ console.log(JSON.stringify(object)); }); }) casper.run(); 现在返回简单数组,这是casper.each()正确迭代所需的数组。 {page 1}}中会立即提取page.evaluate个属性。还有这个修正:

href

脚本运行的结果是

 object[date][eachPageHref] = listOfItems; // previously assigned items which were undefined in this scope

答案 1 :(得分:3)

您正在evaluate()函数中返回 DOM节点,这是不允许的。您可以改为返回实际的网址。

  

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

     

闭包,函数,DOM节点等不起作用!

参考:PhantomJS#evaluate

答案 2 :(得分:1)

如果我理解你的问题,要解决,给项目[]一个全球范围。在您的代码中,我会做以下事情:

var items = [];
this.each(listOfLinks, function(self, link) {

    var eachPageHref = link.href;

    console.log("Creating new array in object for " + eachPageHref);

    object[date][eachPageHref] = []; // array for page to store names

    self.thenOpen(eachPageHref, function () {

        this.evaluate(function() {
        // Perform DOM manipulation to get items
        items.push(whateverThisItemIs);
      });
    });

希望这有帮助。