【问题标题】:call back on cheerio node.js回调cheerio node.js
【发布时间】:2013-09-28 22:08:56
【问题描述】:

我正在尝试使用 'request' 和 'cheerio' 编写 scraper。我有一个包含 100 个网址的数组。我正在遍历数组并在每个网址上使用“请求”,然后执行 Cheerio.load(body)。如果我将 i 增加到 3 以上(即,将其更改为 i nodeJS - Using a callback function with Cheerio 似乎同意。

我的问题是我不明白如何确保网页已“加载”或在循环的每次迭代中被解析,这样我就不会得到任何未定义的变量。根据另一个答案,我不需要回调,但是我该怎么做呢?

for (var i = 0; i < productLinks.length; i++) {
    productUrl = productLinks[i];
    request(productUrl, function(err, resp, body) {
        if (err)
            throw err;
        $ = cheerio.load(body);
        var imageUrl = $("#bigImage").attr('src'),
            productNumber = $("#product").attr('class').split(/\s+/)[3].split("_")[1]
        console.log(productNumber);

    });
};

输出示例:

1461536
1499543

TypeError: Cannot call method 'split' of undefined

【问题讨论】:

  • 你遇到了什么错误?
  • 添加到问题中,不能调用未定义的拆分。如果我删除拆分并仅打印出 imageUrl 和/或 productNumber,则设置了一些变量但很多未定义,这使我相信循环在网页响应之前继续进行?

标签: node.js asynchronous cheerio


【解决方案1】:

由于您没有为每次迭代创建新的$ 变量,因此在请求完成时它会被覆盖。这可能会导致未定义的行为,其中循环的一次迭代正在使用 $,就像它被另一次迭代覆盖一样。

所以尝试创建一个新变量:

var $ = cheerio.load(body);
^^^ this is the important part

此外,您正确地假设循环在请求完成之前继续(在您的情况下,不是 cheerio.load 是异步的,而是 request 是)。这就是异步 I/O 的工作原理。

要协调异步操作,您可以使用例如async 模块;在这种情况下,async.eachSeries 可能有用。

【讨论】:

    【解决方案2】:

    您正在抓取一些外部网站。您不能确定所有 HTML 都符合完全相同的结构,因此您需要对遍历它的方式保持警惕。

    var product = $('#product');
    if (!product) return console.log('Cannot find a product element');
    var productClass = product.attr('class');
    if (!productClass) return console.log('Product element does not have a class defined');
    var productNumber = productClass.split(/\s+/)[3].split("_")[1];
    console.log(productNumber);
    

    这将帮助您调试哪里出了问题,并且可能表明您无法像希望的那样轻松地抓取数据集。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-02-19
      • 2016-02-04
      • 2019-07-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多