API 教程与代码示例
掌握 Playwright Python 最常用的 API,配合可运行的代码示例快速学习。
元素定位
Playwright 提供多种选择器引擎,推荐优先使用语义化定位方法。
selectors.py — 推荐方式
# ===== 推荐:语义化定位方法 ===== # 按角色(ARIA role)定位 — 最推荐 page.get_by_role("button", name="提交") page.get_by_role("heading", name="欢迎") page.get_by_role("link", name="首页") page.get_by_role("textbox", name="用户名") page.get_by_role("checkbox", name="记住我") # 按可见文本定位 page.get_by_text("立即注册") page.get_by_text("注册", exact=True) # 精确匹配 # 按 label 定位表单元素 page.get_by_label("邮箱地址") page.get_by_label("密码") # 按 placeholder 定位 page.get_by_placeholder("请输入搜索内容") # 按 alt text 定位图片 page.get_by_alt_text("公司 Logo") # 按 data-testid 定位(适合与开发协作) page.get_by_test_id("submit-button")
selectors.py — CSS / XPath / 组合
# ===== CSS 选择器 ===== page.locator("#login-form") page.locator(".btn.btn-primary") page.locator("input[type='email']") page.locator("div.card >> h3") # 嵌套 # ===== XPath ===== page.locator("xpath=//button[@class='submit']") # ===== 链式过滤 ===== page.locator(".product-card").filter( has_text="Python 入门" ).first # ===== 第 N 个元素 ===== page.locator("li.item").nth(2) # 第 3 个(从 0 开始) page.locator("li.item").first page.locator("li.item").last # ===== 计数 ===== count = page.locator("li.item").count() print(f"共 {count} 个元素")
页面操作
点击、输入、选择、拖放等常用交互操作。
actions.py
# ===== 点击操作 ===== page.click("#submit") page.dblclick("#item") # 双击 page.click("#menu", button="right") # 右键 page.click("#link", modifiers=["Shift"]) # Shift+点击 # ===== 文本输入 ===== page.fill("#username", "admin") # 清空再填入 page.type("#search", "Playwright", delay=80) # 模拟逐字输入 page.press("#search", "Enter") # 按键 # ===== 下拉选择 ===== page.select_option("#city", "shanghai") # 按 value page.select_option("#city", label="上海") # 按显示文本 page.select_option("#tags", ["python", "web"]) # 多选 # ===== 复选框与单选框 ===== page.check("#agree") # 勾选 page.uncheck("#agree") # 取消勾选 page.set_checked("#agree", True) # 设置状态 # ===== 文件上传 ===== page.set_input_files("input[type='file']", "report.pdf") page.set_input_files("input[type='file']", ["a.png", "b.png"]) page.set_input_files("input[type='file']", []) # 清空 # ===== 拖放 ===== page.drag_and_drop("#source", "#target") # ===== 悬停 ===== page.hover(".dropdown-trigger") # ===== 聚焦 ===== page.focus("#email") # ===== 截图 ===== page.screenshot(path="full.png", full_page=True) page.locator(".chart").screenshot(path="chart.png")
等待与断言
Playwright 内置的自动等待与 expect 断言 API。
waiting.py
# ===== 自动等待(内置,通常不需要手动等待) ===== # page.click() 自动等待元素:可见、稳定、可接受事件、已启用 # page.fill() 自动等待元素:可见、已启用、可编辑 # ===== 显式等待 ===== # 等待元素出现 page.wait_for_selector(".result", state="visible") page.wait_for_selector(".spinner", state="hidden") page.wait_for_selector(".modal", state="detached") # 等待 URL 变化 page.wait_for_url("**/dashboard") page.wait_for_url(lambda url: "success" in url) # 等待网络请求 with page.expect_response("**/api/data") as resp: page.click("#load-data") data = resp.value.json()
assertions.py — 配合 pytest
from playwright.sync_api import expect # ===== 页面断言 ===== expect(page).to_have_title("Dashboard") expect(page).to_have_url("https://example.com/dashboard") # ===== 元素断言 ===== locator = page.locator(".message") expect(locator).to_be_visible() expect(locator).to_have_text("操作成功") expect(locator).to_contain_text("成功") expect(locator).to_have_class("alert alert-success") expect(locator).to_have_attribute("href", "/home") expect(locator).to_be_enabled() expect(locator).to_be_checked() # 否定断言 expect(locator).not_to_be_visible() # 列表断言 items = page.locator("ul > li") expect(items).to_have_count(5) expect(items).to_have_text(["A", "B", "C", "D", "E"])
网络处理
拦截请求、Mock API、监控网络活动。
network.py
# ===== 监听请求与响应 ===== page.on("request", lambda req: print(f">> {req.method} {req.url}")) page.on("response", lambda res: print(f"<< {res.status} {res.url}")) # ===== 拦截并修改请求 ===== def block_images(route): if route.request.resource_type == "image": route.abort() else: route.continue_() page.route("**/*", block_images) # ===== Mock API 响应 ===== def mock_api(route): route.fulfill( status=200, content_type="application/json", body='{"users": [{"name": "Alice"}, {"name": "Bob"}]}' ) page.route("**/api/users", mock_api) # ===== 修改请求头 ===== def add_auth(route): headers = route.request.headers headers["Authorization"] = "Bearer my-token" route.continue_(headers=headers) page.route("**/api/**", add_auth) # ===== 等待特定请求 ===== with page.expect_request("**/api/submit") as req: page.click("#submit") print(req.value.post_data)
高级功能
截图录屏、PDF 导出、多标签页、设备模拟等进阶用法。
device_emulation.py
# 模拟移动设备 iphone = p.devices["iPhone 14"] ctx = browser.new_context(**iphone) page = ctx.new_page() # 模拟地理位置 ctx = browser.new_context( geolocation={ "latitude": 31.23, "longitude": 121.47 }, permissions=["geolocation"] ) # 模拟暗色模式 ctx = browser.new_context( color_scheme="dark" )
multi_tab.py
# 处理新标签页 with context.expect_page() as new: page.click("a[target='_blank']") new_page = new.value print(new_page.url) # 处理弹窗 page.on("dialog", lambda d: d.accept()) page.click("#delete") # 处理文件下载 with page.expect_download() as dl: page.click("#download-btn") download = dl.value download.save_as("report.xlsx")
pdf_and_video.py
# 导出 PDF(仅 Chromium headless) page.pdf( path="page.pdf", format="A4", print_background=True, margin={"top": "1cm", "bottom": "1cm"} ) # 录制视频 ctx = browser.new_context( record_video_dir="./videos", record_video_size={"width": 1280, "height": 720} ) page = ctx.new_page() # ... 操作 ... ctx.close() # 关闭后视频保存 print(page.video.path())
auth_state.py
# 保存登录状态(避免重复登录) ctx = browser.new_context() page = ctx.new_page() page.goto("https://example.com/login") page.fill("#user", "admin") page.fill("#pass", "secret") page.click("#login") # 保存状态到文件 ctx.storage_state(path="auth.json") # 后续测试直接加载 ctx2 = browser.new_context( storage_state="auth.json" ) # 已经是登录状态!