简介:这份PDF面向Python自动化测试初学者与转型中的测试工程师,聚焦Playwright框架的入门与环境搭建,帮助读者在Selenium之外快速建立新的技术选型认知。内容从Selenium 1.0到4.0的发展脉络讲起,梳理Cypress、Puppeteer、TestCafe等后Selenium时代框架的定位差异,并说明Playwright支持Chromium、Firefox、WebKit且API统一的优势。随后进入实操层面,涵盖pip安装playwright、浏览器驱动配置、同步API启动浏览器访问网页、headless无界面模式、智能等待机制,以及录制生成脚本、page.pause()断点调试与Playwright Inspector定位元素等调试手段。资源包为单个PDF文件,约916KB,轻量易读,适合作为系统学习的第一章入口。目前已有2092人学习,读者可借此快速完成环境准备、跑通基础脚本,并掌握录制与调试的排错思路,为后续复杂测试任务打下基础。
1. 从 Selenium 到 Playwright:一份 PDF 到底能不能帮你把环境跑通
如果你最近在搜 Python 自动化测试,大概率会刷到 Playwright 这个名字。它 2020 年由微软开源,支持 Chromium、Firefox、WebKit 三大渲染引擎,提供 Python、Node.js、Java、.NET 四种语言绑定。和 Selenium 最大的区别在于:Playwright 内置了浏览器二进制和通信协议,不需要你再去折腾 chromedriver、geckodriver 的版本匹配。这份《Playwright+Python 自动化测试》第一章 PDF,覆盖的就是从 Selenium 发展史到 Playwright 环境搭建、快速上手、录制脚本、断点调试的完整入门链路。适合两类人:一是被 Selenium 驱动版本搞到崩溃、想换一套更省心方案的测试工程师;二是刚接触自动化、想找一个能快速看到效果的切入点的 Python 开发者。但 PDF 终究是静态的,环境能不能跑通、录制出来的脚本能不能直接用、断点调试到底怎么操作,这些才是决定你留不留下来的关键。下面我按实际动手的顺序,把这份资料里的核心内容拆开讲一遍。
2. 环境准备:pip install 之后那一步才是分水岭
2.1 为什么 Playwright 不需要你手动配驱动
Selenium 时代最让人头疼的一件事就是驱动版本对齐。Chrome 升到 120,你手里的 chromedriver 还是 119,启动直接报 session not created。Playwright 的做法是把浏览器二进制和驱动逻辑一起打包,通过playwright install命令下载三个内置浏览器到本地缓存目录。Python 端只负责发指令,底层通信走的是 Playwright 自己维护的协议层,不依赖外部 driver。这也是为什么这份资料里反复强调“不需要安装驱动包了”——它确实解决了 Selenium 最频繁的翻车点。
但注意,playwright install下载的三个浏览器(Chromium、Firefox、WebKit)加起来大概几百 MB,国内网络环境下可能需要几分钟。如果中途断了,重新执行一次命令即可,它会续传已下载的部分。
2.2 安装步骤与版本约束
资料里给出的版本要求是 Python 3.7+,推荐 3.8。Playwright 库本身对 Python 版本的要求随着版本迭代会变,但 3.8 以上基本不会出问题。安装分两步:
# 第一步:安装 Playwright Python 包 pip install playwright # 第二步:下载内置浏览器(Chromium、Firefox、WebKit) playwright install这两步做完,环境就算齐了。但实际动手时有两个常见报错需要提前知道:
报错一:缺少 Visual C++ 运行库。现象是playwright install执行到一半提示 DLL 加载失败,或者运行脚本时报Dll load failed while importing _greenlet。原因是 Playwright 底层依赖的 greenlet 库需要 VC++ Redistributable。解决办法是安装 Microsoft Visual C++ Redistributable 2019,装完重启终端再试。
报错二:pip 安装超时。现象是pip install playwright卡在下载阶段。常见做法是换国内镜像源:
pip install playwright -i https://pypi.tuna.tsinghua.edu.cn/simple提示:
playwright install下载的浏览器存放在用户目录下的缓存文件夹里,不在你的项目目录中。如果换电脑,需要重新执行这一步。
2.3 验证环境是否真的可用
装完之后别急着写复杂脚本,先用最小代码验证一遍。资料里给的快速体验代码是这样的:
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://www.baidu.com") # 打印页面标题,验证页面确实加载了 print(page.title()) # 关闭浏览器 browser.close()这段代码的逻辑很直白:sync_playwright()创建一个 Playwright 上下文管理器,p.chromium.launch()启动 Chromium 实例,browser.new_page()开标签页,page.goto()导航。关键参数是headless,默认值是True,也就是不显示浏览器窗口。调试阶段建议显式写成headless=False,能看到浏览器在做什么,心里有底。
如果这段代码能打印出百度首页的标题,说明环境没问题。打印不出来或者报错,优先检查playwright install是否完整执行过。
3. 快速开始:同步、异步和 headless 到底怎么选
3.1 同步 API 和异步 API 的适用边界
Playwright 的 Python 绑定同时提供同步和异步两套 API。资料里给了两种写法,但没说清楚什么时候该用哪个。我的经验是:如果你在写独立的自动化脚本、做页面巡检、跑数据采集,用同步 API 就够了,代码直观、调试方便。如果你在 FastAPI、aiohttp 这类异步框架里集成浏览器操作,或者需要同时控制多个页面并发执行,那就用异步 API。
同步写法就是上面那段with sync_playwright() as p的结构。异步写法长这样:
import asyncio from playwright.async_api import async_playwright async def main(): async with async_playwright() as p: # 异步模式下所有操作都需要 await browser = await p.chromium.launch(headless=False) page = await browser.new_page() await page.goto("https://www.baidu.com") # title() 也是异步方法,需要 await print(await page.title()) await browser.close() asyncio.run(main())两套 API 的方法名基本一一对应,区别就是异步版本每个调用前要加await。如果你不习惯with语句,还可以用start()和stop()手动管理生命周期:
from playwright.sync_api import sync_playwright playwright = sync_playwright().start() browser = playwright.chromium.launch(headless=False) page = browser.new_page() page.goto("https://www.baidu.com/") browser.close() playwright.stop()这种写法在需要把 Playwright 实例作为参数传递时比较灵活,但日常脚本用with更省心。
3.2 headless 模式与 slow_mo 参数
Playwright 默认以 headless 模式运行,也就是不弹出浏览器窗口。这在 CI 环境或者服务器上跑批量任务时是合理的,因为不需要图形界面。但调试阶段你什么都看不到,出了问题只能靠日志猜。所以资料里建议调试时传headless=False。
另一个实用参数是slow_mo,单位是毫秒。它的作用是在每个操作之间插入等待间隔,让你能看清页面上的动作顺序:
from playwright.sync_api import sync_playwright with sync_playwright() as p: # slow_mo=50 表示每个操作间隔 50 毫秒 browser = p.chromium.launch(headless=False, slow_mo=50) page = browser.new_page() page.goto("https://www.baidu.com") print(page.title()) # 在搜索框输入关键词 page.fill('#kw', "Python 自动化测试") # 点击搜索按钮 page.click('#su') browser.close()slow_mo的作用范围是全局的,从启动浏览器到每个元素操作都会生效。调试时设 50 到 200 比较合适,设太大反而浪费时间。
3.3 等待机制:为什么 time.sleep 在这里不能用
这是新手最容易踩的坑。Selenium 时代很多人习惯用time.sleep(5)来等页面加载,但在 Playwright 里这样做会出问题。原因是 Playwright 内部依赖异步事件循环,time.sleep()会阻塞整个线程,导致 Playwright 的事件处理无法正常执行。资料里明确说了:用page.wait_for_timeout(5000)代替time.sleep(5)。
from playwright.sync_api import sync_playwright with sync_playwright() as p: browser = p.chromium.launch(headless=False, slow_mo=1000) page = browser.new_page() page.goto("https://www.baidu.com") print(page.title()) # 等待 5 秒,使用 Playwright 提供的等待方法 page.wait_for_timeout(5000) page.fill('#kw', "Python 自动化测试") page.click('#su') browser.close()但更重要的一个认知是:Playwright 在查找元素时自带自动等待。也就是说,page.click('#su')执行时,如果按钮还没出现,它会自动等待元素变为可操作状态,不需要你手动加等待。wait_for_timeout只在调试阶段用来暂停观察,不应该出现在正式脚本里。
注意:
wait_for_timeout的参数单位是毫秒,不是秒。写 5000 才是 5 秒。
4. 录制生成脚本:codegen 能帮你省多少事
4.1 启动录制与基本操作流程
Playwright 的 codegen 功能是它区别于 Selenium 的一个亮点。你不需要手写定位器,直接在浏览器里操作,它自动生成对应的代码。启动命令:
playwright codegen http://127.0.0.1:8000/login.html执行后会弹出两个窗口:左边是浏览器,你正常操作;右边是 Playwright Inspector,实时显示生成的代码。以登录流程为例,在页面上输入用户名、密码、点击登录按钮,Inspector 里就会生成类似这样的代码:
from playwright.sync_api import Playwright, sync_playwright, expect def run(playwright: Playwright) -> None: browser = playwright.chromium.launch(headless=False) context = browser.new_context() page = context.new_page() page.goto("http://127.0.0.1:8000/login.html") # get_by_placeholder 是 Playwright 推荐的定位方式 page.get_by_placeholder("请输入用户名").click() page.get_by_placeholder("请输入用户名").fill("yoyo") page.get_by_placeholder("请输入密码").click() page.get_by_placeholder("请输入密码").fill("aa123456") page.get_by_role("button", name="立即登录 >").click() # --------------------- context.close() browser.close() with sync_playwright() as playwright: run(playwright)生成的代码里用的是get_by_placeholder和get_by_role这类语义化定位器,比 XPath 和 CSS Selector 可读性高很多。fill()用于输入文本,click()用于点击,这两个是最常用的操作。
4.2 录制命令的实用参数
codegen 支持不少参数来模拟不同环境。资料里列了几个常用的:
| 参数 | 作用 | 示例 |
|---|---|---|
--viewport-size | 设置浏览器视口大小 | playwright codegen --viewport-size=800,600 网址 |
--device | 模拟移动设备 | playwright codegen --device="iPhone 11" 网址 |
--color-scheme | 模拟配色方案 | playwright codegen --color-scheme=dark 网址 |
--timezone | 设置时区 | playwright codegen --timezone="Europe/Rome" 网址 |
--geolocation | 设置地理位置 | playwright codegen --geolocation="41.89,12.49" 网址 |
--lang | 设置语言 | playwright codegen --lang="it-IT" 网址 |
--save-storage | 保存登录状态 | playwright codegen --save-storage=auth.json 网址 |
--load-storage | 加载登录状态 | playwright codegen --load-storage=auth.json 网址 |
--device的值必须用双引号包起来,并且区分大小写。--save-storage和--load-storage配合使用可以跳过重复登录:先用--save-storage录一次登录流程,把 cookie 和 localStorage 存到 auth.json,后续录制或运行脚本时用--load-storage加载,就直接是登录状态了。
4.3 生成 pytest 代码与 page.pause() 断点
如果你在做自动化测试而不是写一次性脚本,codegen 还能直接生成 pytest 格式的代码:
from playwright.sync_api import Page, expect def test_example(page: Page) -> None: page.goto("http://127.0.0.1:8000/login.html") page.get_by_placeholder("请输入用户名").click() page.get_by_placeholder("请输入用户名").fill("yoyo") page.get_by_placeholder("请输入密码").click() page.get_by_placeholder("请输入密码").fill("aa123456") page.get_by_role("button", name="立即登录 >").click()这个函数可以直接放进 pytest 项目里跑,page参数由 Playwright 的 pytest 插件注入。
另一个调试利器是page.pause()。在脚本里任意位置插入这行代码,执行到那里时会暂停,并打开 Inspector 窗口。你可以在暂停状态下检查页面元素、查看选择器、单步执行后续操作。这在处理复杂交互或者定位不稳定的元素时特别有用。
from playwright.sync_api import sync_playwright with sync_playwright() as p: browser = p.chromium.launch(headless=False) page = browser.new_page() page.goto("http://127.0.0.1:8000/login.html") # 在这里暂停,打开 Inspector 进行调试 page.pause() page.get_by_placeholder("请输入用户名").fill("yoyo") browser.close()5. 避坑与排查:那些文档里没写清楚的细节
5.1 现象:playwright install 卡住不动
原因:默认从海外 CDN 下载浏览器二进制,国内网络环境下速度极慢甚至超时。
解决:设置环境变量指向国内镜像源后再执行安装。常见做法是在终端里先设置PLAYWRIGHT_DOWNLOAD_HOST,然后重新运行playwright install。如果已经下载了一部分,重新执行会续传,不会从头开始。
5.2 现象:脚本在本地能跑,放到 CI 上就报错
原因:CI 环境通常是 Linux 容器,缺少 Chromium 运行所需的系统依赖库(如 libnss3、libatk 等)。
解决:在 CI 配置里加上依赖安装步骤。Playwright 提供了playwright install-deps命令来自动安装系统依赖:
# 安装浏览器 playwright install # 安装系统依赖(Linux 环境需要) playwright install-deps注意:
install-deps需要 root 权限,在 Dockerfile 里用RUN指令执行时要确保用户权限正确。
5.3 现象:codegen 生成的定位器换台机器就失效
原因:codegen 优先使用get_by_placeholder、get_by_role这类语义化定位器,但如果页面元素的 placeholder 或 role 属性是动态生成的,换一个环境可能就变了。
解决:录制完成后手动检查定位器,对于动态属性,改成基于稳定文本或测试 ID 的定位方式。Playwright 推荐在开发阶段就给关键元素加上>import pytest from playwright.sync_api import Page, expect # conftest.py 里定义 fixture @pytest.fixture(scope="session") def auth_state(browser): """登录一次,保存状态,后续测试复用""" context = browser.new_context() page = context.new_page() page.goto("http://127.0.0.1:8000/login.html") page.get_by_placeholder("请输入用户名").fill("yoyo") page.get_by_placeholder("请输入密码").fill("aa123456") page.get_by_role("button", name="立即登录 >").click() # 等待登录完成,保存存储状态 page.wait_for_url("**/dashboard") context.storage_state(path="auth.json") context.close() # test_login.py 里用存储状态跳过登录 @pytest.fixture(scope="session") def logged_in_page(browser, auth_state): context = browser.new_context(storage_state="auth.json") page = context.new_page() yield page context.close() def test_dashboard_title(logged_in_page: Page): logged_in_page.goto("http://127.0.0.1:8000/dashboard") # 用 expect 做自动重试断言 expect(logged_in_page).to_have_title("控制台")
这里的关键改动有几个:第一,用context.storage_state()保存登录后的 cookie 和 localStorage,后续测试通过storage_state参数加载,避免每个用例都重新登录。第二,用expect()做断言,它自带重试机制,比assert更适合动态页面。第三,fixture 的 scope 设为 session,整个测试会话只登录一次。
另一个实用技巧是处理 iframe 和 Shadow DOM。Playwright 的选择器默认会穿透 Shadow DOM,但 iframe 需要显式切换:
# 定位 iframe 内的元素 frame = page.frame_locator("#my-iframe") frame.get_by_role("button", name="提交").click()frame_locator返回的是一个定位器作用域,后续操作都在这个 iframe 内查找,不需要手动 switch_to。
最后说一个我踩过的坑:codegen 录制时如果页面加载慢,生成的代码里可能会插入page.wait_for_timeout()。这些硬等待在正式运行时会让整个测试套件变慢。我的习惯是录制完成后全局搜索wait_for_timeout,能删的删掉,删不掉的改成wait_for_selector或wait_for_url这类条件等待。从那以后我每次用 codegen 生成脚本,都会先过一遍等待逻辑再提交到仓库。希望帮到你。
本文还有配套的精品资源,点击获取