Проблема возвращения результата, когда я использую обещание - PullRequest
0 голосов
/ 14 апреля 2019

Я создал скрипт в node, используя promise в сочетании с cheerio, чтобы проанализировать links для заголовков различных постов с веб-сайта, а затем очистить title каждого поста от его внутреннюю страницу, используя эти links.

Мой текущий скрипт может извлекать их соответствующим образом, если я раскомментирую эту строку console.log($("h1 > a").eq(0).text()); в getData. Однако, похоже, что вторая функция все еще ничего не возвращает.

Как сделать так, чтобы скрипт успешно работал, как сейчас?

Я уже написал:

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)
})

После выполнения вышеуказанного скрипта я не получаю ни результата, ни ошибки.

1 Ответ

1 голос
/ 14 апреля 2019

Ваша проблема в том, что 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.all(), который разрешается с массивом результатов, когда все обещания выполнены:

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)
}
...