Playwright
快速入门
1. 简介
Playwright 是微软开发的Web应用的自动化测试框架。
Playwright 可以使用NodeJS和Python语言进行编写。
与Selenium的区别
- Selenium 只提供了 web 自动化功能。如果你做自动化测试,需要结合其他自动化测试框架,而 playwright 是面向自动化测试的,除了 web 自动化功能,它也包含了自动化测试的功能框架。
- 两者的自动化原理有些差别
2. 安装
pip install playwright
出现以下信息表示安装完成:
C:\Windows\system32>pip install playwright
Looking in indexes: https://pypi.tuna.tsinghua.edu.cn/simple/
Collecting playwright
Downloading https://pypi.tuna.tsinghua.edu.cn/packages/46/4f/9ba607fa94bb9cee3d4beb1c7b32c16efbfc9d69d5037fa85d10cafc618b/playwright-1.55.0-py3-none-win_amd64.whl (35.5 MB)
---------------------------------------- 35.5/35.5 MB 6.1 MB/s eta 0:00:00
Collecting pyee<14,>=13 (from playwright)
Downloading https://pypi.tuna.tsinghua.edu.cn/packages/9b/4d/b9add7c84060d4c1906abe9a7e5359f2a60f7a9a4f67268b2766673427d8/pyee-13.0.0-py3-none-any.whl (15 kB)
Collecting greenlet<4.0.0,>=3.1.1 (from playwright)
Downloading https://pypi.tuna.tsinghua.edu.cn/packages/d8/0f/30aef242fcab550b0b3520b8e3561156857c94288f0332a79928c31a52cf/greenlet-3.2.4-cp311-cp311-win_amd64.whl (299 kB)
---------------------------------------- 299.1/299.1 kB 6.1 MB/s eta 0:00:00
Collecting typing-extensions (from pyee<14,>=13->playwright)
Downloading https://pypi.tuna.tsinghua.edu.cn/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl (44 kB)
---------------------------------------- 44.6/44.6 kB ? eta 0:00:00
Installing collected packages: typing-extensions, greenlet, pyee, playwright
安装playwright后,运行以下命令来安装浏览器:
playwright install chromium
3. 自动化代码助手
Playwright内置了代码助手,可以自动生成代码。 输入以下命令,即可启动代码助手:
playwright codegen
注意:代码助手主要是记录人对页面的输入,并不能取代人自己写代码,特别是获得页面上的信息的代码。(比如打印标题栏就没有办法自动生成)
page.wait_for_timeout(1000) 单位:ms
4. 跟踪功能
Playwright有个特色功能:跟踪(tracing) 启动跟踪功能后,可以再执行自动化后,通过记录的跟踪数据文件,回看自动化过程中的每个细节。
执行完成后,会再当前工作目录生成一个trace.zip的跟踪数据文件。 查看这个文件有两种方式:
- 直接访问
https://trace.playwright.dev/这个网站,上传跟踪文件。 - 执行命令
playwright show-trace trace.zip,在本地打开查看。
定位
Web界面自动,要对界面进行操作,首先需要定位界面元素。 我们需要让浏览器先定位找到元素,然后才能操作元素。
相对来说,定位元素比后续操作元素更难一些,因为常见操作不是很多,并且是一些固定调用。
比如:
- 点击元素,click()
- 输入文本,fill()
- 获取元素内部文本,inner_text()
Locator对象
Playwright中根据CSS Selector定位元素,就是使用Locator对象。
Page对象的locator方法就是创建一个Locator类型的对象,参数就可以是CSS Selector 表达式。
page.locator("div") # div元素
page.locator("#myId") # id为myId的元素
page.locator(".myClass") # class为myClass的元素
根据 tag名、id、class 定位元素
CSS Selector 可以根据HTML元素的标签名、id、class进行定位。
根据tag名选择元素时可以直接写tag名,比如要选择所有的tag名的div元素:
locators = page.locator("div").all()
然后可以获取所有div元素的内部可见文本,可以直接调用all_inner_texts
for one in locators:
print(one.inner_text())
要获取所有div元素的内部可见文本也可以使用链式调用
texts = page.locator("div").all_inner_texts()
注意:如果locator调用匹配的结果是多个元素,调用针对单个元素的方法,比如inner_text,会有错误抛出:
page.locator('div').inner_text()
一个元素可以有多个class类型,多个class类型的值用空格隔开,比如:
<span class="chinese student">张三</span>
注意,这里的span标签有两个class属性,分别是chinese、student,而不是chinese student。 使用代码选择这个元素,可以指定任意一个class属性值,都可以匹配到这个元素。 而不能写成
page.locator(".chinese student")
如果要表示同时具有两个class属性,可以写为:
page.locator(".chinese.student")
如果要表示同时选择两种class属性,可以写为:
page.locator(".chinese,.student")
验证CSS Selector正确选择元素
当然可以写出python代码,然后运行,看是否正确选择元素。但是太麻烦了。
可以直接在浏览器的开发者工具中验证
- 打开开发者工具
- 在
Elements标签中,同时按Ctrl + F,打开搜索框。这个搜索框是支持css selector的写法的。
匹配多个元素
如果一个locator表达式匹配到多个元素,要获取所有元素的locator对象,要使用all()方法。
locators = page.locator(".plant").all()
有时只需要获得某种表达式对应的元素的数量可以使用count()方法
count = page.locator(".plant").count()
根据结果(也就是匹配的元素数量),可以判断元素是否存在。
有时只需要得到第一个匹配的元素,或者最后一个元素。 可以使用first和last属性。
lct = page.locator(".plant")
print(lct.first().inner_text(), lct.last().inner_text())
也可以通过nth方法,指定索引,获取第几个元素。
lct = page.locator(".plant")
print(lct.nth(0).inner_text(), lct.nth(1).inner_text())
元素内部定位
前面都是通过Page对象调用的locator方法,定位的范围是整个网页。 如果想要在某个元素内部定位,可以通过Locator对象调用locator方法。
# 在#bottom对应元素的范围内寻找标签名为span的元素
lct = page.locator("#bottom")
eles = lct.locator("span").all()
for e in eles:
print(e.inner_text())
选择子元素和后代元素
HTML中元素内部可以包含其他元素。 如果元素2是元素1的直接子元素。CSS Selector选择子元素的语法是:
元素1 > 元素2
最终选择的元素是元素2。
如果元素2是元素1的后代元素。CSS Selector选择后代元素的语法是:
元素1 元素2
最终选择的元素是元素2。
根据属性选择元素
CSS Selector 可以根据元素的属性来选择元素。 语法是一个方括号[]。 例如选择一个a元素
<a href="https://www.baidu.com">百度</a>
如果要选择href属性为https://www.baidu.com的a元素,可以使用
[href='https://www.baidu.com']
也可以加上标签限制
a[href='https://www.baidu.com']
根据属性选择,也可以不指定属性值:
[href]
CSS还可以选择属性值包含某个字符串的元素:
a[href*="baidu"]
还可以选择属性值为某个字符串开头的元素:
a[href^="https"]
还可以选择属性值为某个字符串结尾的元素:
a[href$="com"]
也可以指定多个属性:
a[href*="baidu"][title="百度"]
按次序选择子节点
CSS Selector 可以选择某个元素的第几个子节点。 语法是:
元素:nth-child(n)
n是一个整数,表示第几个子节点。n从1开始计数。
例如,选择一个div元素的第2个子元素:
div:nth-child(2)
如果要选择一个div元素的第2个子元素,并且这个子元素是一个span元素,可以写为:
div > span:nth-child(2)
也可以选择倒数第几个子元素:
div:nth-last-child(2)
选择父节点
选择相邻兄弟元素
Xpath 定位
XPath(XML Path Language)是由W3C发布的,用来在XML和HTML文档中选择节点的语言。 Playwright也支持使用XPath来定位元素。
Playwright 代码助手生成的定位
Playwright不推荐CSS Selector的定位方式,都是根据HTML网页元素特征的定位,属于开发者的角度。 Playwright更推荐用户角度视觉呈现的定位。
根据文本内容定位
有时想要获取页面中包含某些文字的元素,使用CSS Selector可能比较麻烦,可以使用Page/Locator对象的get_by_text方法。
# 选择所有带有百度一下文字的元素
elements = page.get_by_text("百度一下").all()
匹配文字可以使用正则表达式。例如匹配结尾为下的文字的元素。
import re
elements = page.get_by_text(re.compile("百度一下$")).all()
根据Role定位
web应用有一种标准称之为:ARIA(Accccessible Rich Internet Applications)。 ARIA定义了网页中各种元素的角色,比如按钮、链接、图片、文本、输入框等。 Playwright提供了根据ARIA角色来定位元素的方法。
# 选择所有按钮
elements = page.get_by_role("button").all()
常用视觉定位
根据placeholder属性定位。 可以使用Page/Locator对象的get_by_placeholder方法。
<input type=""text placeholder="captcha"/>
page.get_by_placeholder("captcha",exact=True) # 表示精确匹配
其他视觉定位
可以通过 label 来定位
page.get_by_label("username").fill("ttp")
操作
缺省等待时间
Playwright在定位元素时,如果没有找到这个元素,Playwright在定位元素时,如果没有找到这个元素,Playwright并不会立即抛出错误,而是缺省等待元素时间为30秒。在30秒内,如果元素出现了,就会立即操作成功返回。
元素通用操作
- 获取文本内容 通过 locator 对象的
inner_text()的方法,可以获得内部文本 如果 locator 选择到的元素是多个,可以使用all_inner_texts(),获取所有匹配的文本,放到列表中返回。 上面这两个方法返回的都是元素内部的可见元素。 - 获取隐藏内容 可以使用
text_content()或all_text_contents()方法获取单个或多个匹配对象文本。 - 获取元素的属性 获取元素的属性值,可以使用Locator对象的
get_attribute('属性名')方法。 - 获取元素内部HTML Locator对象的
inner_html()方法 - 等待元素可见
wait_for()等待一个元素的出现 - 判断元素是否可见 有时,自动化代码需要根据当前页面中
是否存在某些内容,来决定下一步操作。 此时可以使用is_visible()方法
该方法不会等待元素出现,会直接返回 true 或 false
光标动作
- 点击
click()方法是单击元素;双击可以使用dbclick()。 - 悬停 让光标悬停到某个元素上方,可以使用
hover()方法
输入框操作
- 文本框输入 单行文本框
input或多行文本框textarea都可以使用 Locator 对象的file方法进行输入。 - 文本框清空 要清空单行文本框或多行文本框的内容,可以使用
clear方法。
注意:获取
input框的内容要使用input_value()方法
- 文件输入框 对于html 中有文件类型的输入框,通常用于上传文件。 要设置选中的文件,可以设置 locator 对象的
set_input_files()方法。
page.locator('input[type=file]')
# 选择单个
lc.set_input_files('d:/1.png')
# 选择多个
lc.set_input_files(['d:/1.png','d:/2.png'])
- radio单选/checkbox多选 常见的选择框包括 radio、checkbox、select。 radio 是常见的
点选元素
<div id="s _radio">
<input type="radio" name="teacher" value="小江老师">小江老师<br>
<input type="radio" name="teacher" value="小雷老师">小雷老师<br>
<input type="radio" name="teacher" value="小凯老师” checked="checked">小凯老师
</div>
如果要点选 radio 框,可以使用 check() 方法。 如果要取消选择 radio 框,可以使用 uncheck() 方法。 如果要判断 radio 框是否选中,可以使用 is_checked() 的方法。
check框同radio。
- select框 可以使用 select 元素对应的
select_option方法。 对于单选框
page.locator('#ss_single').select_option('小江老师')
这里
select_option参数是选项option元素的value或者选项文本要完全匹配。
也可以使用关键字参数、index、value、label 指定分别根据索引、 value 属性、选项文本进行匹配。
#根据 索引 选择,从0开始
page.locator('#ss_single').select_option(index=1)
# 根据 value属性 选择
page.locator('#ss_single').select_option(value='小江老师')
#根据 选项文本 选择
page.locator('#ss_single').select_option(label='小江老师')
# 消空所有选择
page.locator('#ss_single').select_option([])
select多选框,方法与上面相同,参数换成列表即可。
page.locator('#ss_single').select_option(value=['小江老师','小王老师'])
对网页的操作
打开网址/刷新/前进/后退 要打开网址/刷新/前进/后退,可以分别调用Page对象的。goto/reload/go_back/go_forward方法。
获取网页HTML 要获取整个网页的 html,可以调用Page的 content() 方法。
title 要获取整个网页的标题栏文本,可以调用Page对象的 title() 方法。
set-viewport-size 要设置页面大小,可以调用Page对象的 set_viewport_size 方法。
#单位是像素
page.set_viewport_size({"width": 640,"height": 480})
frame切换
网页可以嵌入网页,但是 playwright在打开一个网页时,操作范围 缺省是当前 html ,并不包含被嵌入的 html 文档里面的内容。如果想要定位操作被嵌入的 html 文档中的元素,就必须切换操作范围到被嵌入的文档当中。 可以使用Page或Locator对象的frame_locator()方法定位到需要操作的frame。
# 产生一个Frame locator 对象
frame = page.frame_locator("iframe[src='sample1.html']")
# 再 在其内部进行定位
lcs = frame.locator('.plant').a11()
for lc in lcs:
print(lc.inner_text(timeout=1000))
窗口切换
点击a连接可以跳转到另一个网页,也可以新打开另一个网页。 即使新窗口打开了,这时Page变量对应的还是老窗口,自动化操作,也还是在老窗口进行的,所以需要切换到新窗口。 BoowserContext对象有一个pages属性,里面依次为所有的窗口对应的Page对象。
from playwright.sync_api import sync_playwright
pw = sync_playwright().start()
browser = pw.chromium.launch(headless=False)
# 创建BoowserContext对象
context = browser.new_context()
# 通过context创建page
page = context.new_page()
page.goto("https:ur")
#点击连接,打开新窗口
page.locator("a").click()
# 等待2秒
page.wait_for_timeout(2000)
# pages属性是所有窗口的列表
newPage = context.pages[1]
# 打印新旧网页标题
print(newPage.title())
print(page.title())
如果打开了很多窗口,不知道目标的次序号,可以用检查标题的方法。
设置当前tab
想要把某个窗口作为当前活动窗口显示,可以调用这个窗口对象的bring_to_front()方法。
关闭网页窗口
直接调用page对象的close()方法。
冻结窗口
有些元素需要光标移上去才显示。 可以在控制台输入
setTimeout(function(){debugger}, 5000)
截屏
使用Page对象的screenshot()方法。
# 截屏当前页面可见内容,保存到当前工作目录下的ss1.png文件中。
page.screenshot(path='ss1.png')
# 完整截图,页面过长,可以截全图
page.screenshot(path='ss1.png',full_page=True)
也可以只对某一个元素的显示内容进行截屏,使用Locator对象的screenshot方法。
page.locator('input[type=file]').screenshot(path='ss1.png')
拖拽
可以使用page对象的drag_and_drop()方法。 比如选择 span #t1的文本内容,拖拽到输入框里面去
page.locator('#t1').select_text()
page.drag_and_drop('#t1', '[placeholder="captcha"]')
弹出对话框
弹出的对话框有三种类型,分别是 alert(警告信息)、confirm(确认信息)和 prompt(提示输入)。
Alert
alert 就是通知信息,在用户看完信息后点击 ok 就可以了。
# 处理弹出对话框的函数
def handleDlg(dialog):
page.wait_for_timeout(1000)
# 点击确认
dialog.accept()
print(dialog.message)
# 设置弹出对话框时间回调函数
page.on("dialog", handleDlg)
Confirm
accept()方法相当于点击确认 dismess()相当于点击取消
Prompt
在accept()方法中输入参数字符串,作为要输入的信息
dialog.accept("要输入的内容")
