当前位置: 首页 > news >正文

Playwright 浏览器自动化完全指南:从入门到实战

目录

  • 一、什么是 Playwright
  • 二、Playwright vs Selenium:为什么选择 Playwright
  • 三、支持的语言与浏览器
  • 四、核心架构与执行流程
  • 五、环境安装与验证
  • 六、第一个程序:打开网页并截图
  • 七、常用操作速查
  • 八、元素定位详解
  • 九、自动等待机制深度解析
  • 十、浏览器上下文与页面管理
  • 十一、常见场景实战
  • 十二、Codegen:代码录制神器
  • 十三、调试与排查技巧
  • 十四、Playwright 能做什么
  • 十五、最佳实践与避坑指南
  • 十六、总结与学习路线

一、什么是 Playwright

1.1 定义

Playwright 是一个开源的浏览器自动化框架,由 Microsoft 开发并维护。它提供了一套统一的 API,可以用代码控制 Chromium、Firefox 和 WebKit 三大浏览器引擎,完成包括打开网页、点击、输入、数据抓取、截图、文件上传等在内的几乎所有浏览器操作。

1.2 一句话理解

Playwright = 用代码驱动浏览器,完成一切网页操作

1.3 核心能力一览

打开网页 ──→ 点击 / 输入 ──→ 数据抓取 ──→ 截图 / 录屏 ──→ 自动化测试 │ │ │ │ │ ▼ ▼ ▼ ▼ ▼ goto() click() / text_content() screenshot() assert / fill() inner_text() video() expect()

1.4 发展历程

  • 2020 年 1 月:Microsoft 正式开源 Playwright,首个版本支持 JavaScript/TypeScript
  • 2020 年中:陆续发布 Python、Java、.NET 版本
  • 2021 年:Playwright Test(Node.js 测试运行器)成熟,社区快速壮大
  • 2022-2023 年:在全球开发者调查中,Playwright 使用率持续攀升,逐步成为最受推荐的浏览器自动化工具之一
  • 2024-2025 年:持续迭代更新,生态日趋完善,支持组件测试、UI 模式、全局设置等特性

二、Playwright vs Selenium:为什么选择 Playwright

2.1 全方位对比

维度SeleniumPlaywright
诞生时间2004 年2020 年
维护方Selenium 社区Microsoft
浏览器驱动需要单独安装 WebDriver(如 chromedriver)内置浏览器二进制,无需额外驱动
自动等待需手动编写显式等待(WebDriverWait)原生内置,所有操作自动等待
定位器find_element 系列,基于 WebDriver 协议Locator API,支持链式、自动重试
并行执行需要额外配置(Grid、pytest-xdist 等)原生支持并行,浏览器上下文天然隔离
调试工具依赖第三方工具内置 Trace Viewer、Codegen、UI 模式
移动模拟Appium(独立项目)内置设备描述符,可直接模拟
网络拦截需要额外工具(如 mitmproxy)原生支持 route() 拦截请求/响应
学习曲线资料丰富但 API 略显繁琐API 现代简洁,上手更快
社区生态极为成熟,第三方库丰富快速成长中,官方文档质量高

2.2 结论

Selenium:传统经典方案,生态成熟,适合已有项目维护 Playwright:现代首选方案,自动等待强、定位器智能、调试高效,适合新项目

2.3 如何选择

  • 如果你是一个全新项目且团队没有历史包袱 →优先选择 Playwright
  • 如果你的项目已经大量使用 Selenium,迁移成本高 → 可以继续使用 Selenium
  • 如果你需要高质量的 E2E 测试CI/CD 集成强烈推荐 Playwright
  • 如果你需要爬虫 / 数据采集→ Playwright 的网络拦截和自动等待更省心

三、支持的语言与浏览器

3.1 支持的编程语言

