Playwright Sync API 不能在 asyncio event loop 中运行,因其设计要求同步阻塞调用必须脱离异步上下文;需统一使用 async_playwright() 配合 async with 和 await,避免混用或线程间 event loop 冲突。

Playwright Sync API 不能在 asyncio event loop 里运行,这是设计限制,不是 bug。 你看到的 It looks like you are using Playwright Sync API inside the asyncio loop 报错,本质是 Python 的事件循环不允许同步阻塞调用混入异步上下文——就像不能在 async def 函数里直接调用 time.sleep() 一样。
sync_playwright() 在 async 函数里被调用
最常见触发点:你在 async def 函数中写了 sync_playwright().start() 或 with sync_playwright() as p:。Playwright 的同步 API 会启动自己的线程并阻塞等待,而 asyncio 要求所有 I/O 必须是非阻塞的。
- 错误示例:
async def crawl(): with sync_playwright() as p: ... - 正确做法:统一用
async_playwright()+async with+await链路 - 别试图“包装”同步 API 成异步:比如用
loop.run_in_executor()调用sync_playwright,这只会让资源管理更混乱、泄漏更难排查
全局 event loop 已运行,却误启 sync_playwright
典型场景是 Jupyter、FastAPI 启动脚本、或某些测试框架(如 pytest-asyncio)已隐式创建并运行了 loop。此时哪怕你没写 async def,只要当前线程的 asyncio.get_event_loop().is_running() 返回 True,sync_playwright() 就会拒绝工作。
华为云 Python SDK 查询工具。自动发现已安装 SDK 的服务包、Client类、API 方法、入参详情、类信息(__init__ 参数、属性、类型、描述),支持关键字搜索,快速定位目标 API 使用方法。
- 检查方式:
import asyncio; print(asyncio.get_event_loop().is_running()) - 临时绕过(仅调试):用
asyncio.new_event_loop()创建新 loop 并set_event_loop(),但生产环境不推荐 - 根本解法:确认你的执行环境是否本就该走异步路线——Jupyter 默认支持
await,直接用async_playwright更干净
多线程中误共享 event loop
如果你用 threading.Thread 启动多个任务,并在每个线程里都调用 sync_playwright(),而主线程又在跑 asyncio,就可能触发这个报错。因为 Python 的 event loop 是线程绑定的,子线程默认没有自己的 loop,会尝试复用主线程的(已运行)loop。
立即学习“Python免费学习笔记(深入)”;
- 现象:单线程跑正常,一开多线程就报错
- 验证:在子线程开头加
asyncio.set_event_loop(asyncio.new_event_loop()) - 更稳妥方案:每个线程只用
async_playwright,并在该线程内完整管理自己的async with生命周期
真正容易被忽略的是:这个报错往往不是你第一行代码的问题,而是某个被 import 的模块、或者某个第三方库的初始化逻辑偷偷启动了 sync_playwright。建议用 grep -r "sync_playwright" . 扫一遍依赖代码,尤其是封装了浏览器操作的工具类。

















