Playwright跨函数使用Page对象报错Event loop is closed,求解决方案
问题原因
你的报错根源在于sync_playwright()的with语句特性:当代码退出with块时,Playwright的上下文会被自动销毁,事件循环随之关闭。此时你返回的Browser和Page对象已经失去了有效的运行环境,后续调用自然会触发"Event loop is closed! Is Playwright already stopped?"错误。
解决方案
要在不同函数间传递并使用Page对象,需要保证Playwright上下文的生命周期覆盖所有对象使用的流程,以下是两种可行方案:
方案1:将Playwright上下文管理移到外层函数
把sync_playwright()的with块放到调用链的最外层,让所有依赖Playwright对象的操作都在上下文有效期内执行:
from playwright.sync_api import sync_playwright from playwright.sync_api._generated import Locator, Browser, Page from typeguard import typechecked @typechecked def initialise_playwright_browsercontroller( p, # 传入已启动的Playwright上下文 *, start_url: str, ) -> tuple[Browser, Page]: """创建浏览器、打开页面并导航到指定URL""" for browser_type in [p.chromium, p.firefox, p.webkit]: if browser_type.name == "firefox": # 简化冗余的条件判断 browser = browser_type.launch() page = browser.new_page() page.goto(start_url) return browser, page raise ValueError("Error: Could not find browser.") @typechecked def do_something_on_webpage(page: Page) -> None: """在页面上执行操作""" print(f"page url = {page.url}") sign_in_button: Locator = page.locator("text=Sign in") # 修正选择器写法,添加text=前缀匹配文本 sign_in_button.click() print("Done.") def main(): start_url: str = "https://github.com" # 将Playwright上下文管理放在最外层,覆盖所有操作流程 with sync_playwright() as p: browser, page = initialise_playwright_browsercontroller(p, start_url=start_url) try: do_something_on_webpage(page) finally: browser.close() # 手动关闭浏览器 if __name__ == "__main__": main()
方案2:手动管理Playwright生命周期(不使用with)
如果必须在内部函数初始化Playwright,可以手动调用start()和stop()方法,确保在使用完对象后再终止上下文:
from playwright.sync_api import sync_playwright from playwright.sync_api._generated import Locator, Browser, Page from typeguard import typechecked @typechecked def initialise_playwright_browsercontroller( *, start_url: str, ) -> tuple[Browser, Page, sync_playwright]: """创建浏览器、打开页面并导航到指定URL,返回上下文用于后续终止""" p = sync_playwright().start() # 手动启动Playwright try: for browser_type in [p.chromium, p.firefox, p.webkit]: if browser_type.name == "firefox": browser = browser_type.launch() page = browser.new_page() page.goto(start_url) return browser, page, p raise ValueError("Error: Could not find browser.") except Exception: p.stop() raise @typechecked def do_something_on_webpage() -> None: start_url: str = "https://github.com" browser, page, p = initialise_playwright_browsercontroller(start_url=start_url) try: print(f"page url = {page.url}") sign_in_button: Locator = page.locator("text=Sign in") sign_in_button.click() print("Done.") finally: browser.close() p.stop() # 手动终止Playwright上下文 do_something_on_webpage()
额外注意点
- 原代码中浏览器选择的条件逻辑冗余:
browser_type.name != "webkit" and browser_type.name == "firefox"直接写成browser_type.name == "firefox"即可 - Locator选择器写法错误:匹配文本需要添加
text=前缀,否则会被当作CSS选择器处理,无法找到目标元素
内容的提问来源于stack exchange,提问作者a.t.
相关产品推荐
相关产品推荐

