0

Stack上有几个类似的问题,但我无法得到任何适合我的答案,我对Node和异步编程的想法完全陌生,所以请多多包涵。

我正在构建一个目前有 4 个步骤的刮板:

  1. 我给它一个链接集合
  2. 它转到这些链接中的每一个,img src在页面上找到所有相关的
  3. 它找到“下一页”链接,获取它的href,从中检索 domhref并重复步骤 #2。
  4. 所有这些img src都放入一个数组并返回

这是代码。getLinks可以异步调用,但其中的while循环目前不能:

function scrape(url, oncomplete) {
    console.log("Scrape Function: " + url);
    request(url, function(err, resp, body) {
        if (err) {
            console.log(UHOH);
            throw err;
        }
        var html = cheerio.load(body);
        oncomplete(html);
    }
    );
}
function getLinks(url, prodURL, baseURL, next_select) {
    var urls = [];
    while(url) {
        console.log("GetLinks Indexing: " + url);
        var html = scrape(url, function(data) {
            $ = data;
            $(prodURL).each(function() {
                var theHref = $(this).attr('href');
                urls.push(baseURL + theHref);
            }
            );
            next = $(next_select).first().attr('href');
            url  = next ? baseurl + next : null;
        }
        );
    }
    console.log(urls);
    return urls;
}

目前,这进入了一个无限循环,没有刮掉任何东西。如果我把url = next ? baseurl + next : null;回调放在外面,我会得到一个"next" is not defined错误。

关于如何重新工作以使其对节点友好的任何想法?看起来,就这个问题的本质而言,它需要被阻塞,不是吗?

4

1 回答 1

1

这是一种常见的模式,您希望执行循环但使用带有回调的异步函数。由于您不能等待异步函数,因此不能简单地使用 while 循环。

一种解决方案是使用“堆栈”(或数组)。用您要处理的初始元素填充它。当您发现更多要处理的元素时,将它们添加到此堆栈中。并递归调用您的函数递增索引以进行处理,直到索引超过数组的长度。

例如

function do_scrape( stack, this_url, callback ) {
    // get list of URLs from webpage at this_url
    ...
    stack.push( new_url ); // adding new element to array
    ...
    ...
    callback(); // process callback
}

function process_stack( stack_of_urls, idx ) {
    var this_url = stack_of_urls[idx];

    do_scrape(
        stack_of_urls,
        this_url,           
        function () {
            if ( idx + 1 < stack_of_urls.length ) {
                process_stack( stack_of_urls, (idx + 1) );
            } else {
                process.exit( 0 );
            }
        }
    );
}

var stack_of_urls = [ "http://www.yahoo.com/" ];
process_stack( stack_of_urls, 0 ); // start from index zero

请注意,有很多方法可以解决这个问题。为了提高效率,您可以从堆栈中删除已处理的元素。您还可以选择是从头到尾处理堆栈,还是从头到尾处理堆栈等。最后请注意,如果您不在函数中调用异步函数,do_scrape那么您将有一个紧密的回调循环,其中 node. js 将中止抱怨堆栈太大。

于 2013-06-04T15:05:04.900 回答