首页 > 解决方案 > 节点 puppeteer Promise.all 一次查看不同页面时的所有问题

问题描述

所以我对网络抓取相当陌生,并且一直在使用 puppeteer 库来这样做。我设法让大多数事情正常工作,但是当尝试 promise.all 并触发第二个函数以转到两个单独的页面时,它始终是 promise.all 映射中的最后一页,即使在调试器中它也会变为两个它应该已经转到有问题的页面。

触发数据获取的函数类似于下面的代码示例

const fetchSeasonUrls = async () => {
  const driver = await configuration.getDriver(baseUrl);

  const watchList = await fetchWatchList(driver);

  // When the function below is hit the end result looks like example result one below
  const watchListSeasons = await Promise.all(
    watchList.map(async show => {
      await tvSplurgeio.getSeasonData(driver, show);
    })
  );

  // When the function below is hit the end result looks like example result two below
  const showOne = await tvSplurgeio.getSeasonData(driver, watchList[0]);
  const showTwo = await tvSplurgeio.getSeasonData(driver, watchList[1]);
} 

示例结果一

[
  [S01, S02, ..., S31],
  [S01, S02, ..., S31]
]

示例-结果-二

const showOne = [S01, S02, ..., S10];
const showTwo = [S01, S02, ..., S31];

第二个结果是正确的,因为它导航到正确的显示页面并用它拉回季节数据,但是当它在一个承诺中时,它似乎返回数组中的最后一个东西 x 次。

返回此数据的 puppeteer 代码如下所示。


const tvSplurgeio = {
  getSeasonData: async (driver, show) => {
    let navigationPromise = driver.page.waitForNavigation();
    await driver.page.goto(show.url);
    await navigationPromise;

    await driver.page.waitForSelector(".sidebar-seasons");
    const seasonData = await driver.page.evaluate(() => {
      const allSeasons = document.querySelectorAll(
        'li[class*="sidebar-season"]'
      );

      let data = [];
      Array.prototype.forEach.call(allSeasons, season => {
        Array.prototype.forEach.call(season.children, child => {
          const seasonNumber = parseInt(child.innerText.split(" ")[1], 10);
          data.push(
            seasonNumber < 10 ? `S0${seasonNumber}` : `S${seasonNumber}`
          );
        });
      });
      return data;
    });

    await navigationPromise;
    return seasonData;
  },
}

我已经尝试了很多东西,从 page.waitFor() 到等待导航承诺,我不太确定这是否只是对 promise.alls 中这个库可以做什么的误解。

克里斯,任何帮助将不胜感激。

标签: javascriptnode.jsasynchronouses6-promisepuppeteer

解决方案


我怀疑您的问题来自使用Promise.all. 此外,map当您想要对数组的元素执行操作,然后返回带有修改的新数组时,更适合使用。

由于您似乎没有使用 from 返回的值map,因此我建议您尝试forEach并简单地将 from 返回的每个值推tvSplurgeio.getSeasonData()送到一个新数组seasonData中。

const watchList = await fetchWatchList(driver);
const seasonData = [];

watchList.forEach(async show => {
  seasonData.push(await tvSplurgeio.getSeasonData(driver, show));
});

推荐阅读