如何解决Puppeteer访问重度脚本化网站的加载超时问题?
解决Puppeteer访问重度脚本化网站的超时问题
我明白你现在的困扰——用Puppeteer访问像香港讨论区这种塞满广告脚本、重度依赖JS的网站时,频繁碰到加载超时,调了waitUntil的各种参数也没效果。这些广告脚本一直在后台跑请求,导致networkidle状态永远没法达成,自然会超时。给你几个亲测有效的解决方案:
1. 拦截非必要请求,砍掉加载负担
广告、第三方统计、冗余的图片/视频资源是拖慢页面的核心,直接拦截它们能大幅减少页面需要加载的内容:
async function run() { const browser = await puppeteer.launch({ args: ['--no-sandbox', '--disable-setuid-sandbox'] }); const page = await browser.newPage(); page.setViewport({ width: 1280, height: 2000 }); // 开启请求拦截 await page.setRequestInterception(true); page.on('request', (req) => { // 定义要拦截的资源类型和关键词 const blockedTypes = ['image', 'stylesheet', 'font', 'media']; const blockedKeywords = ['ad', 'analytics', 'doubleclick', 'cdn.ad', 'video']; // 如果是拦截的类型或包含广告关键词,就终止请求 if (blockedTypes.includes(req.resourceType()) || blockedKeywords.some(keyword => req.url().toLowerCase().includes(keyword))) { req.abort(); } else { req.continue(); } }); page.on('load', () => console.log('Page loaded!', page.url())); // 后续的页面跳转和截图逻辑... }
2. 放弃等网络空闲,改用等待核心元素加载
很多广告脚本会一直发请求,networkidle0或networkidle2永远不会触发。不如直接等待页面的核心元素加载完成,同时设置合理的超时兜底:
// 替换原来的page.goto逻辑,比如访问论坛列表页: await page.goto('http://www.discuss.com.hk/forumdisplay.php?fid=215', { timeout: 60000, // 设置60秒超时,可根据情况调整 }); // 等待论坛帖子列表的核心容器加载(这里的选择器需要你根据页面实际情况调整) await page.waitForSelector('#threadlisttableid', { timeout: 30000 }); await page.screenshot({ path: 'dis2.png' });
这样只要核心内容加载完毕,就可以继续操作,不用管后台的广告脚本瞎折腾。
3. 优化浏览器启动参数,减少后台开销
给Puppeteer的浏览器加一些优化参数,禁用不必要的功能,降低资源占用:
const browser = await puppeteer.launch({ args: [ '--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage', // 避免容器或低内存环境下的内存不足问题 '--disable-gpu', // 禁用GPU加速,无头模式下不需要 '--disable-service-worker', // 禁用Service Worker,减少后台持续请求 '--blink-settings=imagesEnabled=false', // 禁用图片加载,进一步提速 '--disable-ads' // 尝试内置的广告拦截(部分Chromium版本支持) ], headless: 'new', // 使用新版无头模式,稳定性更好 defaultViewport: { width: 1280, height: 2000 } });
4. 避免连续快速跳转,给页面留缓冲时间
不要一口气连续跳转多个页面,每次操作后给页面留一点稳定时间,比如加个短暂延迟或者等待domcontentloaded:
// 首页加载后,先等DOM加载完成再截图 await page.goto('https://www.discuss.com.hk'); await page.waitForNavigation({ waitUntil: 'domcontentloaded' }); await page.screenshot({ path: 'dis1.png' }); // 跳转前加1秒延迟,让当前页面状态稳定 await page.waitForTimeout(1000); await page.goto('http://www.discuss.com.hk/forumdisplay.php?fid=215'); await page.waitForSelector('#threadlisttableid'); await page.screenshot({ path: 'dis2.png' });
你的原始代码:
async function run() { const browser = await puppeteer.launch({ args: ['--no-sandbox', '--disable-setuid-sandbox'] }); const page = await browser.newPage(); page.setViewport({ width: 1280, height: 2000 }); page.on('load', () => console.log('Page loaded!', page.url())); //Goto website home page await page.goto('https://www.discuss.com.hk'); await page.screenshot({ path: 'dis1.png' }); //goto another page in the website await page.goto('http://www.discuss.com.hk/forumdisplay.php?fid=215'); await page.screenshot({ path: 'dis2.png' }); //Goto another page in the website await page.goto('http://www.discuss.com.hk/forumdisplay.php?fid=1192'); await page.screenshot({ path: 'dis3.png' }); //Goto another page in the website await page.goto('http://www.discuss.com.hk/viewthread.php?tid=27173245&extra=page%3D1'); await page.screenshot({ path: 'dis4.png' }); await browser.close(); return 'done!'; }
内容的提问来源于stack exchange,提问作者skyblue
相关产品推荐
相关产品推荐

