首页 > 解决方案 > Puppeteer 不断收到 TimeoutError:超过 80000 毫秒的导航超时

问题描述

我正在尝试抓取传递给抓取函数的任何网页,但是无论在 page.goto() 设置的超时时间如何,我都会收到超时错误,如果设置为 0,则应用程序只会一直等待。

const express = require('express');
const cors = require('cors');
const MYPORT = process.env.PORT || 4001;


const app = express();
const puppeteer = require('puppeteer');

app.use(express.json());
app.use(cors());

const scrape = async (url) => {
    var body;
    try {
        const browser = await puppeteer.launch({
            headless: true,
            args: ['--no-sandbox'],
            timeout: 0
        });
        console.log('Browser launched');
        const page = await browser.newPage();
        console.log('Page opened');
        await page.goto(url, { waitUntil: 'load', timeout: 3 * 60000 });
        await page.waitForSelector('body', {waitUntil: 'load'})
        console.log('Link opened');
        await page.waitForNavigation({waitUntil: 'networkidle2', timeout: 3 * 60000});
        page.$eval('html', bdy => {
            console.log(bdy);
            body = bdy.innerHTML;
        });
        browser.close();
        return body;
    } catch (err) {
        console.log(err);
    }
};

scrape('http://google.com');

请问,我做错了什么?

我在 WSL(Linux 的 Windows 子系统)上使用 Ubuntu 18.04

标签: node.jsexpresspuppeteerubuntu-18.04windows-subsystem-for-linux

解决方案


您使脚本的 timeout-waitfor 部分过于复杂。我建议进行以下更改:

  1. 如果您不确定是什么原因导致您应该设置超时,headless: false以便您可以在 UI 上看到出了什么问题,您可以打开浏览器控制台等。
  2. waitForSelector在脚本使用-s完成您想要的操作之前,不要设置超时。我从你的脚本中删除了它们。
  3. 如果你对每个网络事件都不感兴趣(尤其是对分析和跟踪请求不感兴趣),但你只需要 DOM,那么使用waitUntil: 'domcontentloaded'而不是load或最严格的networkidle2!在文档中查看它们之间的确切区别:[链接]
  4. waitForNavigation在您已经等待选择器之后不要这样做。这就是您的脚本失败的主要原因:一旦<body>出现在 DOM 中,您要求 puppeteer 等到导航完成,但此时您没有导航:您已经在页面上。记住:

    page.waitForNavigation当页面导航到新 URL 或重新加载时解析。当您运行将间接导致页面导航的代码时,它很有用。[资源]

  5. page.eval$缺乏它的异步性质,而它应该总是异步的。无论如何innerHTML<body>可以用更简单的方法来检索of await page.evaluate(el => el.innerHTML, await page.$('body')):。
const scrape = async url => {
  try {
    const browser = await puppeteer.launch({
      headless: false,
      args: ['--no-sandbox']
    })
    console.log('Browser launched')
    const page = await browser.newPage()
    console.log('Page opened')
    await page.goto(url, { waitUntil: 'domcontentloaded' })
    await page.waitForSelector('body')
    console.log('Link opened')
    const body = await page.evaluate(el => el.innerHTML, await page.$('body'))
    console.log(body)
    browser.close()
    return body
  } catch (err) {
    console.log(err)
  }
}

推荐阅读