Puppeteer中'TimeoutError is not defined'及后续类型错误排查求助
Puppeteer中'TimeoutError is not defined'及后续类型错误排查求助
问题分析
从你的代码和报错来看,核心问题有两个:
TimeoutError无全局定义:Puppeteer的TimeoutError并不是全局可用的,必须从你导入的puppeteer实例的errors属性中获取,直接使用会提示未定义。- 变量作用域导致
puppeteer未初始化:你在代码顶部声明了let puppeteer;,但实际在main函数里才执行require赋值,而scrape函数在main外部,当scrape执行时puppeteer变量还是undefined,所以访问puppeteer.errors就会触发Cannot read properties of undefined的错误。
修复方案
我们可以通过调整导入位置、修正作用域,以及正确引用错误类来解决问题:
1. 提前正确导入Puppeteer
把Puppeteer的require移到代码最顶部,确保在所有函数定义前就完成导入,这样所有函数都能访问到正确的puppeteer实例:
// 提前导入依赖,确保作用域覆盖所有使用的函数 const puppeteer = require('puppeteer-extra'); const stealthPlugin = require('puppeteer-extra-plugin-stealth'); puppeteer.use(stealthPlugin()); // **************************************** constants // all error codes that we pass back const ERROR_CODE_URL_INVALID = 1002; const ERROR_INTERNAL_SERVER_ERROR = 1003; const ERROR_TIMEOUT = 1004;
2. 正确引用TimeoutError
在catch块中,使用puppeteer.errors.TimeoutError来判断错误类型,此时puppeteer已经完成初始化,不会再出现未定义的问题:
catch (error) { // 现在可以正常访问puppeteer.errors下的TimeoutError if (error instanceof puppeteer.errors.TimeoutError) { errorContent = ERROR_TIMEOUT; } else { throw error; } }
3. 额外的小细节修复
原代码里还有两个容易被忽略的小问题,一起修复可以避免更多意外:
throw response.text;要改成throw await response.text();,因为response.text()是异步函数,直接抛函数引用没有实际错误信息。page.mouse.click(1, 1);是异步操作,需要加上await,否则会在点击未完成时就执行后续的evaluate,可能导致弹窗未关闭就爬取内容。
完整修复后的SSCCE示例
// 提前导入依赖,确保作用域正确 const puppeteer = require('puppeteer-extra'); const stealthPlugin = require('puppeteer-extra-plugin-stealth'); puppeteer.use(stealthPlugin()); // **************************************** constants // all error codes that we pass back const ERROR_CODE_URL_INVALID = 1002; const ERROR_INTERNAL_SERVER_ERROR = 1003; const ERROR_TIMEOUT = 1004; // **************************************** scrape const scrape = async (page, url) => { let response = null; let errorContent = null; try { // 故意设置短超时来测试问题 response = await page.goto(url, { waitUntil: 'load', timeout: 100 }); if (!response) { response = await page.waitForResponse(() => true, { timeout: 100 }); } if (response.status() === 200) { // 成功,无需额外操作 } else if (response.status() === 404) { errorContent = ERROR_CODE_URL_INVALID; } else if (response.status() === 500) { errorContent = ERROR_INTERNAL_SERVER_ERROR; } else { // 抛出实际的响应文本作为错误信息 throw await response.text(); } } catch (error) { // 正确引用Puppeteer的TimeoutError if (error instanceof puppeteer.errors.TimeoutError) { errorContent = ERROR_TIMEOUT; } else { throw error; } } if (errorContent !== null) { throw errorContent; } // 等待点击操作完成 await page.mouse.click(1, 1); // 获取页面HTML const data = await page.evaluate(() => document.querySelector('*').outerHTML); return data; }; // **************************************** main let browser; (async function main() { browser = await puppeteer.launch({ headless: false }); const [page] = await browser.pages(); try { let s = await scrape(page, "https://www.scrapethissite.com/pages/"); console.log(s); } catch (err) { console.log("爬取错误:", err); } })() .catch(err => console.log("全局错误:", err)) .finally(() => browser?.close());
内容来源于stack exchange
相关产品推荐
相关产品推荐

