优化Puppeteer爬虫性能:解决接口响应过慢问题
Puppeteer 爬取性能优化方案
你的接口响应慢的核心原因是每次请求都重复启动/销毁浏览器,以及多次独立的DOM查询导致上下文切换开销,以下是针对性的优化措施:
核心优化点
1. 全局复用浏览器实例
启动浏览器是Puppeteer中最耗时的操作之一,不要在每次请求中都调用puppeteer.launch()和browser.close(),改为服务启动时初始化一次,全局复用:
// 全局保存浏览器实例 let browser; // 服务启动时初始化浏览器 async function initBrowser() { browser = await puppeteer.launch({ headless: 'new', // 新版无头模式,性能更优 args: [ '--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage', // 解决内存不足问题 '--disable-gpu' ] }); } // 启动服务时执行初始化 initBrowser().catch(err => console.error('浏览器初始化失败:', err)); // 服务关闭时关闭浏览器 process.on('exit', async () => { if (browser) await browser.close(); });
2. 合并多次DOM查询为一次
当前代码分4次调用$$eval,每次都要在Node.js和浏览器上下文之间切换,合并成一次查询,直接在浏览器端组装好数据结构,减少上下文切换开销。
3. 禁用非必要资源加载
页面加载的图片、CSS、字体等资源对爬取数据无帮助,禁用这些资源可以大幅减少页面加载时间。
4. 优化页面加载等待策略
page.goto()默认等待所有资源加载完成,改为等待DOM渲染完成即可开始爬取。
优化后的完整接口代码
app.get("/home", async (req, res) => { try { if (!browser) { return res.status(503).json({ error: "浏览器未初始化,请稍后重试" }); } const page = await browser.newPage(); const pageNumber = req.query.page || 1; // 拦截并禁用非必要资源请求 await page.setRequestInterception(true); page.on('request', (req) => { const resourceType = req.resourceType(); // 禁用样式、图片、字体、媒体资源 if (['stylesheet', 'image', 'font', 'media'].includes(resourceType)) { req.abort(); } else { req.continue(); } }); // 等待DOM加载完成即可,无需等待所有资源 await page.goto(`https://gogoanimehd.io/?page=${pageNumber}`, { waitUntil: 'domcontentloaded', timeout: 30000 // 设置30秒超时,避免请求挂起 }); // 一次查询所有数据并组装成目标结构 const animeCard = await page.$$eval(".items", (items) => { return items.map(item => ({ animeInfo: item.querySelector('p.name')?.textContent.trim() || '', animeEpNo: item.querySelector('p.episode')?.textContent.trim() || '', animeimage: item.querySelector('img')?.getAttribute('src') || '', animeEpLink: item.querySelector('a')?.getAttribute('href') || '' })); }); await page.close(); // 仅关闭当前页面,保留浏览器实例复用 res.json(animeCard); } catch (error) { console.error('爬取错误:', error); res.status(500).json({ error: "爬取数据时发生错误" }); } });
额外优化建议
- 使用
headless: 'new':新版无头模式比旧版headless: true性能更高,兼容性更好。 - 页面复用:如果请求频率高,可以考虑复用单个页面(通过
page.goto导航到新URL),但要注意清理页面缓存和状态。 - 错误日志:增加详细错误日志,方便排查爬取失败的具体原因。
内容的提问来源于stack exchange,提问作者himalhasan
相关产品推荐
相关产品推荐

