微软出品的UI自动化测试工具Playwright(三)
微软出品的UI自动化测试工具Playwright(三)
网址 | 说明 |
---|---|
https://playwright.dev/ | 官网首页 |
https://playwright.dev/python/docs/intro | Python部分入口 |
https://github.com/microsoft/playwright-python | github,python入口 |
https://github.com/microsoft/playwright-python/releases | python部分的release notes |
本文基于 playwright 1.32.1 发布于 2023-3-30
学习前你得有html、css、xpath等基础,最好有selenium基础,我是对比来讲解的
⑤实例
通过一个个实例来讲述Playwright的能力
实例一: 打开某某网站
参考代码
from playwright.sync_api import sync_playwright with sync_playwright() as p:
browser = p.chromium.launch(headless=False)
page = browser.new_page()
page.goto("https://www.baidu.com")
执行效果:打开百度后自动关闭
对比selenium,这是有点麻烦的
playwright是个包(文件夹),里面主要是3个部分
- sync_api:同步,入门你用的最多的是这个
- driver
- async_api:异步
sync_playwright是一个函数,返回值类型是PlaywrightContextManager
def sync_playwright() -> PlaywrightContextManager:
return PlaywrightContextManager()
从名字上看得出是个上下文管理器,所以你可以用with来处理
钻进去你能看到__enter__和__exit def __enter__(self) -> SyncPlaywright:
而这个SyncPlaywright是有很多属性的,主要的就是我们要打开的几个浏览器
def chromium(self) -> "BrowserType":
"""Playwright.chromium This object can be used to launch or connect to Chromium, returning instances of `Browser`. Returns
-------
BrowserType
"""
return mapping.from_impl(self._impl_obj.chromium) def firefox(self) -> "BrowserType":
def webkit(self) -> "BrowserType":
BrowserType则是浏览器类型类,它的launch方法是重要的方法,参数非常多,一般用到的就是headless,赋值False就是有头(能看到页面)。返回的是浏览器实例。
在playwright中你仅有一个浏览器实例是作不了什么的,你必须要打开一个页面
Browser有一些方法属性,其中new_page是用来打开新的页面的,返回类型是Page
玩过selenium的同学应该知道,Page对象是你最多了解的部分
Page对象属性方法详见附录一
实例二: 登录开源论坛
前面了解了打开网页
下面就涉及UI自动化测试最重要的定位了
参考代码
from playwright.sync_api import sync_playwright with sync_playwright() as p:
browser_type = p.chromium
browser = browser_type.launch(headless=False)
page = browser.new_page()
page.goto("http://114.116.2.138:8090/forum.php")
page.locator('#ls_username').fill('admin')
page.locator('#ls_password').fill('123456')
page.locator('.pn.vm').click()
page.wait_for_timeout(5000)
可以看到我们使用了css语法来定位
page对象的locator方法中就可以去塞一个css表达式来定位元素
而这个元素也是非常重要的对象,其类型是Locator,这个对象的属性方法可以参考附录二
此处的等待要注意,在页面上等待不建议使用time.sleep,而是应该用page的wait_for_timeout
参考代码2
from playwright.sync_api import sync_playwright with sync_playwright() as p:
browser_type = p.chromium
browser = browser_type.launch(headless=False)
page = browser.new_page()
page.goto("http://114.116.2.138:8090/forum.php")
page.fill('#ls_username','admin')
page.fill('#ls_password','123456')
page.click('.pn.vm')
page.wait_for_timeout(5000)
的确,locator都可以省略的,直接在fill或者click上写表达式
实例三: 获取百度热点
参考代码
from playwright.sync_api import sync_playwright
with sync_playwright() as pw:
browser = pw.chromium.launch(headless=False)
page = browser.new_page()
page.goto('https://www.baidu.com')
hot_news = page.locator('.title-content-title').all_text_contents()
for hot_new in hot_news:
print(hot_new)
上述代码是ok的,但是你如果从selenium转过来,是比较别扭的
因为page.locator('.title-content-title')定位元素在实例二中提到了,但此处表达式.title-content-title是有多个元素的
在selenium中如果定位到了多个,你操作的是第一个,但playwright用locator的做法不一样,这多少有点不习惯。
此处all_text_contents()的返回是个list,其内容就是我们热点的文本信息
['红树林边的瞩望', '带你体验中老友谊之旅', '中央转移支付首破十万亿 钱去哪儿了', '云南玉溪山火蔓延 火场燃烧迅猛', '银行发现7位数存款5年未动急寻人', '台媒:大陆禁航从27分钟变6小时']
我们可以看看如果定位到一个元素的话,它的输出是没问题的
from playwright.sync_api import sync_playwright
with sync_playwright() as pw:
browser = pw.chromium.launch(headless=False)
page = browser.new_page()
page.goto('https://www.baidu.com')
# .hotsearch-item:nth-child(1) .title-content-title 这个表达式就定位到一个元素
hot_news = page.locator('.hotsearch-item:nth-child(1) .title-content-title')
print(hot_news.text_content())
如果你定位到多个元素,就不行了
from playwright.sync_api import sync_playwright
with sync_playwright() as pw:
browser = pw.chromium.launch(headless=False)
page = browser.new_page()
page.goto('https://www.baidu.com')
hot_news = page.locator('.title-content-title')
print(hot_news.text_content())
Traceback (most recent call last):
File "D:\pythonProject\AutoTest\DemoPlaywright0413\demos\demo_openpage.py", line 7, in <module>
print(hot_news.text_content())
File "D:\pythonProject\AutoTest\DemoPlaywright0413\venv\lib\site-packages\playwright\sync_api\_generated.py", line 17562, in text_content
self._sync(self._impl_obj.text_content(timeout=timeout))
File "D:\pythonProject\AutoTest\DemoPlaywright0413\venv\lib\site-packages\playwright\_impl\_sync_base.py", line 104, in _sync
return task.result()
File "D:\pythonProject\AutoTest\DemoPlaywright0413\venv\lib\site-packages\playwright\_impl\_locator.py", line 564, in text_content
return await self._frame.text_content(
File "D:\pythonProject\AutoTest\DemoPlaywright0413\venv\lib\site-packages\playwright\_impl\_frame.py", line 605, in text_content
return await self._channel.send("textContent", locals_to_params(locals()))
File "D:\pythonProject\AutoTest\DemoPlaywright0413\venv\lib\site-packages\playwright\_impl\_connection.py", line 61, in send
return await self._connection.wrap_api_call(
File "D:\pythonProject\AutoTest\DemoPlaywright0413\venv\lib\site-packages\playwright\_impl\_connection.py", line 461, in wrap_api_call
return await cb()
File "D:\pythonProject\AutoTest\DemoPlaywright0413\venv\lib\site-packages\playwright\_impl\_connection.py", line 96, in inner_send
result = next(iter(done)).result()
playwright._impl._api_types.Error: Error: strict mode violation: locator(".title-content-title") resolved to 6 elements:
1) <span class="title-content-title">红树林边的瞩望</span> aka get_by_role("link", name=" 红树林边的瞩望")
2) <span class="title-content-title">带你体验中老友谊之旅</span> aka get_by_role("link", name="3 带你体验中老友谊之旅")
3) <span class="title-content-title">中央转移支付首破十万亿 钱去哪儿了</span> aka get_by_role("link", name="1 中央转移支付首破十万亿 钱去哪儿了")
4) <span class="title-content-title">云南玉溪山火蔓延 火场燃烧迅猛</span> aka get_by_role("link", name="4 云南玉溪山火蔓延 火场燃烧迅猛")
5) <span class="title-content-title">银行发现7位数存款5年未动急寻人</span> aka get_by_role("link", name="2 银行发现7位数存款5年未动急寻人")
6) <span class="title-content-title">台媒:大陆禁航从27分钟变6小时</span> aka get_by_role("link", name="5 台媒:大陆禁航从27分钟变6小时") =========================== logs ===========================
waiting for locator(".title-content-title")
============================================================ 进程已结束,退出代码为 1
- 然playwright还有一些其他的定位方法
实例四: 验证码破解登录
参考代码
from playwright.sync_api import sync_playwright
with sync_playwright() as pw:
browser = pw.chromium.launch(headless=False)
page = browser.new_page()
page.goto('http://121.5.150.55:8090/forum.php')
page.locator('#ls_username').fill('admin')
page.locator('#ls_password').fill('123456')
page.locator('.pn.vm').click()
code_bytes = page.locator("[id^='vseccode_cSA']>img").screenshot()
import ddddocr
ocr = ddddocr.DdddOcr()
code_text = ocr.classification(code_bytes)
page.locator("input[id^='seccodeverify_cSA']").fill(code_text)
page.locator("[name='loginsubmit']").click()
在这个案例中,我们主要用到了元素的screenshot(),返回的是一个bytes对象
然后经过ddddocr处理可以得到其文本
实例五: 相对定位
仅供参考
实例代码
from playwright.sync_api import sync_playwright
with sync_playwright() as pw:
browser = pw.chromium.launch(headless=False)
page = browser.new_page()
page.goto('http://121.41.14.39:8088/index.html')
page.locator('input:above(#password)').fill('sq1')
page.locator('#password:near(#username)').fill('123')
page.locator('#code:left-of(img)').fill('999999')
page.locator('#submitButton:below(#code)').click()
page.wait_for_timeout(5000)
实例六: 论坛的悬停登录
from playwright.sync_api import sync_playwright
with sync_playwright() as pw:
browser = pw.chromium.launch(headless=False)
page = browser.new_page()
page.goto('http://114.116.2.138:8090/forum.php')
qmenu_locator = page.locator('#qmenu')
qmenu_locator.hover()
page.click('.xi2>strong')
page.fill('[id^=username_L]','admin')
page.fill('[id^=password3_L]','123456')
page.click('[name=loginsubmit].pn.pnc')
page.wait_for_timeout(5000)
实例七: 论坛的发帖
from playwright.sync_api import sync_playwright
with sync_playwright() as pw:
browser = pw.chromium.launch(headless=False)
page = browser.new_page()
page.goto('http://114.116.2.138:8090/forum.php')
page.fill('#ls_username','admin')
page.fill('#ls_password','123456')
page.keyboard.press('Enter')
page.wait_for_timeout(2000)
page.click('text=默认版块')
page.click('css=#newspecial')
page.fill('#subject','帖子标题')
page.frame_locator('#e_iframe').locator('#editorheader+body').fill('帖子内容') #frame切换
page.click('#postsubmit')
page.wait_for_timeout(5000)
附录
Page对象属性方法
属性 | 说明 |
---|---|
accessibility | 可访问性 |
add_init_script | |
add_script_tag | |
add_style_tag | |
bring_to_front | |
check | |
click | |
close | |
content | |
context | 上下文 |
dblclick | 双击 |
dispatch_event | |
drag_and_drop | |
emulate_media | |
eval_on_selector | |
eval_on_selector_all | |
evaluate | |
evaluate_handle | |
expect_console_message | |
expect_download | |
expect_event | |
expect_file_chooser | |
expect_navigation | |
expect_popup | |
expect_request | |
expect_request_finished | |
expect_response | |
expect_websocket | |
expect_worker | |
expose_binding | |
expose_function | |
fill | |
focus | |
frame | |
frame_locator | |
frames | |
get_attribute | |
get_by_alt_text | |
get_by_label | |
get_by_placeholder | |
get_by_role | |
get_by_test_id | |
get_by_text | |
get_by_title | |
go_back | |
go_forward | |
goto | 跳转到指定页面 |
hover | |
inner_html | |
inner_text | |
input_value | |
is_checked | |
is_closed | |
is_disabled | |
is_editable | |
is_enabled | |
is_hidden | |
is_visible | |
keyboard | 键盘操作入口,返回Keyboard |
locator | 定位元素 |
main_frame | |
mouse | 鼠标操作入口,返回Mouse |
on | |
once | |
opener | |
pause | |
press | |
query_selector | |
query_selector_all | |
reload | 页面刷新 |
remove_listener | |
request | |
route | |
route_from_har | |
screenshot | 截图 |
select_option | |
set_checked | |
set_content | |
set_default_navigation_timeout | |
set_default_timeout | |
set_extra_http_headers | |
set_input_files | |
set_viewport_size | |
tap | |
text_content | |
title | 标题 |
touchscreen | |
type | |
uncheck | |
unroute | |
url | url |
video | |
viewport_size | |
wait_for_event | |
wait_for_function | |
wait_for_load_state | |
wait_for_selector | |
wait_for_timeout | 等待,参数是毫秒,float |
wait_for_url | |
workers |
Locator对象属性方法
属性 | 说明 |
---|---|
all | 所有元素 |
all_inner_texts | |
all_text_contents | 所有文本内容 |
blur | |
bounding_box | |
check | |
clear | 清空 |
click | 点击 |
count | 元素个数 |
dblclick | 双击 |
dispatch_event | |
drag_to | 拖拽 |
element_handle | |
element_handles | |
evaluate | |
evaluate_all | |
evaluate_handle | |
fill | 输入内容 |
filter | |
first | |
focus | |
frame_locator | |
get_attribute | |
get_by_alt_text | 通过alt属性的文本定位 |
get_by_label | |
get_by_placeholder | |
get_by_role | |
get_by_test_id | |
get_by_text | |
get_by_title | |
highlight | |
hover | |
inner_html | |
inner_text | |
input_value | |
is_checked | |
is_disabled | |
is_editable | |
is_enabled | |
is_hidden | |
is_visible | |
last | |
locator | |
nth | 下标 |
on | |
once | |
page | |
press | |
remove_listener | |
screenshot | 元素截图 |
scroll_into_view_if_needed | |
select_option | |
select_text | |
set_checked | |
set_input_files | |
tap | |
text_content | |
type | |
uncheck | |
wait_for |
get_by_role所支持的标签
[
"alert",
"alertdialog",
"application",
"article",
"banner",
"blockquote",
"button",
"caption",
"cell",
"checkbox",
"code",
"columnheader",
"combobox",
"complementary",
"contentinfo",
"definition",
"deletion",
"dialog",
"directory",
"document",
"emphasis",
"feed",
"figure",
"form",
"generic",
"grid",
"gridcell",
"group",
"heading",
"img",
"insertion",
"link",
"list",
"listbox",
"listitem",
"log",
"main",
"marquee",
"math",
"menu",
"menubar",
"menuitem",
"menuitemcheckbox",
"menuitemradio",
"meter",
"navigation",
"none",
"note",
"option",
"paragraph",
"presentation",
"progressbar",
"radio",
"radiogroup",
"region",
"row",
"rowgroup",
"rowheader",
"scrollbar",
"search",
"searchbox",
"separator",
"slider",
"spinbutton",
"status",
"strong",
"subscript",
"superscript",
"switch",
"tab",
"table",
"tablist",
"tabpanel",
"term",
"textbox",
"time",
"timer",
"toolbar",
"tooltip",
"tree",
"treegrid",
"treeitem",
]
元素状态
元素状态(英) | 元素状态(中) | 说明(英) |
---|---|---|
Attached | 附着 | Element is considered attached when it is connected to a Document or a ShadowRoot. |
元素连接到DOM或者ShadowRoot则认为元素是附着的 | ||
Visible | 可见 | Element is considered visible when it has non-empty bounding box and does not have visibility:hidden computed style. Note that elements of zero size or with display:none are not considered visible. |
元素的可见意味着它有边界并且没有visibility:hidden ,注意元素大小为0或者具有 display:none 则认为是不可见的 |
||
Stable | 稳定的 | Element is considered stable when it has maintained the same bounding box for at least two consecutive animation frames |
元素在至少两个连续的动画帧中保持相同的边界框时被认为是稳定的 | ||
Enabled | 使能 | Element is considered enabled unless it is a <button> , <select> , <input> or <textarea> with a disabled property. |
元素如果是 <button> , <select> , <input> or <textarea> 且具有disabled 属性就认为是非使能的,否则都是使能的 |
||
Editable | 可编辑 | Element is considered editable when it is enabled and does not have readonly property set. |
元素是可编辑的,意味着它一定是使能的且没有readonly 属性 |
||
Receivces Events | 接收事件 | element is considered receiving pointer events when it is the hit target of the pointer event at the action point. For example, when clicking at the point (10;10) , Playwright checks whether some other element (usually an overlay) will instead capture the click at (10;10) |
微软出品的UI自动化测试工具Playwright(三)的更多相关文章
- Selenide 阶段性总结介绍(UI自动化测试工具)
今天给大家介绍一个比较新的UI自动化测试工具-- Selenide.确实是比较新的,国内应该还没有多少人用它.在百度和google上你只能搜到一个中文帖子简单介绍了一下.如果你想用这个工具,不可避免的 ...
- Airtest网易开源的一款UI自动化测试工具
Airtest网易开源的一款UI自动化测试工具 1 Airtest 简介Airtest Project是网易游戏内部工具团队开发并开源的一款UI自动化测试工具,据说曾经获得谷歌力挺. AirtestI ...
- 非常好用的1款UI自动化测试工具:airTest
网易团队开发的UI自动化测试神器airTest,下载地址:http://airtest.netease.com/tutorial/Tutorial.html Appium和airTest对比,我的看法 ...
- 网易UI自动化测试工具Airtest中导入air文件中的方法
最近看了一下网易的Airtest ,UI测试工具,写了一些后在导入其他air文件中的.py文件,卡了一下,现在博客中纪录一下导入其他air文件的方式: 在Airtest 测试工具中,导入其他air文件 ...
- UI 自动化测试工具BackstopJS简介(1)
BackstopJS源码地址 https://github.com/garris/BackstopJS 我写了一个DEMO放到github上面,https://github.com/shenggen1 ...
- 微软出品自动化神器Playwright,不用写一行代码(Playwright+Java)系列(一) 之 环境搭建及脚本录制
一.前言 半年前,偶然在视频号刷到某机构正在直播讲解Playwright框架的使用,就看了一会,感觉还不错,便被种草,就想着自己有时间也可以自己学一下,这一想着就半年多过去了. 读到这,你可能就去百度 ...
- <自动化测试方案_7>第七章、PC端UI自动化测试
第七章.PC端UI自动化测试 UI自动化测试又分为:Web自动化测试,App自动化测试.微信小程序.微信公众号UI层的自动化测试工具非常多,比较主流的是UFT(QTP),Robot Framework ...
- 使用WatiN进行UI自动化测试
Watin是一个UI自动化测试工具,支持ie/firefox,官方网站:http://watin.org/. 主要有以下特点: 支持主要的html元素,见:http://watin.org/docum ...
- 如何正确选择UI自动化测试
近年流行一个词-UI,和UI搭边好像都那么高大上,软件测试行业也不例外,比如UI自动化测试. 常见的UI自动化测试程序有哪些呢? l 带UI的Unit Test,比如mock掉底层代码,仅仅测试UI ...
- 微软自动化测试工具palywright
前言 我们介绍许多e2e的自动化测试工具 一类是基于 Selenium 的测试框架: robot framework gauge SeleniumBase seldom(我自己维护的) 另一类是基于J ...
随机推荐
- Unity学习笔记——坐标转换(1)
1.Center与Pivot的区别 Pivot是模型坐标轴的真实位置,将辅助图标定位在网格的实际轴心点. Center是模型渲染边界的中心. 当包含子物体时,Pivaot模式辅助图标在物体的实际轴心点 ...
- 探测域名解析依赖关系(运行问题解决No module named 'DNS')
探测域名解析依赖关系 最近很懒,今天晚上才开始这个任务,然后发现我原来能跑起来的程序跑不起来了. 一直报错 ModuleNotFoundError: No module named 'DNS' 这个应 ...
- Flutter安装SDK及配置
一.下载SDK 1.官网下载 https://docs.flutter.dev/development/tools/sdk/releases?tab=macos 2.git下载 git clone h ...
- 多级路由,重定向之后,刷新页面报错问题:报错Unexpected token '<'
使用脚手架:vue-cli3.0vue版本:vue3.0vue-router版本:vue-router4.0 配置多级路由,首次访问,到重定向页面没有问题,然后在当前页面刷新控制台报错:Unexpec ...
- node express框架搭建
前面了解了一些node.js的服务建立及事件绑定和触发,要想一步一步自己来写所有响应,还是比较麻烦,看了express,很多东西都由框架自动完成,开发人员仅需关注自己想要实现的功能即可,真正实现了让开 ...
- DHCP分配IP的流程
1.DHCP客户端以广播的形式发送DHCP Discover报文 2.所有的DHCP服务端都可以接收到这个DHCP Discover报文,所有的DHCP服务端都会给出响应,向DCHP客户端发送一个DH ...
- java获取类内容
java获取类内容 Book类 public class Book implements Serializable { private int id; private String name; pri ...
- python-实现动态web服务器
# encoding=utf-8 import socket from multiprocessing import Process import re import sys # 设置静态文件根目录 ...
- 如果摄像头不支持Web Socket,猿大师播放器还能在网页中播放RTSP流吗?
问: 我们的情况比较复杂,摄像头设备品牌和数量都比较多,分布在全国各地都有,地点分布比较广泛,有的甚至是比较老的型号,如果摄像头设备不支持Web Socket,猿大师播放器还可以在网页中播放RTSP流 ...
- Javaweb知识复习--MyBatis+Mapper代理开发
一种持久层框架,主要用于简化JDBC MyBatis应用步骤 1.在数据库里面创建一个表 2.创建模块,导入坐标 就是新建一个Maven项目,在pom.xml里面导入mybatis相应导包依赖代码: ...