playwright 中应复用同一 browser_context 并发创建多个 page,避免多 context 导致状态隔离;并发控制在 10–20 页内,用 asyncio.gather(return_exceptions=true) 安全执行 goto 等操作,并显式关闭 page/context/browser。

Playwright 中 page 和 context 的并发关系必须理清
Playwright 不允许跨 context 复用 page,但支持单个 browser_context 内并发创建多个 page 实例——这才是安全的多标签页并发基础。直接在同一个 context 里调用多次 context.new_page() 是正确做法;若误用多个 context(比如为每个标签页新建一个),不仅浪费资源,还可能触发浏览器限制或 session 隔离问题。
常见错误现象:TimeoutError: Page closed 或页面间 cookie / localStorage 不共享,往往是因为用了独立 context 而非共享上下文。
- 同一
context下的page共享 cookies、localStorage、viewport 设置等状态 - 并发数建议控制在 10–20 以内,超出易触发 Chromium 的进程/内存限制
- 避免在
page创建后立即goto,应先批量创建再统一 await,减少调度等待
用 asyncio.gather 启动并发 page 任务时要注意异常传播
asyncio.gather 默认遇到任一协程抛异常就取消其余任务,这对多标签页测试很危险:一个页面加载失败,其他本可成功的页面也被中断。必须显式传入 return_exceptions=True,让失败结果以 Exception 对象形式返回,而不是中断整个批次。
示例关键片段:
pages = [context.new_page() for _ in range(5)] await asyncio.gather(*[p.goto(url) for p in pages], return_exceptions=True)
- 每个
page.goto()应单独加超时(如timeout=30000),否则默认 30 秒可能卡死整组 - 不要在
gather中混用不同生命周期操作(如部分含screenshot、部分只goto),容易因耗时差异放大失败影响 - 检查结果时需遍历返回值,用
isinstance(res, Exception)判断是否失败,而非靠 try/except 包裹整个gather
多标签页下定位元素失败?大概率是没处理好 page 生命周期和作用域
并发中常出现 TimeoutError: Element not found,不是 selector 写错,而是目标 page 已被关闭、重定向,或脚本执行时该 page 还未完成 goto。Playwright 的 page 是强绑定对象,不能“复用”或“切换”到别的页面实例上。
- 每个
page必须持有自己的引用,禁止用循环变量临时覆盖(如for page in pages: await page.click(...)中未 await 或未捕获异常,可能导致后续 page 引用失效) - 需要等待页面加载就绪,优先用
page.wait_for_load_state("networkidle")而非固定sleep - 若需跨页面交互(如 A 页点击打开新页 B),必须用
page.expect_popup()或context.wait_for_event("page")拿到新page实例,不能假设context.pages[-1]就是它
资源清理不彻底会导致端口占用、内存泄漏甚至 CI 失败
并发结束后,仅调用 browser.close() 不够——如果某个 page 因异常未正常关闭,其底层 WebSocket 连接可能残留,下次运行时报 Connection refused 或 Browser already closed。必须确保每个 page 和 context 显式关闭。
- 推荐用
async with管理browser和context(Playwright 1.40+ 支持),或手动在finally块中按page.close() → context.close() → browser.close()顺序清理 - 不要依赖 GC 自动回收
page,尤其在高并发短生命周期场景下,Python 的引用计数可能滞后 - CI 环境中建议加
playwright install-deps chromium预检,避免因系统缺少字体/库导致页面渲染异常进而阻塞关闭流程
真正麻烦的从来不是开多少页,而是每一页从创建、交互到销毁的完整链路是否可控。稍有遗漏,就会在本地跑通、CI 报错、线上偶发之间反复横跳。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











