【问题标题】:Trouble returning result when I make use of promise当我使用承诺时无法返回结果
【发布时间】:2019-09-04 15:36:36
【问题描述】:

我在node 中创建了一个脚本,使用promise 结合cheeriolinks 解析为来自网站的不同帖子的标题,然后从它的每个帖子中抓取title内页重用那些links

如果我在getData 中取消注释这一行console.log($("h1 > a").eq(0).text());,我当前的脚本可以相应地获取它们。但是,第二个函数似乎仍然没有返回任何内容。

如何让脚本以现在的方式成功运行?

到目前为止我已经写了:

const request = require('request');
const cheerio = require('cheerio');

const link = 'https://stackoverflow.com/questions/tagged/web-scraping';
const base_link = 'https://stackoverflow.com';

const items = [];
const titles = [];

let getLinks = () => {
    return new Promise((resolve, reject) => {
        request(link, function(error, response, html) {
            let $ = cheerio.load(html);
            $('.summary').each(function() {
                items.push(base_link + $(this).find(".question-hyperlink").attr("href"));
            });
            resolve(items);
        });
    });
};

let getData = (links) => {
    return new Promise((resolve, reject) => {
        for (let nurl of links) {
            request(nurl, function(error, response, html) {
                let $ = cheerio.load(html);
                titles.push($("h1 > a").eq(0).text())
                // console.log($("h1 > a").eq(0).text());

            });
            resolve(titles);
        }
    });
};

getLinks().then((resultList) => {
    return getData(resultList)
})

执行上述脚本后,我没有得到任何结果,也没有错误。

【问题讨论】:

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


    【解决方案1】:

    你的问题是 request 是异步的,所以在执行回调时你会看到控制台日志。

    但是,您在 for 循环的第一次迭代中解决了承诺。因此,您返回一个空数组。

    只有在最后一个请求完成后,您才需要解决承诺:

    let getData = (links) => {
      return new Promise((resolve, reject) => {
        let count = 0
        for (let nurl of links) {
          request(nurl, function(error, response, html) {
            let $ = cheerio.load(html);
            titles.push($("h1 > a").eq(0).text())
    
            count++ // increment count
            if (count === links.length) {
              resolve(titles); // resolve if last request to complete
            }
          });
        }
      });
    };
    

    或者,您可以尝试将每个请求包装在一个 Promise 中,然后使用 Promise.all(),它会在所有 Promise 完成后使用一组结果进行解析:

    let getData = (links) => {
      const promises = links
        .map(nurl => new Promise((resolve, reject) => {
          request(nurl, function(error, response, html) {
            let $ = cheerio.load(html);
            resolve($("h1 > a").eq(0).text())
          })
        }))
    
      return Promise.all(promises)
    }
    

    【讨论】:

    • 感谢您的回答@Steve Holgado。我只是在纠正了你建议的部分后执行了脚本,但我仍然没有得到任何输出。谢谢。
    • 当你说输出时,你的意思是像getData(resultList).then(data => console.log(data))这样的吗?
    • 完美!!是的,这就是我的意思@Steve Holgado。
    • 很高兴它有帮助:)
    猜你喜欢
    • 2019-02-06
    • 1970-01-01
    • 2020-09-21
    • 1970-01-01
    • 2014-05-07
    • 2019-04-19
    • 2017-09-10
    • 2016-04-30
    • 1970-01-01
    相关资源
    最近更新 更多