检查页面、填写表单、核对数据、截图留档,这些工作常常重复发生。
手工操作容易遗漏,临时录制的脚本又容易在页面改版后失效:按钮位置变了,加载慢了一点,或者登录过期了,后面的步骤就不再可信。
Playwright 是一个面向网页测试和自动化的开源项目,可以通过统一 API 操作 Chromium、Firefox 和 WebKit。
它的价值不只是“替人点鼠标”,而是把浏览器操作、状态判断和结果证据组织成可重复执行的程序。
本文使用 Node.js / TypeScript 与 Playwright Test 举例。代码包含本地模拟页面,不登录真实商城、不提交真实订单。脚本是教学示例,不是已完成的生产项目或跨浏览器验收报告。
一、哪些工作适合做网页自动化?
可以从规则明确、重复频繁、结果可核对的小任务开始:
- 网站改版后的导航、搜索和详情页回归。
- 多个尺寸下的页面截图与布局检查。
- 测试环境的表单校验和业务流程验证。
- 经授权的后台数据核对、文件下载和例行操作。
- 对没有合适接口的系统做有限、可控的页面操作。
如果系统已经提供稳定 API,数据读写通常应优先考虑 API;浏览器更适合验证用户真正看到和操作的界面。
验证码绕过、未授权采集、批量骚扰和规避站点限制,不应成为自动化脚本的正常目标。
二、Playwright Library 和 Playwright Test 怎么选?
两者有关联,但用途不完全相同。
- Playwright Library 提供浏览器控制能力,适合嵌入已有程序或编写独立自动化任务。
- Playwright Test 是测试框架,在浏览器操作之外提供测试组织、断言、隔离、报告、重试和追踪等能力。
下面的示例用 Playwright Test,因为它便于说明“操作完成后如何验证”,也方便按不同设备配置运行。
不要把所有自动化任务都硬写成测试,也不要为了一个临时操作就省略结果验证。形式可以不同,边界和证据不能少。
三、先搭一个最小环境
在空目录中执行官方初始化命令:
npm init playwright@latest
按提示选择 TypeScript。浏览器可以在初始化时安装,也可以稍后安装,例如只安装本例需要的 Chromium:
npx playwright install chromium
Node.js 版本、操作系统依赖和浏览器支持范围以当前官方文档为准。Linux 环境还可能需要相应系统依赖,不宜把一台电脑上的安装步骤当成所有机器的完整方案。
项目可以先保持简单:
playwright.config.ts
tests/
└── product.spec.ts
下面是一个配置示例。它只使用 Chromium,分别模拟桌面与手机视口:
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
testDir: './tests',
timeout: 30_000,
retries: 0,
reporter: 'html',
use: {
trace: 'retain-on-failure',
screenshot: 'only-on-failure',
},
projects: [
{
name: 'desktop-chromium',
use: { ...devices['Desktop Chrome'] },
},
{
name: 'mobile-chromium',
use: { ...devices['Pixel 7'] },
},
],
});
设备模拟不等于真机测试,使用 Chromium 也不代表已经验证 Firefox、WebKit 或 iPhone Safari。需要相应覆盖时,应另行配置、安装浏览器并执行检查。
四、先写一个不会碰真实业务的脚本
下面通过请求拦截返回一段模拟商品页。shop.test 是测试地址,这个页面的 HTML 由脚本提供,不依赖真实商城。
保存为 tests/product.spec.ts:
import { test, expect } from '@playwright/test';
const demoPage = `
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>商品预览示例</title>
<style>
body { margin: 24px; font: 16px/1.8 sans-serif; }
main { max-width: 600px; }
label { display: block; margin: 12px 0; }
input, select, button { font: inherit; max-width: 100%; }
</style>
</head>
<body>
<main>
<h1>帆布收纳袋</h1>
<label>颜色
<select id="color">
<option value="natural">原色</option>
<option value="green">深绿色</option>
</select>
</label>
<label>数量
<input id="quantity" type="number" min="1" max="10" value="1">
</label>
<button type="button" id="preview">预览订单</button>
<p role="status">等待选择</p>
</main>
<script>
document.querySelector('#preview').addEventListener('click', () => {
const color = document.querySelector('#color');
const quantity = document.querySelector('#quantity');
document.querySelector('[role="status"]').textContent =
color.options[color.selectedIndex].text + ' × ' + quantity.value;
});
</script>
</body>
</html>
`;
test('选择规格后生成正确预览', async ({ page }, testInfo) => {
await page.route('https://shop.test/product/demo', async route => {
await route.fulfill({
status: 200,
contentType: 'text/html; charset=utf-8',
body: demoPage,
});
});
await page.goto('https://shop.test/product/demo');
await expect(page.getByRole('heading', { name: '帆布收纳袋' }))
.toBeVisible();
await page.getByLabel('颜色').selectOption({ label: '深绿色' });
await page.getByLabel('数量').fill('2');
await page.getByRole('button', { name: '预览订单' }).click();
await expect(page.getByRole('status')).toHaveText('深绿色 × 2');
await page.screenshot({
path: testInfo.outputPath('product-preview.png'),
fullPage: true,
});
});
运行测试和打开报告:
npx playwright test
npx playwright show-report
这个例子验证了“选择规格 → 触发预览 → 检查结果”的闭环。配置中有两个项目,因此会分别按桌面和手机配置执行。
它没有验证真实库存、支付或后台接口;截图也只是留存证据,不是自动视觉差异比对。正式项目需要接入实际页面并补齐对应断言。
五、脚本稳定,首先靠定位和等待
1. 优先使用用户能理解的定位方式
例如:
page.getByRole('button', { name: '保存设置', exact: true });
page.getByLabel('邮箱');
page.getByTestId('order-summary');
角色、可访问名称和明确的测试标识,通常比一长串 DOM 路径更容易维护。
像 div:nth-child(3) > div:nth-child(2) > button 这样的选择器,可能在增加一块提示信息后就失效。
页面有多个同名按钮时,应缩小到明确区域,不要随手加 .first() 掩盖定位歧义。
2. 等待状态,不要靠固定睡眠碰运气
不建议把流程写成:
await page.waitForTimeout(3000);
然后假设数据已经加载。
Playwright 会在执行相关动作前检查可操作条件,定位器也能在使用时重新查找元素。但它不知道你的业务何时完成,所以仍需要明确断言:
await expect(page.getByRole('status')).toHaveText('保存成功');
这种 Web 断言会在超时范围内重试检查。反过来,先取一次文本再用普通同步断言比较,不会自动获得同样的等待行为。
自动等待解决的是一部分时序问题,不会自动证明业务正确。
六、登录态、失败与定时任务要怎样处理?
登录态是凭证,不是普通测试附件
Playwright 可以保存和复用浏览器状态,例如:
await context.storageState({ path: 'playwright/.auth/user.json' });
这个动作应放在完成真实授权登录之后。状态可能包含可用于访问账户的 Cookie 或令牌,不能提交到公开仓库。
建议忽略:
playwright/.auth/
playwright-report/
test-results/
状态会过期,也不保证所有应用的认证信息都能按同一种方式恢复。正式脚本要检查登录是否有效,必要时重新授权;不要在失败后无限重试密码、验证码或二次验证。
失败重试不能代替故障定位
脚本失败后,优先保存 Trace、截图和必要日志,查清是定位错误、登录失效、业务失败还是环境问题。
报告与 Trace 也可能包含页面数据或敏感信息,应控制保存期限和访问权限。
对创建订单、发送消息等有副作用的操作,重试前要确认上次是否已经成功,必要时采用业务幂等标识和结果查询。不能把“再点一次”当成通用恢复策略。
定时执行是另一层能力
Playwright 负责浏览器流程,任务计划程序、CI 或其他调度器负责何时运行。
还需要考虑:运行账户、环境变量、工作目录、并发锁、超时、日志和告警。桌面上成功一次,不代表无人值守就能长期稳定执行。
七、接到定制需求,先问清这些事
“做一个自动操作网站的脚本”还不足以评估范围。
至少要确认:
- 目标系统是谁维护的,是否已获得自动化授权。
- 从哪个状态开始,到什么结果结束。
- 哪些操作只读,哪些会写入或对外发送。
- 是否有测试环境、专用账户和安全测试数据。
- 是否需要登录、验证码、下载或文件上传。
- 运行频率、浏览器与设备覆盖范围是什么。
- 失败后停止、重试还是转人工,证据保存在哪里。
- 页面改版、账户过期后由谁维护。
这不是额外的文书工作,而是在区分“能跑的演示”和“可以交付的工具”。
八、一份可靠的脚本,应该交付什么?
除了代码,建议至少包含:
- 安装、浏览器依赖和运行说明。
- 配置项与环境变量示例,不包含真实密码。
- 输入输出定义,以及成功判定条件。
- 正常、异常和权限边界的测试记录。
- 截图、Trace 和报告的获取与清理方法。
- 定位规则、依赖版本与维护说明。
- 明确的操作授权范围和人工接管条件。
如果需要检查整站,也应按首页、列表、详情、表单等页面类型分组,而不是只打开首页截一张图就宣称验收完成。
写在最后
网页自动化最难的部分,往往不是如何点击,而是如何知道该点击哪个元素、何时继续,以及做完之后是否真的成功。
先选择一个可隔离的小流程,用稳定定位描述操作,用断言确认结果,用记录保留证据。再逐步加入登录、批量、异常处理和调度。
把“看起来跑完了”,变成“可以说明为什么成功、失败后也能定位”。 这才是 Playwright 脚本从演示走向交付的关键。
参考资料
以上示例用于说明设计方法。依赖、支持环境和认证行为请以使用版本的官方文档为准。
转载请注明:TUTERM.COM » 告别重复点击:用 Playwright 自动操作网页
