CasperJS - 如何从数组中为每个页面保存一些数据?

时间:2016-09-01 11:12:40

标签: javascript phantomjs casperjs

我尝试使用CasperJS抓取网站,但遇到了问题。

第一页我收集了我想要抓取的链接并使用getLinks()函数将它们保存到数组中 - 这很有效。

然后我想从这个数组抓取每个页面(我让这个部分工作),我想从这些页面中获取一些细节。

我的代码如下(修剪了像casper start和login等工作内容):

// Casper start here, and some login stuff, all these are working fine so I removed them to have a light example

// ....
// ....
// ....

// Function for saving members to an array
function getLinks() {
    var links = document.querySelectorAll(".member_name_and_title");
    return Array.prototype.map.call(links, function(link) {
        return link.childNodes[1].childNodes[1].href
    });
}

casper.then(function() {
    // Aggregate results 
    links = this.evaluate(getLinks);

    casper.each(links, function (self, link) {
        self.thenOpen(link, function () {

            var details = this.evaluate(function(){
                document.getElementsByClassName('member_name')[0].textContent;
            });

            // Grab details for each member
            var data = details + " - " + link;

            // Save data
            var fs = require('fs');
            fs.write('results/output.txt', JSON.stringify(data, null, '  '), 'aw');

        });
    });

});

// Casper run
casper.run(function() {
    this.exit();
});

问题是details var将返回null,因此最终的output.txt将是这样的:

"null - domain.com/link1"
"null - domain.com/link2"
"null - domain.com/link3"
"null - domain.com/link4"
"null - domain.com/link5"

link var工作正常,但details var返回null。

当我从阵列中访问任何网址(例如:domain.com/link1)并在浏览器控制台中运行document.getElementsByClassName('member_name')[0].textContent时,它会正确返回值,因此我确定定位很好

我不确定我错过了什么或我做错了什么。任何帮助将非常感激。谢谢!

2 个答案:

答案 0 :(得分:1)

好吧我最终想到了这一点,完全是菜鸟错误......查询是正确的,问题是由页面加载引起的,或者更好地说在运行实际查询之前没有加载数组中的链接。

为了测试这个,我在self.thenOpen函数中使用captureSelection()来捕获页面打开时的状态,但是在收集数据之前。

this.captureSelector('1.jpg', '#page');

我立即注意到该页面未完全加载,因此return document.querySelector('.member_name.').textContent;返回null

为了解决这个问题,我增加了1.5秒的等待时间,如下所示:

casper.wait(1500, function() {
  var details = this.evaluate(function(){
    return document.querySelector('.member_name').textContent;
  });
});

新秀的错误,但未来可能会帮助其他人。

答案 1 :(得分:0)

尝试添加如下所述的回报:

var details = this.evaluate(function(){
    return document.getElementsByClassName('member_name')[0].textContent;
});

修改

这对我有用。我的代码设置如下:

var casper = require('casper').create();

function getLinks() {
    var matchedLinks = document.querySelectorAll(".member_name_and_title");
    return Array.prototype.map.call(matchedLinks, function(link) {
        return link.href;
    });
}

casper.start('http://localhost:8080');

casper.then(function() {
    // Aggregate results 
    links = this.evaluate(getLinks);

    casper.each(links, function (self, link) {

        // INSPECT: Check if it shows the correct link here.
        self.echo('Opening link:' + link);

        self.thenOpen(link, function () {

            var details = this.evaluate(function(){
                // INSPECT: Make sure to 'return' the text content.
                return document.getElementsByClassName('member_name')[0].textContent;
            });

            // Grab details for each member
            var data = details + " - " + link;

            // INSPECT: Check if the data is correct.
            self.echo(data);

            // Save data
            var fs = require('fs');
            fs.write('results/output.txt', JSON.stringify(data, null, '  '), 'aw');
        });
    });
});


casper.run(function(){
    this.exit();
});

我的html文件如下:

的index.html

<!DOCTYPE html>
<html>
<head>
<title>Hello CasperJs</title>
</head>
<body>

<a href="page1.html" class="member_name_and_title">Page 1</a>
<a href="page2.html" class="member_name_and_title">Page 2</a>
<a href="page3.html" class="member_name_and_title">Page 3</a>
<a href="page4.html" class="member_name_and_title">Page 4</a>

</body>
</html>

page1.html

<!DOCTYPE html>
<html>
<head>
<title>Page 1 Title</title>
</head>
<body>

<p class="member_name">Page 1 Text</p>

</body>
</html>

page2.html,page3.html和page4.html的类似HTML标记。我的http服务器在8080端口运行。

我的控制台输出如下:

Opening link:http://localhost:8080/page1.html
Opening link:http://localhost:8080/page2.html
Opening link:http://localhost:8080/page3.html
Opening link:http://localhost:8080/page4.html
Page 1 Text - http://localhost:8080/page1.html
Page 2 Text - http://localhost:8080/page2.html
Page 3 Text - http://localhost:8080/page3.html
Page 4 Text - http://localhost:8080/page4.html

我正在使用带有phantomjs 2.1.1的casperjs 1.1.3。

您可以更新代码并共享控制台输出和软件包版本吗?