You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Puppeteer定时调用十余次waitForSelector报30秒超时问题

问题原因说明

为什么设置了2分钟导航超时,实际报30秒超时

  • Puppeteer的超时配置是分类型生效的:setDefaultNavigationTimeout仅对goto、reload、页面跳转类的导航操作生效,你报错的waitForSelector属于元素等待类API,它的默认超时是独立的30000ms,没有单独配置的话就会触发30秒超时,和导航超时设置无关。

为什么运行10-15次后必现超时,重启服务才恢复

  • 核心原因是资源泄漏:你当前的代码每次调用爬虫函数都会启动一个全新的Chrome浏览器实例,但逻辑全程没有调用browser.close()、page.close()释放资源。运行十几次后,服务器后台会堆积十多个无头Chrome进程,吃光CPU、内存资源,后续新启动的Chrome根本无法在超时时间内完成页面渲染,自然等不到目标选择器。此时只有重启服务杀掉所有残留进程,释放资源后才能恢复正常。
  • 额外的隐藏问题:
    • 启动参数缺少服务端运行必备的--disable-dev-shm-usage,多数Linux服务端的/dev/shm共享内存分区默认大小只有64M,Chrome默认往这个分区写临时数据,跑几次就会写满导致页面加载卡住。
    • catch块没有接收error参数,真出异常也打不出完整错误栈,会误导排查方向。
    • 每次调用都新建浏览器实例的开销极大,本身就会加速资源耗尽。
修复方案
  • 统一超时配置:调用page.setDefaultTimeout(120000)设置全局默认超时,所有操作(包括元素等待、导航)都会继承这个配置,也可以给waitForSelector单独传timeout参数覆盖。
  • 补全资源回收逻辑:在finally块里无论爬取成功还是失败,都关闭当前打开的页面,避免标签页、浏览器进程残留。
  • 复用浏览器实例:不要每次调用爬虫都启动新Chrome,维护一个长驻的浏览器实例,每次调用只新建标签页即可,能降低90%以上的资源开销;可以加个逻辑每运行20次左右主动重启一次浏览器,规避Chrome长时间运行的内存泄漏问题。
  • 补全Chrome启动参数,加上--disable-dev-shm-usage适配服务端运行环境。
  • 修正catch块写法,正确接收并打印异常信息。
修复后参考代码
const puppeteer = require('puppeteer');
// 全局维护浏览器实例,避免重复启动
let browser = null;

async function initBrowser() {
  if (browser?.connected) return browser;
  browser = await puppeteer.launch({
    headless: true,
    args: [
      "--no-sandbox",
      "--disable-setuid-sandbox",
      "--disable-dev-shm-usage", // 解决服务端共享内存不足问题
    ],
  });
  // 浏览器意外退出时清空实例引用,下次调用自动重建
  browser.on('disconnected', () => {
    browser = null;
  });
  return browser;
}

async function runCrawler(baseUrl) {
  const browserIns = await initBrowser();
  const page = await browserIns.newPage();
  // 全局设置所有操作默认超时为2分钟
  page.setDefaultTimeout(120000);
  try {
    // waitUntil用domcontentloaded比load更快,不需要等所有图片、静态资源加载完
    await page.goto(baseUrl, { waitUntil: "domcontentloaded" });
    await page.waitForSelector(
      "body > div.page-window.market-watch.compact > div > div.b > div.page-block > div > table > tbody > tr:nth-child(1) > td.symbol"
    );
    // 此处编写你的数据爬取逻辑
    // const result = await page.evaluate(() => {})
    // return result
  } catch (error) {
    console.error('爬取执行异常:', error);
    throw error;
  } finally {
    // 无论成功失败,都关闭当前标签页,避免标签页堆积
    if (!page.isClosed()) {
      await page.close().catch(() => {});
    }
  }
}

// 每5分钟调用一次即可
// setInterval(() => runCrawler('你的目标地址'), 5 * 60 * 1000)

内容的提问来源于stack exchange,提问作者Ebuka

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 02:03:27