0. PlayWright简介
PlayWright与Selenium 相比,具有Api更灵活、无需浏览器Driver 的特点,特别是在当下AI盛行的时代,使用PlayWright 进行自动化测试已为WEB研发人员必需了解的技能。

PlayWright由微软发起,其开源地址为:https://github.com/microsoft/playwright。
PlayWright 支持 Chromium, Firefox, WebKit on Linux这些主流浏览器,且支持多种语言的API,如:Python ,.NET , Java ,Node.js等。
在本文中,将使用PlayWright 配合服务器中的Java程序 ,通过具体示例的方式,完成对PlayWright的熟悉。
1. PlayWright简单使用(控制本地浏览器)
以让PlayWright 打开一个URL为例,演示一下它的用法。
假设需要打开的URL为:http://bilibili.com/video/BV1oN7A67EFU,这里使用的编程语言为java。
使用前,先在在pom文件 中引入playwright的依赖:
xml
<dependency>
<groupId>com.microsoft.playwright</groupId>
<artifactId>playwright</artifactId>
<version>1.59.0</version>
</dependency>
再编写以下代码并运行:
java
try (Playwright playwright = Playwright.create()) {
// 1. 获取 Chromium 浏览器
BrowserType chromium = playwright.chromium();
// 2. 启动浏览器
// headless(false) 表示显示浏览器窗口,方便你观察
Browser browser = chromium.launch();
// 3. 新建页面
Page page = browser.newPage();
// 4. 打开页面
String url = "https://www.bilibili.com/video/BV1oN7A67EFU";
System.out.println("正在打开页面:" + url);
page.navigate(url);
// 5. 等待页面加载
page.waitForLoadState();
Thread.sleep(3_000);
// 6. 输出页面信息
System.out.println("页面已打开");
System.out.println("当前 URL:" + page.url());
System.out.println("页面标题:" + page.title());
// 7. 关闭浏览器
browser.close();
System.out.println("浏览器已关闭");
}
运行结果为:

从运行结果可以看出,它成功打开了指定的URL,并将标题输出到了控制台中。
在整个运行过程中,它没有打开界面,这是因为默认用的是chromium 的无头模式 ,如需要查看到界面,可以将headless 设置为false,这样就可以看到具体的界面,以方便观察了。
2. PlayWright简单使用(控制远程浏览器)
有时,我们需要在我们的服务中调用PlayWright ,但服务中是没有部署浏览器的(如linux中以docker方式运行的java程序),这时就需要用到PlayWright 的远程模式。

