Puppeteer导航超时问题求助:已调超时参数仍报错
解决Puppeteer访问重型视频网站的超时问题
问题分析
你遇到的90000ms超时错误,并非来自page.goto()的设置,而是由以下核心问题导致:
- 浏览器与Puppeteer通信的超时参数未配置,默认值可能不足以支撑重型网站的加载
- 代码中存在DOM元素获取的错误:
page.evaluate()无法直接返回DOM元素句柄,后续的hover()、click()调用会失效,导致代码卡住触发超时 waitForSelector()未设置自定义超时,默认超时可能无法覆盖重型页面的元素加载时长
解决方案
1. 配置浏览器级别的超时参数
在puppeteer.launch()中显式设置启动超时和通信超时,避免浏览器初始化或连接时中断:
browser = await puppeteer.launch({ headless: false, timeout: 690000, // 浏览器启动超时时间 protocolTimeout: 690000, // Puppeteer与浏览器通信的超时时间 });
2. 给所有等待操作设置超时
给waitForSelector()设置与导航一致的长超时,避免默认30秒超时触发:
await page.waitForSelector("custom-gallery", { timeout: 690000 });
3. 拦截非必要资源提升加载效率
重型视频网站的视频、图片等静态资源会大幅拖慢加载速度,通过请求拦截只保留核心资源:
const page = await browser.newPage(); // 启用请求拦截 await page.setRequestInterception(true); page.on("request", (req) => { // 拦截视频、图片、字体等非必要资源 const blockedTypes = ["image", "video", "font"]; if (blockedTypes.includes(req.resourceType())) { req.abort(); } else { req.continue(); } });
4. 修正DOM元素获取逻辑
page.evaluate()无法直接返回可操作的DOM元素句柄,需通过元素句柄API获取Shadow DOM内的视频元素:
// 正确获取custom-gallery的元素句柄 const customGalleryHandle = await page.$("custom-gallery"); // 获取Shadow Root的句柄 const shadowRootHandle = await customGalleryHandle.evaluateHandle(el => el.shadowRoot); // 从Shadow Root中获取所有video元素句柄 const videoTags = await shadowRootHandle.$$("video");
5. 调整导航等待策略
如果domcontentloaded后页面仍有大量资源加载,可切换到更宽松的网络空闲等待策略:
await page.goto("https://www.crcmedia.com/", { timeout: 690000, waitUntil: "networkidle2", // 当网络连接数低于2个持续500ms时视为加载完成 });
修正后的完整代码示例
const express = require("express"); const app = express(); const puppeteer = require("puppeteer"); let timer; async function checkSite() { let browser; try { console.log("TEST SCRIPT STARTED..."); browser = await puppeteer.launch({ headless: false, timeout: 690000, protocolTimeout: 690000, }); const page = await browser.newPage(); await page.setDefaultNavigationTimeout(0); // 拦截非必要资源,提升加载速度 await page.setRequestInterception(true); page.on("request", (req) => { const blockedTypes = ["image", "video", "font"]; if (blockedTypes.includes(req.resourceType())) { req.abort(); } else { req.continue(); } }); await page.goto("https://www.crcmedia.com/", { timeout: 690000, waitUntil: "networkidle2", }); await page.waitForSelector("custom-gallery", { timeout: 690000 }); // 正确获取Shadow Root内的视频元素句柄 const customGalleryHandle = await page.$("custom-gallery"); const shadowRootHandle = await customGalleryHandle.evaluateHandle(el => el.shadowRoot); const videoTags = await shadowRootHandle.$$("video"); console.log("VIDEO TAGS COUNT", videoTags.length); for (let i = 0; i < videoTags.length; i++) { console.log("PROCESSING VIDEO", i + 1); const video = videoTags[i]; await video.hover(); // 检查当前视频是否处于hover状态 const isHovered = await video.evaluate(el => el.matches(":hover")); await video.click(); // 检查当前视频是否播放 const isClicked = await video.evaluate(el => !el.paused); if (isHovered && isClicked) { console.log(`Video ${i + 1} interactions working properly`); } else { console.log(`Video ${i + 1} interactions not working properly`); } } } catch (error) { console.error("CAUGHT AN ERROR", error); } if (browser) { await browser.close(); } } app.get("/", (req, res) => { res.send("Site monitoring is running"); checkSite().catch((error) => console.error("ERROR RUNNING CHECKSITE", error)); }); app.listen(3000, () => { console.log("Server is running on port 3000"); checkSite().catch((error) => console.error("ERROR RUNNING CHECKSITE", error)); });
内容的提问来源于stack exchange,提问作者Jacob Cooper
相关产品推荐
相关产品推荐

