You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Pyppeteer设置1000ms超时后page.goto仍无限挂起问题排查及解决方案求助

为什么Pyppeteer访问特定网站会无限挂起(即使设置了超时)?

这个问题我之前踩过类似的坑,尤其是对付那些做了反爬优化或者持续保持网络连接的网站,你的情况大概率和这几个核心原因有关:

1. networkidle0 等待条件永远无法满足

你在page.goto()里用了waitUntil: 'networkidle0',这个规则要求500毫秒内完全没有任何网络请求才会判定导航完成。但像ig.com.br这类网站,可能会持续发送心跳请求、WebSocket连接或者SSE(服务器推送事件)来维持会话——这些高频的小请求会一直触发网络活动,让networkidle0的条件永远达不到。

而你设置的timeout:1000其实只作用于初始导航阶段(比如DNS解析、TCP握手、服务器返回首屏内容),后续等待网络空闲的阶段并不会被这个timeout覆盖,这就直接导致程序无限挂起在等待逻辑里。

2. 网站反爬机制针对headless浏览器做了拦截

很多网站会检测访问来源是否是headless模式的浏览器(Pyppeteer默认的headless模式有不少特征可以被识别),一旦检测到,可能会故意卡住页面渲染流程,或者不返回完整的页面资源,让Pyppeteer一直处于等待页面就绪的状态。

3. Asyncio层面的潜在阻塞(相对少见)

虽然直接关联asyncio的概率不高,但如果页面的JS执行出现死循环,或者Pyppeteer内部的事件循环被异常阻塞,也可能导致整个任务无法终止。不过这种情况更多是极端案例,前两个原因才是主流问题。


解决方法:确保20秒内完成或抛出错误

方法1:换用更宽松的waitUntil条件

把networkidle0换成networkidle2(允许500毫秒内最多2个网络请求)或者domcontentloaded(DOM结构加载完成就停止等待),避开持续心跳请求的干扰:

await page.goto(url, {'waitUntil': 'domcontentloaded','timeout': 20000})

方法2:用asyncio.wait_for强制全局超时

不管Pyppeteer内部的timeout逻辑,直接用asyncio的超时包裹整个导航操作,确保即使内部逻辑卡住,也能在指定时间内抛出错误终止任务:

async def test(): 
    url = 'https://ig.com.br/' 
    browser = await launch(headless=True) 
    page = await browser.newPage() 
    page.setDefaultNavigationTimeout(20000) 
    await page.setUserAgent(fake_useragent.UserAgent().random) 
    try:
        # 强制20秒超时,覆盖所有等待逻辑
        await asyncio.wait_for(
            page.goto(url, {'waitUntil': 'networkidle0'}),
            timeout=20.0
        )
    except asyncio.TimeoutError:
        print("请求超时,强制终止")
    finally:
        await browser.close() 
asyncio.run(test())

方法3:优化headless浏览器配置,模拟真实环境

给浏览器添加一些参数,减少被反爬识别的概率:

browser = await launch(
    headless=True,
    args=[
        '--no-sandbox',
        '--disable-setuid-sandbox',
        '--disable-dev-shm-usage',
        '--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36'
    ]
)

(也可以固定使用主流UA,避免fake_useragent随机到被标记的异常UA)

方法4:提前处理页面弹窗

有些网站会在加载时弹出alert或确认框,headless模式下这些弹窗不会显示,但会卡住页面渲染。可以提前监听弹窗事件并自动关闭:

page.on('dialog', lambda dialog: asyncio.create_task(dialog.accept()))

内容的提问来源于stack exchange,提问作者Milano

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 19:08:13