如果页面中不存在 DOM 元素,我该如何移动到下一次迭代?

How can I move to the next iteration if a DOM element is not present in the page?

我想用 puppeteer 测试网页的几个子页面。该网页有一些针对机器人的保护措施。我有一个数组中的 url,我遍历这个数组。

我不知道应该如何重写我的代码,因为我遇到了几个问题:由于机器人保护,页面在实际加载之前向浏览器发送了一些 "fake loaded" 状态真实的内容。因此,我认为我必须等待一些 DOM 个元素。

await page.waitForSelector('div.site__content');

确保内容已加载。 (等待 page.evaluate 由于机器人保护而无法正常工作,它会在第一个 "fake loaded" 标志上触发)。

但是还有另一个问题:如果页面加载不正确(例如由于连接超时),我会遇到未处理的承诺拒绝错误并且迭代停止,程序的执行将停止。

我的目标是,如果在加载页面时出现任何类型的错误,则跳过当前迭代并移至下一个迭代,而不会导致程序崩溃。但我必须保留

await page.waitForSelector

部分也是。 我怎样才能做到这一点?

(async function filterIds() {
  let filteredIds = ['url1', 'url2', '...', 'url200'];
  const browser = await puppeteer.launch({ headless: false });
  const context = await browser.createIncognitoBrowserContext();
  const page = await context.newPage();
  await tuneUserAgent(page);
  for (let id in filteredIds) {
    let errorPage = null;
    let url = filteredIds[id];
    await page.goto(url, { waitUntil: 'load', timeout: 120000 });
    await page.waitForSelector('div.site__content'); // to be sure that the content has been loaded
    errorPage = await page.evaluate(() => {
      return document.querySelector('div.errorpage');
    });
    if (errorPage != null || errorPage === undefined) {
      continue;
    }
    await page.waitForSelector('div.dialog');
    let noGallery = await page.evaluate(() => {
      return document.querySelector('div[class="is-not-photo-uploaded-text"]');
    });
    if (noGallery != null || noGallery === undefined) {
      openOrNot = 5;
    }
    if (openOrNot < 4) {
      await openGallery(page);
    }
    let html = await page.content();
    await fs.writeFile(`./saved_items/${filteredIds[id].substring(filteredIds[id].lastIndexOf('/') + 1)}.html`, html, function (err) {
      if (err) throw err;
    });
    await page.waitFor(400);
  }
  await browser.close();
})();

当 promise 被拒绝且未被捕获时抛出 "unhandled promise rejection error"。如果像您的情况一样在异步代码块内抛出异常,则隐含这种情况。

要捕获抛出的异常,您只需在循环中使用 try..catch 块。

代码示例

for (let id in filteredIds) {
  try {
    // your code
  } catch (err) {
    console.log(`Iteration for ${id} failed with error: ${err.message}`);
  }
}

您的代码产生的所有错误都应该被此代码捕获,fs.writeFile 中的 if (err) throw err; 除外,因为此回调是异步调用的,因此在您的 try..catch 之外执行堵塞。但是您可以简单地使用新的 fs.promises.writeFile 甚至捕获该错误。

如果出现错误,将调用脚本的 catch (err) { ... } 部分,记录错误消息和发生错误的 id 部分。由于脚本不再崩溃,循环将继续进行下一次迭代。