pyppeteer.errors.TimeoutError: Navigation Timeout Exceeded: 30000 ms exceeded.

本文介绍了在使用Pyppeteer爬虫时遇到的NavigationTimeoutExceeded错误,分析了该问题的原因是执行速度过快导致页面未完全加载。为解决这个问题,提出了通过引入随机延迟函数sleep_time()来确保页面充分加载的方法,从而避免TimeoutError。这种方法对于优化爬虫性能和提高爬取成功率具有实际意义。

使用pyppeteer爬虫时,使用函数

page = await browser.newPage()
await page.goto(url)

时,发现页面已经跳转到了链接所在位置,但是还是报错:
pyppeteer.errors.TimeoutError: Navigation Timeout Exceeded: 30000 ms exceeded.

原因在于,执行速度太快,没有反应过来,再跳转之前增加延时可以解决

from asyncio import sleep
import random

def sleep_time():
    return 1+random.random() * 2
    
page2 = await browser.newPage()
await sleep(sleep_time())
await page2.goto(detaillink)
Traceback (most recent call last): File "C:\Users\chaoguog\PycharmProjects\PythonProject\auto_input\auto_inputer.py", line 54, in <module> inputer.run() ~~~~~~~~~~~^^ File "C:\Users\chaoguog\PycharmProjects\PythonProject\auto_input\auto_inputer.py", line 30, in run income_menu.wait_for(state="visible", timeout=30000) ~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\chaoguog\PycharmProjects\PythonProject\.venv\Lib\site-packages\playwright\sync_api\_generated.py", line 17956, in wait_for self._sync(self._impl_obj.wait_for(timeout=timeout, state=state)) ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\chaoguog\PycharmProjects\PythonProject\.venv\Lib\site-packages\playwright\_impl\_sync_base.py", line 115, in _sync return task.result() ~~~~~~~~~~~^^ File "C:\Users\chaoguog\PycharmProjects\PythonProject\.venv\Lib\site-packages\playwright\_impl\_locator.py", line 692, in wait_for await self._frame.wait_for_selector( self._selector, strict=True, timeout=timeout, state=state ) File "C:\Users\chaoguog\PycharmProjects\PythonProject\.venv\Lib\site-packages\playwright\_impl\_frame.py", line 369, in wait_for_selector await self._channel.send( "waitForSelector", self._timeout, locals_to_params(locals()) ) File "C:\Users\chaoguog\PycharmProjects\PythonProject\.venv\Lib\site-packages\playwright\_impl\_connection.py", line 69, in send return await self._connection.wrap_api_call( ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...<3 lines>... ) ^ File "C:\Users\chaoguog\PycharmProjects\PythonProject\.venv\Lib\site-packages\playwright\_impl\_connection.py", line 558, in wrap_api_call raise rewrite_error(error, f"{parsed_st['apiName']}: {error}") from None playwright._impl._errors.TimeoutError: Locator.wait_for: Timeout 30000ms exceeded. Call log: - waiting for locator("li#z509 > a.dropdown-toggle:has-text('收入管理')") to be visible - waiting for" http://192.168.200.201:8888/KT/main/index" navigation to finish... - navigated to "http://192.168.200.201:8888/KT/main/index" 59 × locator resolved to hidden <a class="dropdown-toggle">…</a>
08-29
<think> 我们遇到了一个Playwright中等待事件"page"超时的错误:`TimeoutError: Timeout 30000ms exceeded while waiting for event "page"`。这个错误通常发生在等待新页面(例如弹窗或新标签页)打开时,但页面没有在指定的30秒内打开。 结合引用[1]和[2],我们得知超时错误通常有几种原因: 1. 页面加载时间确实很长,超过了默认的30秒。 2. 页面加载过程中出现阻塞(如网络问题)。 3. 目标事件根本没有触发(例如,点击操作没有成功打开新页面)。 ### 解决方案 #### 1. 增加超时时间(临时解决方案) 在等待事件的代码中,我们可以设置更长的超时时间。例如,将超时时间设置为60秒(60000毫秒): ```python # 原始代码 new_page_promise = context.wait_for_event("page", timeout=60000) # 60秒超时 ``` #### 2. 检查事件触发条件(根本解决方案) - **确认点击操作是否成功**:确保点击“QQ登录”按钮的操作确实执行了,并且会打开一个新页面。我们可以通过截图或检查页面状态来确认。 - **等待按钮可点击**:在点击之前,确保按钮已经可点击,添加等待条件。 ```python # 等待按钮出现并可点击 await page.wait_for_selector("text=QQ登录", state="visible", timeout=30000) await page.get_by_text("QQ登录").click() ``` #### 3. 使用`expect_popup`上下文管理器(推荐) Playwright推荐使用上下文管理器来等待新页面,这样代码更清晰,并且可以设置超时时间: ```python # 使用expect_popup async with page.expect_popup(timeout=60000) as popup_info: await page.get_by_text("QQ登录").click() new_page = await popup_info.value ``` #### 4. 检查页面是否在iframe中(常见原因) 在B站登录场景中,登录框通常位于iframe内。如果“QQ登录”按钮位于iframe中,我们需要先定位到iframe,然后在iframe内操作: ```python # 等待iframe加载并定位 frame = page.frame_locator("iframe[name=login]") # 在iframe内点击QQ登录 async with page.expect_popup(timeout=60000) as popup_info: await frame.locator("text=QQ登录").click() new_page = await popup_info.value ``` #### 5. 网络问题处理 如果网络较慢,可以增加全局超时设置,或者在`page.goto`时增加超时时间(引用[2]): ```python await page.goto(url, timeout=60000) # 设置60秒超时 ``` ### 完整代码建议 以下是整合以上建议的修改后代码: ```python import asyncio from playwright.async_api import async_playwright async def async_click_btn(): async with async_playwright() as p: browser = await p.chromium.launch( headless=False, channel="msedge") context = await browser.new_context() page = await context.new_page() # 增加页面加载超时时间 await page.goto( "https://www.bilibili.com/video/BV1J1ycB2EPv/?spm_id_from=333.1387.homepage.video_card.click&vd_source=669102571eb2e49655fc1d352a8bf358", timeout=60000 # 60秒超时 ) await page.wait_for_load_state("networkidle") # 点击登录按钮 - 使用更可靠的定位方式 # 注意:B站可能有多个登录按钮,我们选择第二个(.nth(1))可能是正确的,但建议使用更稳定的选择器 # 例如:使用class选择器 # 等待登录按钮出现 await page.wait_for_selector('.header-login-entry', state='visible') await page.locator('.header-login-entry').click() # 等待登录弹窗出现,并确保QQ登录按钮在iframe中 # 注意:B站的登录弹窗是一个iframe,我们需要先定位到这个iframe await page.wait_for_selector('iframe[name=login]', state='attached') frame = page.frame_locator('iframe[name=login]') # 使用上下文管理器等待新页面弹出(QQ登录) async with page.expect_popup(timeout=60000) as popup_info: # 设置60秒超时 # 在iframe内点击QQ登录 await frame.locator('text=QQ登录').click() new_page = await popup_info.value await new_page.wait_for_load_state("networkidle") # 在QQ登录页面上点击头像(假设“概念神”是QQ昵称) # 注意:这里可能需要等待QQ登录页面的特定元素出现 await new_page.wait_for_selector('text=概念神', state='visible') await new_page.get_by_text('概念神').click() # 保持页面打开进行观察 while True: await asyncio.sleep(10000) await browser.close() if __name__ == "__main__": asyncio.run(async_click_btn()) ``` ### 注意事项 1. **iframe处理**:B站的登录框通常嵌套在iframe中,所以必须通过`frame_locator`操作内部元素。 2. **等待策略**:使用`wait_for_selector`确保元素可见可操作,避免因元素未准备好而点击失败。 3. **超时设置**:适当增加超时时间,特别是在网络环境不佳或页面加载较慢时。 4. **调试**:如果问题依旧,可以添加截图功能,在关键步骤截图,帮助定位问题: ```python await page.screenshot(path="screenshot.png") ``` ### 相关问题 1. 如何调试Playwright脚本? 2. Playwright如何处理页面中的iframe? 3. 如何提高Playwright脚本的稳定性? [^1]: 超时错误可能由多种原因引起,包括网络延迟、页面加载缓慢等 [^2]: 可以通过设置`timeout:0`禁用超时,但不推荐,因为可能导致脚本永久挂起 [^3]: 大文件操作时可能需要设置更长的超时时间 </think> ## 解决 Playwright 中的 `TimeoutError: Timeout 30000ms exceeded while waiting for event "page"` 错误 这个错误发生在 Playwright 等待新页面(标签页或弹窗)打开时超时。以下是系统化的解决方案: ### 1. 增加超时时间(推荐) ```python # 增加等待新页面的超时时间(60秒) new_page_promise = context.wait_for_event("page", timeout=60000) await page.get_by_text("QQ登录").click() new_page = await new_page_promise ``` ### 2. 确保页面事件触发 ```python # 添加等待确保元素可点击 await page.wait_for_selector('text=QQ登录', state="visible", timeout=30000) with context.expect_page(timeout=60000) as new_page_info: await page.get_by_text("QQ登录").click() new_page = await new_page_info.value ``` ### 3. 检查页面加载逻辑(关键) ```python # 确保正确等待页面加载完成 await page.goto(url, wait_until="domcontentloaded", timeout=60000) # 使用更可靠的网络状态检测 await page.wait_for_load_state("domcontentloaded") await page.wait_for_load_state("networkidle", timeout=15000) ``` ### 4. 处理可能的 iframe ```python # B站登录常使用iframe,需特殊处理 login_frame = page.frame_locator('iframe[name="login"]') await login_frame.locator('text=QQ登录').wait_for(state="visible") with context.expect_page(timeout=60000) as new_page_info: await login_frame.locator('text=QQ登录').click() new_page = await new_page_info.value ``` ### 5. 完整优化方案 ```python async def login_with_retry(): async with async_playwright() as p: browser = await p.chromium.launch(headless=False, channel="msedge") context = await browser.new_context() try: page = await context.new_page() # 增加超时和加载策略 await page.goto("https://www.bilibili.com", timeout=60000, wait_until="domcontentloaded") # 确保登录按钮可点击 await page.locator(".header-login-entry").wait_for(timeout=30000) await page.click(".header-login-entry") # 处理iframe中的QQ登录 frame = page.frame_locator('iframe[name="login"]') await frame.locator("text=QQ登录").wait_for(timeout=30000) # 使用上下文管理器等待新页面 async with context.expect_page(timeout=60000) as new_page_info: await frame.locator("text=QQ登录").click() new_page = await new_page_info.value await new_page.wait_for_load_state("networkidle") # 后续操作... return True except TimeoutError as e: print(f"操作超时: {e}") await page.screenshot(path="timeout_error.png") return False finally: await browser.close() ``` ### 常见原因分析 1. **页面加载缓慢**:网络延迟或资源加载慢导致超时 2. **元素定位变化**:页面更新导致选择器失效 3. **iframe嵌套**:目标元素在未检测到的iframe中 4. **浏览器设置问题**:反自动化检测机制触发 5. **事件未触发**:点击操作未实际执行 ### 最佳实践建议 1. **使用上下文管理器**:`async with context.expect_page()`更可靠 2. **分层等待**:先等元素可见,再等可点击状态 3. **添加重试机制**:对关键操作添加自动重试 4. **启用调试日志**:启动时添加`DEBUG=pw:api`环境变量 5. **网络模拟**:测试不同网络环境下的表现 > **关键提示**:B站等网站常使用动态加载技术,建议使用`wait_for_selector`配合`state='attached'`检测元素存在性,而非依赖固定等待时间[^1]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值