Playwright Python 的异步 API 通过 from playwright.async_api import async_playwright 导入,主要适用于并发或事件驱动场景,如批量爬取、实时监控,或集成到 FastAPI 等异步框架中。1、启动与基本结构
异步 API 的核心框架是 async 函数 + async with。常见启动流程:- 启动 Playwright:async with async_playwright() as p:
- 启动浏览器:await p.chromium.launch(headless=False)(支持 slow_mo=100 调试慢放;也可选 Firefox/WebKit)。
- 新建上下文:await browser.new_context(viewport={"width": 1920, "height": 1080})(隔离 session)。
- 新建页面:await context.new_page()
- 关闭:await browser.close()(上下文管理器自动处理)
import asynciofrom playwright.async_api import async_playwrightasync def main(): async with async_playwright() as p: browser = await p.chromium.launch(headless=False) context = await browser.new_context() page = await context.new_page() await page.goto("https://example.com") title = await page.title() print(title) await browser.close()asyncio.run(main())
用 try-except 包裹 await 操作,捕获 TimeoutError。并发时,结合 asyncio.gather 运行多个协程2. 导航与等待方法
- await page.goto(url, timeout=30000, wait_until="networkidle")(等待网络空闲)
- await page.go_back() / await page.go_forward()
- await page.wait_for_load_state("domcontentloaded")(轻量等待 DOM)
- await page.wait_for_url("**/dashboard", timeout=10000)(等待特定 URL)
- await page.wait_for_timeout(500)(硬等待毫秒)
async def navigate_example(page): await page.goto("https://playwright.dev") await page.wait_for_url("https://playwright.dev/", timeout=5000) await page.wait_for_load_state("networkidle")
优先 wait_until="networkidle",比 "load" 更可靠,减少 flaky 测试。v1.57 优化了等待逻辑,减少不必要重试。3. 定位器与交互
定位使用 Locator,异步版自动等待元素可交互。- page.get_by_role("button", name="Submit")(ARIA 优先)。
- page.get_by_text("Hello")
- page.get_by_label("Username")
- page.get_by_placeholder("Enter email")
- page.locator("css=div > a")
- await locator.click(force=True)(强制点击)。
- await locator.fill("new value")
- await locator.press("Enter")
- await locator.press_sequentially("slow input", delay=50)(模拟真人输入;注:type() 已弃用)
- await locator.check() / await locator.uncheck()
- await locator.select_option("value2")(下拉选择)
- await locator.set_input_files("file.pdf")(上传)
async def form_example(page): await page.goto("https://example.com/login") await page.get_by_label("Username").fill("admin") await page.get_by_label("Password").fill("pass123") await page.get_by_role("button", name="Login").click() await page.wait_for_url("**/dashboard")
await locator.filter(has_text="Item1").nth(0).click()(过滤 + 索引)。优先 get_by_test_id() 如果项目添加了 data-testid,维护性更强。4. 断言与检查
使用 expect 库,异步版需先 await 值再断言。- from playwright.async_api import expect
- await expect(page).to_have_title(re.compile("Playwright"))(v1.57 更新,支持正则)。
- expect(locator).to_be_visible()
- expect(locator).to_have_text("Expected")
- expect(page).to_have_url(re.compile("example"))
- expect(locator).not_to_be_enabled()
- expect(await locator.count()).to_be_greater_than(0)
async def assert_example(page): locator = page.get_by_text("Success") expect(locator).to_be_visible(timeout=5000) await expect(page).to_have_title("Home Page")
expect 自动重试(默认 30s),异步不阻塞其他任务。5. 高级功能与调试
- 截图/PDF:await page.screenshot(path="shot.png", full_page=True)。
- 执行 JS:result = await page.evaluate("() => document.title")。
- 监听事件:page.on("response", lambda response: print(response.url))。
- Trace 录制:await context.tracing.start(screenshots=True); ... ; await context.tracing.stop(path="trace.zip")。
- 拦截请求:await page.route("/api/", lambda route: await route.continue_())。
- 并发:await asyncio.gather(task1(page1), task2(page2))。
异步 API 在爬虫中特别强大,可并发多个页面抓取数据。但避免过度使用 gather,限制 10-20 个并发以防内存溢出。6. 其他注意点:
- 始终在 async def 中编写代码,使用 asyncio.run 执行。
- 处理异常:async try/except TimeoutError。
- 测试集成:使用 pytest-playwright 的 @pytest.mark.asyncio,v1.50+ 支持异步 fixtures。
- 版本建议:升级到 v1.57 以获最新优化,如 WebSocket 异步路由。
Pandas 3.0 正式版来了!比你想象中更狠的两个改变