依旧使用上面的示例功能,这时需要将代码进行改造:
java
try (Playwright playwright = Playwright.create()) {
// 1. 获取远程 Chromium 浏览器
// 2. 启动浏览器
Browser browser = playwright.chromium().connect("ws://192.168.140.110:3000");
// 3. 新建页面
Page page = browser.newPage();
// 4. 打开页面
String url = "https://www.bilibili.com/video/BV1oN7A67EFU";
System.out.println("正在打开页面:" + url);
page.navigate(url);
// 5. 等待页面加载
page.waitForLoadState();
Thread.sleep(3_000);
// 6. 输出页面信息
System.out.println("页面已打开");
System.out.println("当前 URL:" + page.url());
System.out.println("页面标题:" + page.title());
// 7. 关闭浏览器
browser.close();
System.out.println("浏览器已关闭");
}
其中connect 中的参数ws://192.168.140.110:3001是PlayWright容器的地址,如我这里是以Docker启动的,命令为:
docker run -p 3000:3000 --rm --init -it --workdir /home/pwuser --user pwuser mcr.microsoft.com/playwright:v1.59.0-noble /bin/sh -c "npx -y playwright@1.59.0 run-server --port 3000 --host 0.0.0.0"
在上面这个playwright 的容器中,它内置了一个playwright 运行所需要的默认浏览器。(https://playwright.dev/docs/browsers#install-browsers)
上面的java程序运行结果为:

从运行结果看到,它和本地启动的PlayWright没有什么区别。
但需要注意的是,如果使用PlayWright的远程模式 时,需要在JAVA程序的POM中添加以下配置:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<requiresUnpack>
<dependency>
<groupId>com.microsoft.playwright</groupId>
<artifactId>driver-bundle</artifactId>
</dependency>
</requiresUnpack>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
并将java容器的docker镜像构建时的form 修改为FROM eclipse-temurin:21-jre-jammy,这样拥有更多的内置包,避免运行时缺少相关依赖。
3. playwright-mcp与chrome-devtools-mcp应用场景
最后,本文中提到了很多PlayWright ,那我们也需要了解一下它和chrome-devtools 的区别和应用场景。
在PlayWright 与诸如chrome 这样的浏览器通信时,它也是使用的Chrome DevTools Protocol 通信协议,但PlayWright 的API包装性更好。
为便于理解,可用下图展示:

同时,随着AI工具的普及,playwright 和chrome 也都有各自对应的mcp ,分别为:playwright-mcp和chrome-devtools-mcp,它们都可以添加到相关的AI工具中。使用时,它们的使用区别也主要一个更适合用于测试业务流程 ,另一个适合用于单一事件。
这里以这两个MCP的实际使用示例,看一下它们的区别,先确保已经安装了这两个mcp,我这里使用的AI工具是claude code:

3.1 playwright-mcp使用示例
现在让playwright-mcp 和chrome-devtools-mcp都完成同一件事,看一下区别。
任务为:打开https://blog.csdn.net/puhaiyang这个博客地址,并获取出这个博客中最新文章的标题
当使用playwright-mcp时,首次使用这样发送提示词:
使用 Playwright MCP 打开 https://blog.csdn.net/puhaiyang,
获取页面中最新一篇文章的标题。
要求:
1. 打开页面;
2. 等待文章列表加载完成;
3. 获取文章列表第一篇文章标题;
4. 输出标题;
5. 如果可以,顺便生成一段 Playwright 脚本。
之后,当有了playwright的脚本之后,后面再去完成这个任务,就可直接让AI完成这个任务了,如:
运行get-csdn-latest-article.js,完成这个任务
其中的get-csdn-latest-article.js中的内容为:
node.js
/**
* 获取 CSDN 博主最新一篇文章标题
* 使用方式:
* 1. 安装依赖: npm init -y && npm install playwright
* 2. 运行脚本: node get-csdn-latest-article.js [博主ID]
* 示例: node get-csdn-latest-article.js puhaiyang
*/
const { chromium } = require('playwright');
async function getLatestArticleTitle(username = 'puhaiyang') {
const browser = await chromium.launch({ headless: true });
const context = await browser.newContext({
userAgent:
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) ' +
'AppleWebKit/537.36 (KHTML, like Gecko) ' +
'Chrome/120.0.0.0 Safari/537.36',
});
const page = await context.newPage();
const url = `https://blog.csdn.net/${username}`;
console.log(`正在访问: ${url}`);
await page.goto(url, { waitUntil: 'domcontentloaded' });
// 等待文章列表加载完成(CSDN 文章块 class 为 blog-list-box)
await page.waitForSelector('article.blog-list-box', { timeout: 20000 });
// 取第一篇文章标题(CSDN 标题在 h4 内)
let title;
try {
title = await page
.locator('article.blog-list-box')
.first()
.locator('h4')
.first()
.innerText();
} catch (e) {
// 兜底:直接取 article 内文本
title = await page
.locator('article.blog-list-box')
.first()
.innerText();
}
console.log('==================================================');
console.log(`博主 ${username} 的最新文章标题: ${title.trim()}`);
console.log('==================================================');
await browser.close();
return title.trim();
}
// 从命令行参数读取博主 ID,默认 puhaiyang
const targetUser = process.argv[2] || 'puhaiyang';
getLatestArticleTitle(targetUser).catch((err) => {
console.error('执行失败:', err);
process.exit(1);
});
运行结果为:

3.2 chrome-devtools-mcp使用示例
当使用chrome-devtools-mcp时,发送的提示词为:
使用 Chrome DevTools MCP 打开 https://blog.csdn.net/puhaiyang,并获取页面中最新一篇文章的标题
输出结果为:

3.3 playwright-mcp/chrome-devtools-mcp应用场景总结
从上面3.1 和3.2 两个示例可以看到,这两个mcp的输出结果是一致的,但如果有了playwright 的脚本之后再去执行某个任务,与全描述chrome-devtools-mcp的提示词相比,它的执行速度会更快,且消耗最少的token,对于业务功能测试的场景更为合适。
而对于一次性场景和单一功能性能分析的场景,chrome-devtools-mcp就更合适。