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

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()

额外注意点

  1. 原代码中浏览器选择的条件逻辑冗余:browser_type.name != "webkit" and browser_type.name == "firefox" 直接写成browser_type.name == "firefox"即可
  2. Locator选择器写法错误:匹配文本需要添加text=前缀,否则会被当作CSS选择器处理,无法找到目标元素

内容的提问来源于stack exchange,提问作者a.t.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 16:57:40