遍历 url 来做同样的事情

IT技术 javascript loops phantomjs screen-scraping
2021-02-20 15:23:36

我正在尝试抓取一些网站。这是我的代码:

for (var i = 0; i < urls.length; i++) {
    url = urls[i];
    console.log("Start scraping: " + url);

    page.open(url, function () {
        waitFor(function() {
            return page.evaluate(function() {
                return document.getElementById("progressWrapper").childNodes.length == 1;
            });

        }, function() {
            var price = page.evaluate(function() {
                // do something
                return price;
            });

            console.log(price);
            result = url + " ; " + price;
            output = output + "\r\n" + result;
        });
    });

}
fs.write('test.txt', output);
phantom.exit();

我想抓取数组 url 中的所有站点,提取一些信息,然后将此信息写入文本文件。

但是for循环好像有问题。在不使用循环的情况下仅抓取一个站点时,一切都可以按我的意愿工作。但是在循环中,首先什么也没有发生,然后是线

console.log("Start scraping: " + url);

显示,但一次太多。如果 url = {a,b,c},那么 phantomjs 会:

Start scraping: a 
Start scraping: b 
Start scraping: c 
Start scraping:

似乎根本没有调用 page.open 。我是 JS 的新手,所以我很抱歉这个愚蠢的问题。

1个回答

PhantomJS 是异步的。通过page.open()使用循环多次调用,您实际上是在加快回调的执行。您在完成新请求之前覆盖当前请求,然后再次覆盖。您需要一个接一个地执行它们,例如像这样:

page.open(url, function () {
    waitFor(function() {
       // something
    }, function() {
        page.open(url, function () {
            waitFor(function() {
               // something
            }, function() {
                // and so on
            });
        });
    });
});

但这很乏味。有一些实用程序可以帮助您编写更好的代码,例如async.js可以通过npm安装在phantomjs脚本目录下。

var async = require("async"); // install async through npm
var tests = urls.map(function(url){
    return function(callback){
        page.open(url, function () {
            waitFor(function() {
               // something
            }, function() {
                callback();
            });
        });
    };
});
async.series(tests, function finish(){
    fs.write('test.txt', output);
    phantom.exit();
});

如果您不想要任何依赖项,那么定义您自己的递归函数也很容易(从这里):

var urls = [/*....*/];

function handle_page(url){
    page.open(url, function(){
        waitFor(function() {
           // something
        }, function() {
            next_page();
        });
    });
}

function next_page(){
    var url = urls.shift();
    if(!urls){
        phantom.exit(0);
    }
    handle_page(url);
}

next_page();