Pyppeteer无法捕获4xx/5xx响应及JS、AJAX错误的技术问询
问题描述
使用Pyppeteer抓取指定网站的所有控制台消息时,仅能捕获状态码为200的响应,无法获取网站实际存在的4xx、5xx响应,也无法提取JS及AJAX错误。当前代码及运行输出如下:
当前代码
import asyncio from pyppeteer import launch async def on_console(msg): print('PAGE LOG:', msg.text) async def on_page_error(error): print(error) async def on_response(response): print(f"{response.status} {response.url}") async def on_request_failed(request): failure = request.failure() if failure: print(failure.get('errorText', 'Unknown error'), request.url) else: print('Request failed without error information', request.url) async def main(): browser = await launch() page = await browser.newPage() page.on('console', lambda msg: asyncio.ensure_future(on_console(msg))) page.on('pageerror', lambda error: asyncio.ensure_future(on_page_error(error))) page.on('response', lambda response: asyncio.ensure_future(on_response(response))) page.on('requestfailed', lambda request: asyncio.ensure_future(on_request_failed(request))) try: await page.goto('https://toursthingstodo.com') await page.waitFor(5000) except Exception as e: print(f"An error occurred: {e}") await browser.close() asyncio.run(main())
当前运行输出
200 https://toursthingstodo.com/ 200 https://toursthingstodo.com/_next/static/css/cfeb154ff119552e.css 200 https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-3751418851639209
网站实际存在的错误(翻译自截图)
- 资源加载错误:
GET https://toursthingstodo.com/_next/static/media/logo.8e5b40b0.png 404 (未找到) - JS运行错误:
未捕获的引用错误:$ is not defined - AJAX请求错误:
POST https://toursthingstodo.com/api/data 500 (内部服务器错误)
解决方案
一、使用Pyppeteer实现完整错误捕获
现有代码遗漏了部分事件监听,且对response事件的处理不够全面,调整后可以捕获所有目标错误:
改进后的代码
import asyncio from pyppeteer import launch async def on_console(msg): # 区分控制台消息类型:错误、警告、日志等 msg_type = msg.type if msg_type == 'error': print(f'[控制台错误] {msg.text}') elif msg_type == 'warning': print(f'[控制台警告] {msg.text}') else: print(f'[控制台日志] {msg.text}') async def on_page_error(error): print(f'[页面全局错误] {error}') async def on_response(response): # 捕获所有响应,包括4xx、5xx状态码 status = response.status if 400 <= status < 600: print(f'[异常响应] {status} {response.url}') else: print(f'[正常响应] {status} {response.url}') async def on_request_failed(request): failure = request.failure() if failure: print(f'[请求失败] {failure.get("errorText", "未知错误")} {request.url}') else: print(f'[请求失败] 无错误信息 {request.url}') async def main(): # 启动浏览器时开启日志,方便排查网络问题 browser = await launch(headless=False, args=['--disable-web-security', '--enable-logging']) page = await browser.newPage() # 监听所有关键事件 page.on('console', lambda msg: asyncio.ensure_future(on_console(msg))) page.on('pageerror', lambda error: asyncio.ensure_future(on_page_error(error))) page.on('response', lambda response: asyncio.ensure_future(on_response(response))) page.on('requestfailed', lambda request: asyncio.ensure_future(on_request_failed(request))) # 启用请求拦截,确保捕获所有AJAX请求 await page.setRequestInterception(True) async def intercept_request(request): # 放行所有请求 await request.continue_() page.on('request', lambda req: asyncio.ensure_future(intercept_request(req))) try: # 等待页面完全加载,包括所有资源和AJAX请求 await page.goto('https://toursthingstodo.com', waitUntil='networkidle2', timeout=60000) await asyncio.sleep(5) except Exception as e: print(f'[主流程错误] {e}') await browser.close() asyncio.run(main())
关键改进点
- 完善
response事件处理:主动判断状态码是否为4xx/5xx,这类响应不会触发requestfailed事件,需要单独处理 - 启用请求拦截:确保捕获所有AJAX请求,包括动态发起的异步请求
- 细化控制台消息类型:区分错误、警告和普通日志,精准定位问题
- 调整页面加载策略:使用
waitUntil='networkidle2'等待网络空闲,确保所有资源加载完成
二、其他可选Python库
如果Pyppeteer使用起来有门槛,还可以考虑以下工具:
- Playwright:Pyppeteer的替代方案,API更简洁,支持多浏览器(Chrome、Firefox、Safari),内置更完善的错误捕获机制
- Selenium:老牌自动化测试工具,结合浏览器驱动可以捕获控制台错误和网络请求,适合复杂场景
- requests + BeautifulSoup + aiohttp:如果不需要渲染JS,仅需捕获AJAX错误,可以直接用HTTP请求库模拟,但无法处理前端JS运行错误
内容的提问来源于stack exchange,提问作者Ramiz Ali
相关产品推荐
相关产品推荐

