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

Streamlit多按钮共用Playwright Page对象及截图按钮阻塞问题的解决方法

Streamlit多按钮共用Playwright Page对象及截图按钮阻塞问题的解决方法

嗨,我来帮你搞定这个Streamlit和Playwright集成的阻塞问题!

你遇到的截图按钮阻塞问题,核心原因是每次点击Streamlit按钮时,脚本会重新运行,而你用asyncio.run()单独调用每个异步函数,会创建新的事件循环,和之前打开页面时的事件循环冲突——之前的page对象属于旧的事件循环,在新循环里调用它的异步方法就会卡住。另外,之前的代码还存在Playwright实例未正确关闭的资源泄漏问题。

下面是修正后的完整代码,我会一步步给你解释修改的关键要点:

import streamlit as st
from playwright.async_api import async_playwright
import asyncio
import nest_asyncio

# 应用nest_asyncio以支持嵌套事件循环
nest_asyncio.apply()

# 针对Windows环境设置ProactorEventLoop,解决Playwright异步兼容问题
if st.runtime.exists():
    asyncio.set_event_loop_policy(asyncio.WindowsProactorEventLoopPolicy())

# 初始化session_state,保存跨交互的核心对象
if "browser" not in st.session_state:
    st.session_state.browser = None
if "page" not in st.session_state:
    st.session_state.page = None
if "playwright" not in st.session_state:
    st.session_state.playwright = None

async def open_browser():
    # 避免重复打开浏览器,防止资源浪费
    if st.session_state.browser is not None:
        st.warning("浏览器已经处于打开状态啦")
        return
    
    # 启动Playwright并打开Chromium浏览器
    st.session_state.playwright = await async_playwright().start()
    st.session_state.browser = await st.session_state.playwright.chromium.launch(headless=False)
    st.session_state.page = await st.session_state.browser.new_page()
    await st.session_state.page.goto("https://www.baidu.com")
    st.success("网页已成功打开!")

async def take_screenshot():
    if st.session_state.page:
        await st.session_state.page.screenshot(path="screenshot.png")
        st.success("截图已保存为screenshot.png")
    else:
        st.error("请先打开网页再进行截图操作哦")

async def close_browser():
    if st.session_state.browser:
        # 正确关闭浏览器并停止Playwright实例,避免资源泄漏
        await st.session_state.browser.close()
        await st.session_state.playwright.stop()
        # 重置session_state中的状态,为下一次操作做准备
        st.session_state.browser = None
        st.session_state.page = None
        st.session_state.playwright = None
        st.success("浏览器已关闭")
    else:
        st.error("浏览器还没打开呢")

# Streamlit UI界面
st.title("Playwright 与 Streamlit 集成演示")

# 打开网页按钮
if st.button("打开网页"):
    loop = asyncio.get_event_loop()
    loop.run_until_complete(open_browser())

# 生成截图按钮
if st.button("生成截图"):
    loop = asyncio.get_event_loop()
    loop.run_until_complete(take_screenshot())

# 关闭网页按钮
if st.button("关闭网页"):
    loop = asyncio.get_event_loop()
    loop.run_until_complete(close_browser())

关键修改点说明:

  1. 统一事件循环执行异步操作:
    把原来的asyncio.run()替换成asyncio.get_event_loop().run_until_complete(),这样所有异步操作都会复用我们预先配置好的事件循环(已经应用了nest_asyncio和Windows专属的ProactorEventLoopPolicy),避免了循环冲突导致的阻塞。

  2. 新增Playwright实例到Session State:
    之前的Playwright是局部变量,关闭浏览器后无法停止这个实例,会造成资源泄漏。现在把它存入st.session_state,关闭浏览器时可以正确调用playwright.stop()清理资源。

  3. 添加重复打开判断:
    在open_browser函数里增加了浏览器状态判断,避免用户多次点击打开按钮创建多个浏览器实例。

  4. 优化提示信息:
    把提示改成更贴近中文用户的表达,让操作反馈更清晰。

额外注意事项:

  • 确保你已经安装了所有依赖:
    pip install streamlit playwright nest-asyncio
    playwright install chromium
    
  • 运行脚本时直接用streamlit run 你的脚本名.py,不要用普通Python运行,因为Streamlit需要在它的运行时环境中执行。

备注:内容来源于stack exchange,提问作者ffsxsy

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.14 08:50:29