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

Puppeteer网页爬虫运行过慢问题求助

分析Puppeteer爬取变慢/停滞的原因及解决方案

嘿,结合你的代码和问题描述,我帮你梳理几个最可能的原因,以及对应的解决办法:

1. 异步流程错误:请求响应提前返回,导致资源泄漏

你的start()是异步函数,但在app.get的回调里直接调用却没有加await——这就意味着res.render会在爬虫还没完成的时候就先执行了,不仅前端拿到的是空数据,更严重的是:浏览器实例可能因为请求频繁、来不及关闭而大量积累,导致内存占用飙升,最终爬取速度变慢甚至直接卡住。

解决办法:把app.get的回调改成异步函数,并且await start()的执行结果:

app.get('/', async function(req, res) { // 标记为async
     async function start() {
          const browser = await puppeteer.launch(/* 后面会加优化参数 */);
          const page = await browser.newPage();
          await page.setDefaultNavigationTimeout(0); 
          await page.goto("URL", { waitUntil: 'domcontentloaded' });
          await page.waitForSelector(".overlay-text", { timeout: 30000 }); // 等待元素加载
          const prices = await page.evaluate(() => {
               return Array.from(document.querySelectorAll(".overlay-text")).map(x => x.textContent.trim())
          })
          await page.close();
          await browser.close();
          // 直接返回数据,避免全局变量竞争
          return {
               usdBuy: prices[0],
               usdSell: prices[1],
               gbpBuy: prices[2],
               gbpSell: prices[3],
               eurBuy: prices[4],
               eurSell: prices[5]
          }
     }    
     const data = await start(); // 等待爬虫完成
     res.render("home", data); // 用爬取到的真实数据渲染
})

2. Puppeteer默认配置资源占用过高

默认启动的Puppeteer会加载完整的浏览器环境,包括图片、CSS、GPU加速等,这些都会消耗大量资源,尤其是在服务器环境下,很容易导致爬取速度变慢。

解决办法:启动浏览器时添加优化参数,减少不必要的资源加载:

const browser = await puppeteer.launch({
  headless: 'new', // 新版无头模式,性能更优
  args: [
    '--no-sandbox', // 服务器环境下常用,避免权限问题
    '--disable-setuid-sandbox',
    '--disable-dev-shm-usage', // 解决Linux下/dev/shm内存不足的问题
    '--disable-gpu', // 禁用GPU加速,不需要渲染页面
    '--blink-settings=imagesEnabled=false', // 禁用图片加载,大幅节省时间和资源
    '--disable-extensions',
    '--disable-plugins'
  ]
});

3. 目标网站的反爬机制或页面加载逻辑变化

之前代码正常现在变慢,很可能是目标网站更新了反爬策略(比如检测无头浏览器、增加请求延迟),或者页面的动态加载逻辑变了,导致page.goto默认等待load事件(所有资源加载完成)的时间大幅增加。

解决办法:

  • 优化页面跳转的等待逻辑:把waitUntil设置为domcontentloaded,只等待DOM加载完成,无需等待所有资源:
    await page.goto("URL", { waitUntil: 'domcontentloaded' });
    
  • 模拟真实浏览器环境,规避反爬:
    await page.setUserAgent('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36');
    await page.setExtraHTTPHeaders({
      'Accept-Language': 'en-US,en;q=0.9'
    });
    
  • 显式等待目标元素出现:避免因为元素还未渲染完成就执行evaluate导致的等待超时:
    await page.waitForSelector(".overlay-text", { timeout: 30000 }); // 设置30秒超时,可根据情况调整
    

4. 全局变量导致的请求竞争

你用了全局变量usdBuy、usdSell等存储爬取结果,当有多个并发请求时,这些变量会被覆盖,不仅数据错误,还可能导致异步流程的混乱,间接影响爬取速度。

解决办法:像第一个方案里那样,让start()函数直接返回爬取到的数据,用局部变量接收后再渲染页面,彻底避免全局变量的问题。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 18:50:29