前段时间想写一些“水文”放到公众号上,内容可以从github找,就是排版比较麻烦,浪费了很长时间,经同事提起自动化工具,于是了解到了Playwright,它可以模拟人的操作行为,给我最直接的感受就是“解放双手,不需要再机械地在网页上点点点了”。
介绍
Playwright 是专门为了满足端到端测试的需求而创建的。Playwright 支持包括 Chromium、WebKit 和 Firefox 在内的所有现代渲染引擎。可以在 Windows、Linux 和 macOS 上本地或 CI 上进行测试,在 headless 或 headed 模式下进行,还可以进行原生移动仿真测试。
简单使用
1. 创建Maven项目
创建maven项目,方便在pom.xml中引入Playwright相关的依赖。
2. 项目命名
我这里简单命名为PlaywrightDemo,点击finish
3. 添加依赖
在pom.xml中添加Playwright所需要的依赖,添加依赖是这样的
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>PlaywrightDemo</artifactId>
<version>1.0-SNAPSHOT</version>
<!-- 下方是新加部分 -->
<dependencies>
<dependency>
<groupId>com.microsoft.playwright</groupId>
<artifactId>playwright</artifactId>
<version>1.32.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.10.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
<!-- 新加部分结束 -->
</project>
依赖设置完,点击右上角小图标Sync一下,拉取依赖
4. 写个例子
创建一个类文件,然后写个测试样例,初步了解一下
import com.microsoft.playwright.*;
public class MainTest {
/**
* 百度搜索"稀土掘金"
*/
public static void main(String[] args) {
// 创建一个chrome浏览器实例
try (Playwright playwright = Playwright.create()) {
// setHeadless:是否以可见的形式打开浏览器,默认是true,true是后台运行,一般需要调为false
Browser browser = playwright.chromium().launch(new BrowserType.LaunchOptions().setHeadless(false));
// 在浏览器上创建一个空白标签页
Page page = browser.newPage();
// 在空白标签页基础上输入百度网址并执行跳转
page.navigate("http://www.baidu.com");
// 在输入框输入稀土掘金
// 百度页面的输入框id为kw
page.locator("#kw").fill("稀土掘金");
// 点击"百度一下"
page.getByText("百度一下").click();
// 暂停10s看效果,要不然浏览器在执行完毕时会自动关闭
page.waitForTimeout(10000);
} catch (Exception e) {
e.printStackTrace();
}
}
}
运行一下,初次运行会下载内置浏览器。
然后搜索结果页面就被打开了
需要注意的是,每次运行Playwright会打开一个新的内置浏览器,该浏览器不会包含上次运行的任何信息,这可以确保运行结果的一致性。
自动生成代码
Playwright最主要的功能就是支持“录制回放”,可以把录制的过程生成代码,极大程度节省开发成本。
有两种使用方式,都需要借助命令行
- 方式1 需要配置node.js环境
npx playwright codegen --target java
- 方式2 需要配置python环境,mac系统自带
python3 -m playwright codegen --target java
命令输入后会出现两个面板,一个是浏览器,一个是代码生成器,在浏览器里做的操作会实时生成代码,如果想更改生成代码的语言可以点击Target区域自由选择。
API调用
Playwright提供了丰富的Api提供调用,我这里挑重点说一下,包括元素的定位、元素的一般操作、保存登录信息等。更多API见playwright.dev/java/docs/i…
1. 定位:Locator
定位器:能够定位到页面中具体某一个元素。只有知道了具体的元素是什么,才能对其进行做点击、长按等操作。
注意locator必须具有唯一性,否则会报错。
1.1 一般定位
<input id="test" name="input-name"></input>
// id定位
Locator locator1 = page.locator("#test");
// name属性定位
Locator locator2 = page.locator("input-name");
// 标签名定位
Locator locator3 = page.locator("input");
1.2 XPath定位
在浏览器检查中可以拿到元素的XPath,也具有唯一性,直接复制即可
Locator locator = page.locator("//*[@id="title-content"]/span[2]");
1.3 角色定位
Playwright把元素分为了多种角色,一般情况下是以标签名划分的,比如BUTTON、FORM、ARTICLE等
如果通过角色筛选出来的元素可能存在多个,还可以使用GetByRoleOptions属性过滤来保证结果唯一。
<h3>Sign up</h3>
<label>
<input type="checkbox" /> Subscribe
</label>
<br/>
<button>Submit</button>
Locator locator1 = page.getByRole(AriaRole.HEADING,new Page.GetByRoleOptions().setName("Sign up"));
Locator locator2 = page.getByRole(AriaRole.CHECKBOX,new Page.GetByRoleOptions().setName("Subscribe"));
Locator locator3 = page.getByRole(AriaRole.BUTTON,new Page.GetByRoleOptions().setName("Submit"));
1.4 标签定位
表单元素的控件常与label关联,Playwright支持通过label找到表单控件。
<label>密码 <input type="password" /></label>
可以通过标签定位
// 找到元素并直接输入
page.getByLabel("密码").fill("secret");
1.5 占位符定位
专属于input和textarea的定位方式,可以根据设置的playholder找到输入框控件
<input type="email" placeholder="请输入邮箱" />
// 找到填邮箱的输入框并输入“111234@163.com”
page.getByPlaceholder("请输入邮箱").fill("111234@163.com");
1.6 文字匹配定位
可以根据网页中显示的文字定位出具体的元素,包括但不限于普通文字、button上的文字、超链接上的文字。
<span>Hello World</span>
Locator locator = page.getByText("Hello World");
1.7 iframe内元素定位
在page中无法直接定位frame内的元素,需要先找到frame,再从frame中找其中元素。
<iframe name="iframe_name" src="http://127.0.0.1:8080/"
width="100%" height="500" frameborder="0"
allowfullscreen sandbox>
</iframe>
// 通过标签名称定位到frame,在定位到其中元素并点击
page.frameLocator("iframe").locator("xxxxx").click();
// 通过标签的name属性找到frame对象,再定位到其中元素并点击
Frame frame = page.frame("iframe_name");
frame.locator("xxxx").click();
当通过上方几种方式筛选出多个元素时,可附加一个option参数过滤,也可增加filter方法
Locator locator1 = page.locator("input", new Page.LocatorOptions().setHasText("姓名"))
Locator locator2 = page.locator("input").filter(new Locator.FilterOptions().setHasText("姓名"));
2. 操作:Action
2.1 点击
用于模仿点击DOM中的元素。
<button>Item</button>
// 点击一下鼠标左键
page.getByRole(AriaRole.BUTTON).click();
// 点击两下鼠标左键
page.getByText("Item").dblclick();
// 右键点击一下,左键同理
page.getByText("Item").click(new Locator.ClickOptions().setButton(MouseButton.RIGHT));
// 按住shift键的同时点击左键
page.getByText("Item").click(new Locator.ClickOptions().setModifiers(Arrays.asList(KeyboardModifier.SHIFT)));
// 光标停留
page.getByText("Item").hover();
// 点击元素左上角
page.getByText("Item").click(new Locator.ClickOptions().setPosition(0, 0));
2.2 按键
用于为DOM中的元素模仿按键操作。
<input id="press_key" placeholder="请输入内容"></input>
// 按压单个字符
page.locator("#press_key").press("b");
// 多个字符一起同时按压使用"+"
page.locator("#press_key").press("Meta+v");
目前支持的按键有:
Backquote, Minus, Equal, Backslash, Backspace, Tab, Delete, Escape,
ArrowDown, End, Enter, Home, Insert, PageDown, PageUp, ArrowRight,
ArrowUp, F1 – F12, 0 – 9, A – Z,Shift, Control, Alt(mac上的option键), Meta(mac的command键)
2.3 文字输入
用于为input标签
和textarea标签
填充数据。
<label>
请输入:
<textarea></textarea>
</label>
<label>
时间
<input id="input" type="time"></input>
</label>
// 文本输入框
page.getByLabel("请输入:").fill("你好啊");
// 时间输入框
page.locator("#input").fill("06:09");
2.4 选中
用于为radio标签
和checkbox标签
选择选中状态。
// 获取选择状态
page.getByLabel("Subscribe to newsletter").isChecked();
// 选择
page.getByLabel("XL").check();
注意,定位radio标签时需要注意,如下:page.getByText(“狮子”).check()会报错,因为拿到的只是文字,而不是单选框
<input type="radio" name="animal" />狮子
而对于对于label而言,拿到label就相当于拿到其中元素,如下。
<label>
苹果
<input type="radio" name="111" value="苹果" />
</label>
2.5 设置选项
用于为select标签
设置选中值。
<select id="select_options">
<option>汽车</option>
<option>自行车</option>
<option>马车</option>
</select>
page.locator("#select_options").selectOption("马车");
2.6 上传文件
<label>
上传
<input type="file" name="file" />
</label>
// 文件地址写相对路径时是相对于项目的相对路径
page.getByLabel("上传").setInputFiles(Paths.get("/Users/zeng/Desktop/工作/Demo/PlaywrightDemo/src/main/java/MainTest.java"));
2.7 下载文件
// 点击下载之后捕捉Download对象
Download download = page.waitForDownload(() -> {
page.getByText("Download file").click();
});
// 另存为at.txt
download.saveAs(Paths.get("/path/to/save/download/at.txt"));
3. 保存登录信息
由于Playwright每次都会新开一个没有任何缓存的浏览器,如果涉及到登录的话,每次运行都要登录一次,比较麻烦,因此Playwright提供了一种保存浏览器本地存储信息的方式。
// 让page复用存储的信息
BrowserContext context = browser.newContext(new Browser.NewContextOptions().setStorageStatePath(Paths.get("state.json")));
Page page = context.newPage();
// ...
// 操作完成之后再把最新的本地存储信息保存下来,保存到state.json中
context.storageState(new BrowserContext.StorageStateOptions().setPath(Paths.get("state.json")));
参考资料: