javascript - 通过在 PhantomJS 中循环抓取多个 URL

标签 javascript for-loop web-scraping phantomjs

我正在使用 PhantomJS 抓取一些网站,因此使用 r 提取信息。我正在关注this教程。对于单个页面来说一切正常,但我找不到任何关于如何自动化多个页面的简单教程。 到目前为止我的实验:

var countries = [ "Albania" ,"Afghanistan"];
var len = countries.length;
var name1 = ".html";
var add1 = "http://www.kluwerarbitration.com/CommonUI/BITs.aspx?country=";
var country ="";
var name ="";
var add="";


for (i=1; i <= len; i++){

    country = countries[i]
    name = country.concat(name1)
    add = add1.concat(name1)

    var webPage = require('webpage');
    var page = webPage.create();

    var fs = require('fs');
    var path = name

    page.open(add, function (status) {
        var content = page.content;
        fs.write(path,content,'w')
        phantom.exit();
    });

}

运行代码时我似乎没有收到任何错误,该脚本仅为第二个国家/地区创建一个 html 文件,其中包含为我感兴趣的小表制作的页面异常的所有信息。

我试图从 similar questions 收集一些信息。然而,也因为我找不到一个简单的可重现的例子,我不明白我做错了什么。

最佳答案

主要问题似乎是你退出得太早了。您正在循环中创建多个 page 实例。由于 PhantomJS 是异步的,因此对 page.open() 的调用立即存在,并执行下一个 for 循环迭代。

for 循环非常快,但网络请求很慢。这意味着您的循环在加载第一页之前就已完全执行。这也意味着加载的第一个页面也将退出 PhantomJS,因为您在每个 page.open() 回调中调用 phantom.exit() 。我怀疑第二个 URL 由于某种原因更快,因此总是被写入。

var countFinished = 0, 
    maxFinished = len;
function checkFinish(){
    countFinished++;
    if (countFinished + 1 === maxFinished) {
        phantom.exit();
    }
}

for (i=1; i <= len; i++) {
    country = countries[i]
    name = country.concat(name1)
    add = add1.concat(country)

    var webPage = require('webpage');
    var page = webPage.create();

    var fs = require('fs');
    var path = name

    page.open(add, function (status) {
        var content = page.content;
        fs.write(path, content,'w')
        checkFinish();
    });
}

问题在于您创建了大量 page 实例而没有进行清理。使用完后您应该关闭它们:

for (i=1; i <= len; i++) {
    (function(i){
        country = countries[i]
        name = country.concat(name1)
        add = add1.concat(country)

        var webPage = require('webpage');
        var page = webPage.create();

        var fs = require('fs');
        var path = name

        page.open(add, function (status) {
            var content = page.content;
            fs.write(path, content,'w');
            page.close();
            checkFinish();
        });
    })(i);
}

由于 JavaScript 具有函数级作用域,因此您需要使用 IIFE 在 page.open() 回调中保留对正确 page 实例的引用。有关详细信息,请参阅此问题:Q: JavaScript closure inside loops – simple practical example

如果您不想事后清理,那么您应该对所有这些 URL 使用相同的 page 实例。我已经有一个关于这样做的答案:A: Looping over urls to do the same thing

关于javascript - 通过在 PhantomJS 中循环抓取多个 URL,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34120421/

相关文章:

javascript - Chrome 应用关闭窗口

javascript - Leaflet:如何通过聚类从不同图层的下拉菜单中选择标记

java - 这是一个测验程序,我必须从 4 个选项中选择 1 个选项,然后我必须显示用户得到了多少个错误和正确的答案

matlab - 条件向量化(循环内)

java - java中的Mastermind游戏

javascript - react 选择 : show only the matched options on typing on the select input

python - 无法获取 URL 列表

python - 使用 BeautifulSoup 将 HTML 表格数据解析为字典

python - 返回抓取的结果数

javascript - 使用javascript显示提交按钮