Playwright-Python报错‘Navigation failed because page was closed!’的排查
错误原因分析
- 单页面复用冲突:循环中复用同一个
page对象连续调用goto,前一次导航的资源未完全释放、页面状态未重置时发起新导航,会导致页面上下文异常,触发页面关闭。 - 反爬机制触发:Google会检测自动化工具访问,短时间内频繁请求会被判定为机器人,直接关闭当前页面,导致后续
goto操作报错。 - 未做状态校验与异常处理:未针对页面加载状态做校验,也没有捕获异常的逻辑,一旦页面因意外关闭,后续操作直接抛出错误。
正确实现方式
方案1:每个URL创建独立页面(推荐)
为每个请求创建新页面,彻底避免单页面状态冲突,同时添加反爬规避配置:
from playwright.sync_api import sync_playwright urls = ['http://www.google.co.uk'] * 30 with sync_playwright() as p: # 启动浏览器时添加反爬规避参数 browser = p.chromium.launch( headless=True, args=[ "--disable-blink-features=AutomationControlled", "--no-sandbox", "--disable-setuid-sandbox" ] ) # 创建独立浏览器上下文,隔离会话状态 context = browser.new_context( user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36" ) for i, url in enumerate(urls): print(i, url) page = context.new_page() try: # 等待页面加载完成,设置超时时间 response = page.goto(url, timeout=30000, wait_until="networkidle") if not response.ok: print(f"请求失败,状态码:{response.status}") continue # 等待目标元素加载后再查询 page.wait_for_selector('h1', timeout=10000) headers = page.query_selector_all('h1') print(f"找到{len(headers)}个h1标签") except Exception as e: print(f"处理URL {url}时出错:{str(e)}") finally: # 用完即关闭页面,释放资源 page.close() # 依次关闭上下文和浏览器 context.close() browser.close()
方案2:复用单页面但添加状态重置与异常处理
如果坚持复用单页面,需确保每次导航前后重置状态,并捕获异常:
from playwright.sync_api import sync_playwright urls = ['http://www.google.co.uk'] * 30 with sync_playwright() as p: browser = p.chromium.launch( headless=True, args=["--disable-blink-features=AutomationControlled"] ) page = browser.new_page(user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36") for i, url in enumerate(urls): print(i, url) try: # 导航前确保页面处于就绪状态 page.wait_for_load_state("domcontentloaded") # 发起导航并等待网络空闲 page.goto(url, wait_until="networkidle", timeout=30000) page.wait_for_selector('h1', timeout=10000) headers = page.query_selector_all('h1') print(f"找到{len(headers)}个h1标签") # 重置页面状态,避免残留缓存影响下一次请求 page.reload(wait_until="networkidle") except Exception as e: print(f"处理URL {url}时出错:{str(e)}") # 出错后销毁当前页面,重新创建新页面 page.close() page = browser.new_page(user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36") page.close() browser.close()
关键优化点
- 反爬规避:通过
--disable-blink-features=AutomationControlled隐藏自动化标识,自定义user_agent模拟真实浏览器请求。 - 异常隔离:对每个请求单独捕获异常,出错时及时销毁异常页面,避免影响后续任务。
- 状态管控:使用独立页面/上下文隔离请求状态,或复用页面时强制重置状态,避免跨请求污染。
- 等待策略:使用
wait_until="networkidle"和wait_for_selector确保页面元素加载完成后再执行查询操作。
内容的提问来源于stack exchange,提问作者Richard
相关产品推荐
相关产品推荐