Playwright ├── Python ← 本文重点 ├── JavaScript / TypeScript ├── Java └── .NET (C#)

四套语言的 API 设计高度一致,核心概念完全通用,掌握一门后迁移到其他语言的成本很低。

3.2 支持的浏览器

Playwright 支持的浏览器引擎 ├── Chromium (Chrome、Edge、Opera 等) ├── Firefox └── WebKit (Safari 的内核)

注意:Playwright 不使用系统已安装的浏览器,而是自带经过适配的浏览器二进制文件,确保了行为的一致性和可靠性。


四、核心架构与执行流程

4.1 整体架构

用户代码(Python / JS / Java / .NET) │ ▼ Playwright API 层 │ ▼ Browser Server(浏览器进程管理) │ ▼ ┌─────────┬──────────┬──────────┐ ▼ ▼ ▼ ▼ Chromium Firefox WebKit Edge(Chromium)

4.2 核心对象关系

Playwright 最顶层入口,负责启动浏览器实例 │ ▼ Browser 一个浏览器实例(如一个 Chromium 进程) │ ▼ BrowserContext 浏览器上下文,相当于一个隐身会话,隔离 Cookie、LocalStorage │ 一个 Browser 可以创建多个 Context,天然实现并行隔离 ▼ Page 一个标签页 / 页面,是实际操作的主要对象 │ ▼ Locator 元素定位器,用于查找页面元素并执行操作

4.3 核心执行流程(五步法)

启动浏览器 ──→ 打开页面 ──→ 定位元素 ──→ 执行动作 ──→ 获取结果 │ │ │ │ │ ▼ ▼ ▼ ▼ ▼ launch() goto() locator() click() / text_content() new_page() wait_for() get_by_*() fill() screenshot()

理解这五步是掌握 Playwright 的关键,所有自动化场景都是这五步的组合与扩展。


五、环境安装与验证

5.1 系统要求

  • Python 3.8 及以上版本(推荐 3.10+)
  • Windows、macOS、Linux 均支持
  • 建议 4GB 以上内存(浏览器较占资源)

5.2 安装步骤

第一步:安装 Playwright Python 包

pip install playwright

第二步:安装浏览器二进制文件

playwright install

此命令会自动下载 Chromium、Firefox、WebKit 三大浏览器的适配版本,存储在本地缓存目录中。

如果只需要 Chromium,可以指定:

playwright install chromium

第三步:(可选)安装系统依赖(Linux 服务器环境)

playwright install-deps

该命令会安装浏览器运行所需的系统级依赖库(如 libglib2.0、libnss3 等),在 Linux 服务器或 Docker 环境中通常需要执行。

5.3 验证安装

from playwright.sync_api import sync_playwright with sync_playwright() as p: browser = p.chromium.launch() page = browser.new_page() page.goto("https://example.com") print("页面标题:", page.title()) browser.close()

如果输出了页面标题,说明安装成功。

5.4 国内加速建议

如果下载浏览器二进制时速度过慢,可设置镜像源:

# 设置 Playwright 镜像(Linux / macOS) export PLAYWRIGHT_DOWNLOAD_HOST=https://npmmirror.com/mirrors/playwright # Windows PowerShell $env:PLAYWRIGHT_DOWNLOAD_HOST="https://npmmirror.com/mirrors/playwright" # 然后重新安装 playwright install

六、第一个程序:打开网页并截图

6.1 代码示例

from playwright.sync_api import sync_playwright with sync_playwright() as p: # 启动 Chromium 浏览器(headless=False 表示有界面,方便观察) browser = p.chromium.launch(headless=False) # 创建一个新的页面 page = browser.new_page() # 导航到目标网址 page.goto("https://playwright.dev/") # 打印页面标题 print(f"页面标题:{page.title()}") # 截取整页截图并保存 page.screenshot(path="playwright_homepage.png", full_page=True) print("截图已保存!") # 关闭浏览器 browser.close()

6.2 代码解析

sync_playwright() 获取 Playwright 实例(上下文管理器) └─ p.chromium.launch() 启动 Chromium 浏览器 └─ browser.new_page() 创建空白标签页 └─ page.goto(url) 导航到目标网址 └─ page.screenshot() 截图保存 └─ browser.close() 关闭浏览器释放资源

6.3 headless 模式说明

# 有界面模式(调试时使用,可以看到浏览器操作过程) browser = p.chromium.launch(headless=False) # 无界面模式(正式运行时使用,速度快、资源省) browser = p.chromium.launch(headless=True)

6.4 异步版本

Playwright 同时支持同步和异步两种 API。在高并发场景下推荐使用异步版本:

import asyncio from playwright.async_api import async_playwright async def main(): async with async_playwright() as p: browser = await p.chromium.launch(headless=False) page = await browser.new_page() await page.goto("https://playwright.dev/") print(f"页面标题:{await page.title()}") await page.screenshot(path="async_screenshot.png") await browser.close() asyncio.run(main())

本文后续示例以同步 API 为主,异步版本只需在方法前加await即可,逻辑完全一致。


七、常用操作速查

7.1 导航操作

# 打开网页 page.goto("https://www.baidu.com") # 刷新页面 page.reload() # 后退 / 前进 page.go_back() page.go_forward() # 等待特定 URL 出现(支持通配符) page.wait_for_url("**/dashboard")

7.2 点击操作

# 普通点击 page.locator("text=登录").click() # 双击 page.locator("text=标题").dblclick() # 右键点击 page.locator(".item").click(button="right") # 按住 Shift 点击 page.locator("a").click(modifiers=["Shift"]) # 强制点击(即使元素被遮挡也尝试点击) page.locator("#btn").click(force=True)

7.3 输入操作

# 清空并输入文本 page.locator("#username").fill("admin") # 逐字符输入(模拟真实打字,适合有输入事件监听的场景) page.locator("#search").press_sequentially("Playwright", delay=100) # 按键操作 page.locator("input").press("Enter") page.locator("input").press("Control+a") # 全选 # 输入文件 page.locator('input[type="file"]').set_input_files("test.pdf")

7.4 获取数据

# 获取元素文本内容 text = page.locator("h1").text_content() # 获取元素内部文本(不含子元素标签) inner = page.locator(".content").inner_text() # 获取属性值 href = page.locator("a").get_attribute("href") # 获取输入框的值 value = page.locator("input").input_value() # 获取页面标题 title = page.title() # 获取当前 URL url = page.url

7.5 截图与录屏

# 元素截图 page.locator("#chart").screenshot(path="chart.png") # 整页截图(包含滚动区域) page.screenshot(path="full.png", full_page=True) # 截取指定区域 page.screenshot(path="clip.png", clip={"x": 0, "y": 0, "width": 800, "height": 600})

录屏功能需在创建 BrowserContext 时启用:

context = browser.new_context( record_video_dir="videos/", record_video_size={"width": 1280, "height": 720} ) page = context.new_page() page.goto("https://example.com") context.close() # 关闭上下文时视频自动保存

7.6 等待操作

# 等待元素出现 page.locator("#result").wait_for(timeout=10000) # 超时 10 秒 # 等待元素消失 page.locator(".loading").wait_for(state="hidden") # 等待特定网络请求完成 with page.expect_response("**/api/data") as response_info: page.click("#load-data") response = response_info.value

八、元素定位详解

元素定位是 Playwright 最核心的能力,定位选对了,后续的点击、输入、断言都能水到渠成。

8.1 定位方式全景

元素定位方式 │ ├── 推荐方式(语义化,稳定,抗页面变化) │ ├── get_by_role() 按 ARIA 角色 + 名称定位 │ ├── get_by_text() 按可见文本定位 │ ├── get_by_label() 按表单 label 定位 │ ├── get_by_placeholder() 按 placeholder 定位 │ ├── get_by_alt_text() 按图片 alt 属性定位 │ ├── get_by_test_id() 按># 按按钮角色 + 名称 page.get_by_role("button", name="登录").click() # 按链接角色 page.get_by_role("link", name="首页").click() # 按文本框角色 page.get_by_role("textbox", name="用户名").fill("admin") # 按复选框 page.get_by_role("checkbox", name="记住我").check() # 按标题(heading) page.get_by_role("heading", name="欢迎").click()

get_by_role基于 WAI-ARIA 无障碍标准,定位语义明确、稳定性高,是 Playwright 官方最推荐的方式。

(2)get_by_text — 按文本定位

# 精确匹配 page.get_by_text("登录", exact=True).click() # 模糊匹配(默认) page.get_by_text("登录").click() # 正则匹配 page.get_by_text(re.compile(r"第\d+页")).click()

(3)get_by_label — 按表单标签定位

# 根据 <label for="username">用户名</label> 定位输入框 page.get_by_label("用户名").fill("admin") page.get_by_label("密码").fill("123456")

(4)get_by_placeholder — 按占位文本定位

page.get_by_placeholder("请输入用户名").fill("admin") page.get_by_placeholder("请输入密码").fill("secret")

(5)get_by_test_id — 测试专用属性

HTML 中添加data-testid属性:

<button># ID 定位 page.locator("#username").fill("admin") # 类名定位 page.locator(".btn-primary").click() # 属性定位 page.locator('[type="submit"]').click() # 组合定位 page.locator('div.container > button.submit').click() # 伪类定位 page.locator("button:first-child").click() page.locator("li:nth-child(3)").click()

8.4 XPath 定位

# 文本匹配 page.locator('//button[text()="提交"]').click() # 包含某属性 page.locator('//input[@placeholder="用户名"]').fill("admin") # 模糊匹配文本 page.locator('//div[contains(text(), "加载更多")]').click() # 轴定位(父节点、兄弟节点等) page.locator('//label[text()="用户名"]/following-sibling::input').fill("admin")

8.5 链式定位与过滤

# 链式缩小范围 page.locator("div.card").locator("button").click() # 按文本过滤 page.locator("li").filter(has_text="Python").click() # 按子元素过滤 page.locator("div.row").filter(has=page.locator("text=详情")).click() # 按索引选取(第2个匹配元素) page.locator("div.item").nth(1).click() # 第一个 / 最后一个 page.locator("li").first.click() page.locator("li").last.click() # 获取匹配数量 count = page.locator("div.item").count()

8.6 定位优先级建议

最稳定 最灵活 │ │ ▼ ▼ get_by_test_id → get_by_role → get_by_label → get_by_text → CSS → XPath 写自动化测试:优先 get_by_test_id / get_by_role 写爬虫/采集:常用 CSS / XPath

九、自动等待机制深度解析

9.1 什么是自动等待

Playwright 的每一个操作(click、fill、text_content 等)在执行前,都会自动进行一系列检查,确保元素处于可操作状态后才执行动作。这是 Playwright 相比 Selenium 的核心优势之一。

9.2 自动等待的检查项

当你执行page.locator("button").click()时,Playwright 会在后台自动:

1. 等待元素出现在 DOM 中 │ ▼ 2. 等待元素可见(非 display:none / visibility:hidden) │ ▼ 3. 等待元素稳定(不在动画中,位置不持续变化) │ ▼ 4. 等待元素可接收事件(不被其他元素遮挡) │ ▼ 5. 等待元素可交互(不是 disabled 状态) │ ▼ 6. 执行 click()

每一步检查都有默认超时时间(默认 30 秒),超时后抛出 TimeoutError。

9.3 对比传统方式

Selenium 的写法(需要手动等待):

from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By # 需要手动编写显式等待 wait = WebDriverWait(driver, 10) element = wait.until(EC.element_to_be_clickable((By.ID, "submit"))) element.click()

Playwright 的写法(自动等待):

# 一行搞定,自动等待元素可点击 page.locator("#submit").click()

9.4 少用 sleep,多用自动等待

# ❌ 不推荐:硬编码等待 import time time.sleep(5) page.locator("#result").click() # ✅ 推荐:利用自动等待 page.locator("#result").click() # ✅ 确实需要等待特定条件时,使用 Playwright 的等待 API page.wait_for_selector("#result", state="visible") page.wait_for_url("**/dashboard") page.wait_for_load_state("networkidle") page.wait_for_function("document.querySelector('#result') !== null")

9.5 load_state 说明

# 等待 DOM 加载完成(默认行为,通常够用) page.goto("https://example.com", wait_until="domcontentloaded") # 等待所有资源(图片、CSS、JS)加载完成 page.goto("https://example.com", wait_until="load") # 等待网络空闲(没有超过 0.5 秒的网络请求,适合 SPA 应用) page.goto("https://example.com", wait_until="networkidle")

十、浏览器上下文与页面管理

10.1 BrowserContext 的作用

BrowserContext 是 Playwright 中一个非常重要的概念,它相当于一个独立的浏览器会话

Browser(浏览器实例) │ ├── BrowserContext A ← Cookie、LocalStorage、权限设置完全独立 │ ├── Page 1(标签页) │ └── Page 2(标签页) │ └── BrowserContext B ← 与 Context A 完全隔离 └── Page 1(标签页)

10.2 多上下文场景

from playwright.sync_api import sync_playwright with sync_playwright() as p: browser = p.chromium.launch() # 创建两个独立的上下文(模拟两个独立用户) context_a = browser.new_context() context_b = browser.new_context() page_a = context_a.new_page() page_b = context_b.new_page() # 两个页面的登录状态互不影响 page_a.goto("https://example.com/login") page_b.goto("https://example.com/login") # ... 分别操作 context_a.close() context_b.close() browser.close()

10.3 设备模拟

# 使用内置的设备描述符模拟 iPhone 13 iphone = p.devices["iPhone 13"] context = browser.new_context(**iphone) page = context.new_page() page.goto("https://example.com")

10.4 设置视窗大小与地理位置

context = browser.new_context( viewport={"width": 1920, "height": 1080}, locale="zh-CN", timezone_id="Asia/Shanghai", geolocation={"longitude": 116.397128, "latitude": 39.916527}, permissions=["geolocation"], color_scheme="dark" )

十一、常见场景实战

11.1 登录场景

from playwright.sync_api import sync_playwright with sync_playwright() as p: browser = p.chromium.launch(headless=False) page = browser.new_page() page.goto("https://example.com/login") # 方式一:直接选择器 page.fill('#username', 'admin') page.fill('#password', '123456') page.click('button[type="submit"]') # 方式二:推荐定位方式 # page.get_by_label("用户名").fill("admin") # page.get_by_label("密码").fill("123456") # page.get_by_role("button", name="登录").click() # 等待登录成功跳转 page.wait_for_url("**/dashboard") print("登录成功,当前页面:", page.url) browser.close()

11.2 保存与复用登录状态

from playwright.sync_api import sync_playwright with sync_playwright() as p: browser = p.chromium.launch(headless=False) # 第一次:手动登录并保存状态 context = browser.new_context() page = context.new_page() page.goto("https://example.com/login") page.get_by_label("用户名").fill("admin") page.get_by_label("密码").fill("123456") page.get_by_role("button", name="登录").click() page.wait_for_url("**/dashboard") # 保存登录状态到文件 context.storage_state(path="auth_state.json") print("登录状态已保存!") context.close() # 后续:直接加载状态,无需重复登录 context = browser.new_context(storage_state="auth_state.json") page = context.new_page() page.goto("https://example.com/dashboard") print("已使用保存的状态直接进入后台:", page.title()) context.close() browser.close()

11.3 文件上传

# 单文件上传 page.locator('input[type="file"]').set_input_files("test.pdf") # 多文件上传 page.locator('input[type="file"]').set_input_files(["a.png", "b.png", "c.png"]) # 取消已选文件 page.locator('input[type="file"]').set_input_files([])

11.4 弹窗(Dialog)处理

# 方式一:自动接受所有弹窗 page.on("dialog", lambda dialog: dialog.accept()) # 方式二:根据弹窗类型分别处理 def handle_dialog(dialog): if dialog.type == "confirm": print(f"确认弹窗:{dialog.message}") dialog.accept() # 点击确认 # dialog.dismiss() # 点击取消 elif dialog.type == "alert": print(f"提示弹窗:{dialog.message}") dialog.accept() page.on("dialog", handle_dialog) page.click("#delete-btn") # 触发弹窗

11.5 多标签页处理

with sync_playwright() as p: browser = p.chromium.launch(headless=False) page = browser.new_page() page.goto("https://example.com") # 点击会打开新标签页的链接时,捕获新页面 with page.expect_popup() as popup_info: page.get_by_text("详情").click() new_page = popup_info.value print("新标签页标题:", new_page.title()) # 在新标签页上操作 new_page.locator("#content").click() new_page.close() browser.close()

11.6 网络请求拦截

def handle_route(route): """拦截 API 请求,可以修改请求或返回模拟数据""" if "/api/user" in route.request.url: # 返回模拟数据 route.fulfill( status=200, content_type="application/json", body='{"name": "测试用户", "role": "admin"}' ) else: # 放行其他请求 route.continue_() page.route("**/api/**", handle_route) page.goto("https://example.com")

11.7 执行 JavaScript

# 在页面中执行 JavaScript title = page.evaluate("document.title") print(title) # 传递参数给 JS result = page.evaluate("([a, b]) => a + b", [3, 5]) print(result) # 8 # 获取复杂的页面数据 data = page.evaluate(""" () => { const items = document.querySelectorAll('.product'); return Array.from(items).map(item => ({ name: item.querySelector('.title').textContent, price: item.querySelector('.price').textContent })); } """)

11.8 滚动操作

# 滚动到元素位置 page.locator("#footer").scroll_into_view_if_needed() # 使用鼠标滚轮 page.mouse.wheel(0, 500) # 向下滚动 500 像素 # 通过 JS 滚动到页面底部 page.evaluate("window.scrollTo(0, document.body.scrollHeight)")

11.9 iframe 操作

# 通过选择器定位 iframe frame = page.frame_locator("iframe#editor") # 在 iframe 中操作元素 frame.locator("button.save").click() frame.locator("input.title").fill("文档标题")

十二、Codegen:代码录制神器

12.1 什么是 Codegen

Codegen 是 Playwright 内置的代码录制工具。它会打开一个浏览器窗口并录制你的所有操作(点击、输入、导航等),实时生成对应的 Playwright 代码。

12.2 启动方式

# 基本启动 playwright codegen https://example.com # 指定输出语言(Python) playwright codegen --target python https://example.com # 指定输出文件 playwright codegen --output my_script.py https://example.com # 模拟移动设备 playwright codegen --device "iPhone 13" https://example.com # 保存登录状态 playwright codegen --save-storage=auth.json https://example.com

12.3 Codegen 的价值

快速上手复杂页面 ──→ 不用手动研究 DOM 结构 自动生成定位代码 ──→ 自动推荐最优定位方式 实时预览操作效果 ──→ 边操作边看代码生成 降低学习门槛 ──→ 新手也能快速写出自动化脚本

12.4 使用建议

  • 对于不熟悉的页面,先用 Codegen 录制一遍,了解操作流程和元素结构
  • 录制的代码通常需要手动优化(去除冗余步骤、改用更稳定的定位器)
  • Codegen 是学习工具,不建议直接用于生产环境

十三、调试与排查技巧

13.1 Trace Viewer

Trace Viewer 是 Playwright 内置的可视化调试工具,可以回放测试执行的完整过程。

context = browser.new_context() context.tracing.start(screenshots=True, snapshots=True, sources=True) page = context.new_page() page.goto("https://example.com") # ... 操作代码 ... context.tracing.stop(path="trace.zip")

查看 trace:

playwright show-trace trace.zip

Trace Viewer 会展示每一步操作的截图、DOM 快照、网络请求和控制台日志,是排查问题的利器。

13.2 headed 模式 + slow_mo

# slow_mo 会降低每个操作的速度(单位:毫秒),方便观察执行过程 browser = p.chromium.launch( headless=False, slow_mo=500 # 每步间隔 500 毫秒 )

13.3 截图排查

# 在关键步骤后截图,帮助定位问题 page.goto("https://example.com/login") page.screenshot(path="step1_login_page.png") page.get_by_label("用户名").fill("admin") page.screenshot(path="step2_filled.png") page.get_by_role("button", name="登录").click() page.screenshot(path="step3_after_login.png")

13.4 控制台日志

# 监听控制台输出 page.on("console", lambda msg: print(f"Console [{msg.type}]: {msg.text}")) # 监听页面错误 page.on("pageerror", lambda err: print(f"Page Error: {err}")) # 监听请求失败 page.on("requestfailed", lambda req: print(f"Request Failed: {req.url} - {req.failure}"))

十四、Playwright 能做什么

14.1 应用场景全景

Playwright 应用场景 │ ├── 自动化测试 │ ├── E2E(端到端)测试 │ ├── 回归测试 │ ├── 跨浏览器兼容性测试 │ └── 视觉回归测试(配合截图对比) │ ├── 网页自动化 │ ├── 表单自动填写 │ ├── 内容自动发布 │ ├── 定时任务执行 │ └── 流程审批自动化 │ ├── 数据采集 │ ├── 商品信息采集 │ ├── 社交媒体内容采集 │ ├── 公开数据集构建 │ └── 价格监控 │ ├── 办公自动化 │ ├── 报表自动生成 │ ├── 后台系统批量操作 │ └── 数据导出与归档 │ └── AI + 浏览器 ├── AI Agent 的浏览器交互层 ├── 智能表单填写 └── 自动化信息检索

14.2 与 pytest 集成(测试场景)

Playwright 官方提供了 pytest 插件,可直接使用 pytest 框架组织测试:

pip install pytest-playwright
# test_login.py import pytest from playwright.sync_api import Page, expect def test_login_success(page: Page): page.goto("https://example.com/login") page.get_by_label("用户名").fill("admin") page.get_by_label("密码").fill("123456") page.get_by_role("button", name="登录").click() # 使用 Playwright 的断言(自带等待和重试) expect(page).to_have_url("**/dashboard") expect(page.get_by_text("欢迎回来")).to_be_visible() def test_search(page: Page): page.goto("https://example.com") page.get_by_placeholder("搜索").fill("Playwright") page.get_by_placeholder("搜索").press("Enter") expect(page.locator(".search-result")).to_have_count(greater_than=0)

运行:

pytest test_login.py --browser chromium

14.3 连接远程浏览器

# 连接到已运行的浏览器实例(通过 CDP) browser = p.chromium.connect_over_cdp("http://localhost:9222") # 连接到 Playwright Server browser = p.chromium.connect("ws://remote-server:3000/")

十五、最佳实践与避坑指南

15.1 定位策略

✅ 推荐 └─ 优先使用 get_by_role / get_by_test_id / get_by_label 这些方式语义清晰、抗页面变化能力强 ❌ 避免 └─ 避免使用脆弱的定位方式(如绝对 XPath、索引定位) 页面结构一旦变化就会导致脚本失败

15.2 等待策略

✅ 推荐 └─ 依赖 Playwright 的自动等待机制 只在必要时使用 wait_for_selector / wait_for_url / wait_for_load_state ❌ 避免 └─ 避免使用 time.sleep() 硬编码等待 既不稳定又浪费时间

15.3 资源管理

✅ 推荐 └─ 使用 with 语句(上下文管理器)管理 Playwright 和 Browser 的生命周期 操作完成后及时 close() ❌ 避免 └─ 避免忘记关闭浏览器实例 长时间运行可能导致内存泄漏

15.4 测试组织

✅ 推荐 └─ 每个测试用例使用独立的 BrowserContext 确保测试之间互不影响 利用 pytest fixtures 管理 setup / teardown ❌ 避免 └─ 避免测试用例之间共享登录状态或页面数据

15.5 常见错误排查

错误原因解决方案
TimeoutError: locator.click元素未找到或不可交互检查定位器是否正确,元素是否在 iframe 中
Target page, context or browser has been closed操作的对象已被关闭检查代码逻辑,避免提前关闭
net::ERR_CONNECTION_REFUSED网络不通或地址错误确认目标 URL 是否可达
Element is not visible元素存在但不可见可能需要先滚动到元素位置或展开折叠区域

十六、总结与学习路线

16.1 核心要点回顾

Playwright 的本质 └─ 用代码控制浏览器完成一切网页操作 核心优势 ├── 自动等待 ──→ 稳定可靠,告别 sleep ├── 智能定位 ──→ get_by_role 等语义化 API,好用且抗变化 ├── 跨浏览器 ──→ Chromium / Firefox / WebKit 一套代码全覆盖 ├── Codegen ──→ 录制生成代码,高效上手复杂页面 ├── Trace ──→ 可视化调试,问题排查效率极高 └── Context ──→ 浏览器上下文隔离,天然支持并行与多用户场景

16.2 学习路线建议

第一阶段:入门 │ 安装环境 → 第一个程序 → 理解核心五步流程 │ 第二阶段:基础 │ 掌握常用操作 → 熟练元素定位 → 理解自动等待 │ 第三阶段:进阶 │ 网络拦截 → 多上下文管理 → iframe / 多标签页 → 保存状态 │ 第四阶段:实战 │ 独立完成一个自动化项目(如数据采集 / 自动化测试) │ 第五阶段:高阶 pytest 集成 → CI/CD 集成 → 性能优化 → AI Agent 集成

16.3 官方资源

  • 官方文档:https://playwright.dev/python/
  • GitHub 仓库:https://github.com/microsoft/playwright
  • API 参考:https://playwright.dev/python/docs/api/class-page

Playwright 是现代浏览器自动化的首选工具。掌握它,你就拥有了解决一切网页操作问题的能力。从今天开始,用代码驱动浏览器,让重复劳动交给自动化。

http://www.jsqmd.com/news/874410/

相关文章:

  • DDSC在东阳修车哪家好
  • de风——【从零开始学Linu】 - 基础指令详解(二)
  • 【深度解析】制造业选AI Agent,应看重行业经验还是通用能力?
  • Win11当Linux用?手把手教你配置SSH服务实现远程开发与文件传输
  • 性价比高的生成式引擎优化GEO哪家专业
  • Git学习(四)
  • SQLmap Python环境配置避坑指南:从启动失败到稳定运行
  • IMPROVER系统:AI气象预报统计后处理的工程化实践
  • RuoYi接口调试:Postman作为Spring Boot权限系统可信信使
  • 告别加班!Windows 一键部署 Open Claw,下班前搞定全天工作量
  • 跨平台AI辅助图像标注工具VisioFirm的设计与实现
  • 用函数实现模块化程序设计
  • 深入理解 Eino 的向量体系:从 Embedding 到向量数据库
  • BIND DNS漏洞CVE-2025-13878:EDNS选项解析致堆越界崩溃分析
  • 龙芯电脑装系统,选UOS、Loongnix还是等Debian?给3A4000/3A5000用户的保姆级选择指南
  • 超详细图解Attention机制:从原理到Self-Attention、多头注意力全覆盖
  • 工具变量评估与合成:从核心原理到机器学习实践
  • Windows 11上WSL安装后报getpwuid错误的完整排查手册:从Docker冲突到用户权限
  • 手机抓包配置全指南:从连不上到解密HTTPS
  • 从需求到交付:深度拆解企业级软件定制开发的标准化流程
  • 为什么你的渐变总像PPT?揭秘Midjourney v6.2中未公开的--color-bleed机制与渐变锚点定位技术
  • 别再到处找激活工具了!手把手教你用vlmcsd在Windows上自建KMS服务器(附防火墙配置)
  • 保姆级教程:用Arbe或大陆4D毫米波雷达点云数据,手把手实现Freespace检测(附Python伪代码)
  • 神经纹理:让3D世界“活”起来的AI魔法,一篇讲透!
  • Zookeeper集群启动失败?从myid配置到防火墙,保姆级排错指南来了
  • 语义优先架构:从VLM实验看90%功能漂移与具身AI新范式
  • 河北亮泽管道设备有限公司:2026年至今河北弹簧支吊架领域的优选实力服务商 - 2026年企业推荐榜
  • 无框架手写实现Function Calling:原理拆解+纯Python手写实现
  • Claude API文档版本管理生死线:v2.1→v3.0迁移实录,12个breaking change的文档同步策略
  • 别再乱格式化!一文搞懂NTFS、exFAT等磁盘格式区别与DiskGenius格式化实操