循环播放嵌套承诺

时间:2018-04-04 01:28:43

标签: node.js web-scraping promise request-promise

我正在使用Request-Promisecheerio来抓取一些网站数据,基本上我试图实现以下目标:

  1. 创建空数组
  2. 登录
  3. 从一个页面获取一些信息并将对象推入数组
  4. 从其他页面获取一些信息并将对象推入数组
  5. 对于数组中的每个现在对象,我需要:
    • 转到该对象中存储的网址 {link:“some url”,items:[]}
    • 循环遍历该链接中找到的所有项目,并将其推送到迭代对象中的items数组: {link:“some url”,items:[{item},{item}]} 即可。
  6. 访问已完成的 orderArray ,这应该吐出这样的内容:
  7. {link: "some url", items: [{item},{item}]},
    {link: "some url", items: [{item},{item}]},
    {link: "some url", items: [{item},{item}]}
    

    第6步是我遇到问题的地方,我不知道怎么做,如果没有在for循环中嵌入promise,根据我的代码,然后开始变得讨厌。我能指出正确的方向吗?

    这是我目前的代码:

        let orderArray = [];
    
        rp.post(login)
    
        .then(function(res1){
    
            // Login & Set Cookies
            cookieJar = res1.headers['set-cookie'];
    
            return rp(getOpenOrders);
    
        })
    
        .then(function($){
    
            // Get Some Info from getOpenOrders
    
            orderArray.push({info});
    
            return rp(getShippedOrders);
    
        })
    
        .then(function($){
    
            // Get Some Info from getShippedOrders
    
            orderArray.push({info});
    
            return orderArray;
    
        })
    
        .then(function($){
    
            // Loop through each object in the orderArray
            for (i = 0,; i < orderArray.length; i++){
    
                rp(orderArray[I].link)
    
                .then(function($){
    
                //Get length of items on page
                let itemsOnPage = $('tbody tr').length;
    
                //Get some more details for each object
                for (j = 0,; j < items.length; j++) {
                        let moreinfo = {…};
                        orderArray.items.push(moreinfo);
                }
    
              }
            }
    
            return orderArray;
    
        })
    
        .then(function($){
    
            // Log finished Array
            console.log(orderArray);
    
        })
    
        .catch(function(err){
            console.log(err);
        })
    
        };
    

1 个答案:

答案 0 :(得分:2)

最简单,最干净的方法是使用async/await。该代码不会并行运行(除非我们等待Promise.all

.then(async() => {

    // Loop through each object in the orderArray
    for(let i = 0; i < orderArray.length; i++) {

        // Some may argue no await inside loop...
        // We wait for rp to resolve, it looks like
        // synchronous code so it's easy to understand
        const $ = await rp(orderArray[i].link);

        let items = $('tbody tr');

        for(const item of items) {
            let moreinfo = {};
            orderArray[i].items.push(moreinfo);
        }

    }

    return orderArray;
})

您还可以使用Promise.all并行发送所有请求,并在结果完成后处理结果。

.then(() => {

    // Loop through each object in the orderArray

    const requests = [];

    for(const order of orderArray) {
        // Push each promise
        requests.push(
            rp(order.link)
        );
    }

    // This will resolve when every request finishes
    // If one fails, it will reject, going to `.catch`
    return Promise.all(requests); 
})
.then(results => {

    // Results is an array containing each individual request result.

    results.forEach(($, i) => {

        //Get length of items on page
        let items = $('tbody tr');

        //Get some more details for each object
        for(const item of items) {
            let moreinfo = {};
            orderArray[i].items.push(moreinfo);
        }

    })

    return orderArray;

});

我认为rp会解析一个cheerio对象,如果它没有让我知道。

我无法对其进行测试,因为我没有完整的代码,但它应该有效。