Playwright简介
支持多数浏览器
-
在Chromium,Firefox和WebKit上进行测试。Playwright拥有适用于所有现代浏览器的完整API覆盖,包括Google Chrome和Microsoft Edge(带有Chromium),Apple Safari(带有WebKit)和Mozilla Firefox。
-
跨平台的WebKit测试。使用Playwright,使用适用于Windows,Linux和macOS的WebKit构建,测试您的应用程序在Apple Safari中的行为。在本地和CI上进行测试。
-
测试手机。使用设备仿真在移动Web浏览器中测试您的自适应Web应用程序。
-
无报文头与有报文头。Playwright支持所有浏览器和所有平台的无头(无浏览器UI)和有头(有浏览器UI)模式。有报文头模式适用于调试,而无报文头适用于CI / cloud执行。
拥有快速可靠的执行
-
自动等待APIs。Playwright交互会自动等待直到元素准备就绪。这样可以提高可靠性并简化测试编写流程。
-
无超时自动化。Playwright会接收浏览器信号,例如网络请求,页面导航和页面加载事件,以消除导致睡眠中断的烦恼。
-
与浏览器上下文保持并行。对于多个并行孤立的浏览器上下文可执行环境重复使用一个单独的浏览器实例。
-
弹性元素选择器。Playwright可以依靠面向用户的字符串(例如文本内容和可访问性标签)来选择元素。这些字符串比紧耦合到DOM结构的选择器更具弹性。
拥有强大的自动化功能
-
多个域,页面和框架。Playwright是一种进程外自动化驱动程序,不受页面内JavaScript执行范围的限制,并且可以自动执行具有多个页面的方案。
-
强大的网络控制。Playwright引入上下文范围的网络拦截以便进行终止或者模拟网络请求。
-
现代网络功能。Playwright通过插入阴的选择器,地理位置,权限,Web Worker和其他现代WebAPI支持Web组件。
-
涵盖所有场景的能力。支持文件下载和上传,进程外iframe,原生输入事件,甚至是深色模式
与selenium对比
Selenium 架构
蓝色图中的Selenium Language Binding就是我们平时使用的编码语言,包括java、python等等。可以看到这些语言并没有直接与Browser Drivers进行通信,而是通过了JSON WireProtocol,这就是webdriver协议,然后通过webdriver协议在与各个浏览器的driver进行通信,最后各个浏览器的driver与其对应的浏览器进行通信。这里我们以chromedriver为例进行讲解,他负责与chrome浏览器进行通信。我们在代码中直接 newChromeDriver() 将会启动一个 ChromeDriver进程,ChromeDriver是一个独立的服务,它是google为网站开发人员提供的自动化测试接口,是 selenium 和chrome浏览器进行通信的桥梁。chromeDriver解析webdriver协议,然后根据解析结果,调用与之对应的Chrome DevTool Protocol(CDP)协议来操控chrome浏览器,它可以和浏览器内核进行交互进而操控浏览器,这里就不对该协议进行详细介绍了。另外,其他浏览器的dirver与其对应浏览器的通信原理与ChromeDriver类似
Playwright 架构
client:在客户端是我们用不同的编程语言编写的代码,如JavaScript,Java,Python,C#等。server:Playwright的server通过nodejs构建并负责与client 以及不同的 Web 浏览器引擎进行通信。通信协议:client通过WebSocket 协议与Playwright server 通信;Playwright使用 Chrome DevTools 协议(CDP)与 Chromium 通信。对于Firefox和WebKit,Playwright实现了自己的协议,类似于CDP。一旦触发测试,client端代码将被转换为JSON格式,然后使用websocket协议发送到服务器。palywright通过单个 websocket 协议连接传达所有请求,该连接将保持不变,直到所有测试执行完成。由于命令是在单个连接上发送的,因此测试失败或不稳定的可能性较小,并且命令可以快速执行。这种架构与Selenium相反,Selenium使用HTTP连接协议,并将每个命令(如浏览器打开,单击,发送密钥或关闭浏览器)作为单独的HTTP请求发送。此外,在Selenium中,服务器和客户端之间的连接将在每次请求后终止,并为下一个请求重新建立。最后划重点:这就是Playwright比selenium快的原因!
Playwright安装
pip install playwright # 安装第三方库playwright install # 安装自带浏览器和ffmpeg
API
内容管理器PlaywrightContextManager
浏览器类型BrowserType
with sync_playwright() as pw: def sync_playwright() -> PlaywrightContextManager:return PlaywrightContextManager()
pw对象属性(方法) | 说明 |
---|---|
chromium | chromium内核浏览器 |
devices | 设备 |
firefox | firefox浏览器 |
webkit | webkit内核浏览器 |
浏览器类型BrowserType
from playwright.sync_api import sync_playwrightwith sync_playwright() as pw:browser = pw.chromium.launch(headless=False)
对象属性(方法) | 说明 |
---|---|
connect | |
connect_over_cdp | |
executable_path | |
launch | 运行,可以配置参数 |
launch_persistent_context | |
name | 浏览器的名字 |
on | |
once | |
remove_listener |
浏览器对象browser
from playwright.sync_api import sync_playwrightwith sync_playwright() as pw:browser = pw.chromium.launch(headless=False)
对象属性(方法) | 说明 |
---|---|
close | |
contexts | |
is_connected | |
new_browser_cdp_session | |
new_context | 一个上下文,可用来管理多个窗口 |
new_page | 打开一个新窗口 |
on | |
once | |
remove_listener | |
version | chromium的版本 |
页面对象Page
page = browser.new_page()#源码def new_page(self,*,viewport: ViewportSize = None,screen: ViewportSize = None,no_viewport: bool = None,ignore_https_errors: bool = None,java_script_enabled: bool = None,bypass_csp: bool = None,user_agent: str = None,locale: str = None,timezone_id: str = None,geolocation: Geolocation = None,permissions: typing.List[str] = None,extra_http_headers: typing.Optional[typing.Dict[str, str]] = None,offline: bool = None,http_credentials: HttpCredentials = None,device_scale_factor: float = None,is_mobile: bool = None,has_touch: bool = None,color_scheme: Literal["dark", "light", "no-preference"] = None,forced_colors: Literal["active", "none"] = None,reduced_motion: Literal["no-preference", "reduce"] = None,accept_downloads: bool = None,default_browser_type: str = None,proxy: ProxySettings = None,record_har_path: typing.Union[str, pathlib.Path] = None,record_har_omit_content: bool = None,record_video_dir: typing.Union[str, pathlib.Path] = None,record_video_size: ViewportSize = None,storage_state: typing.Union[StorageState, str, pathlib.Path] = None,base_url: str = None,strict_selectors: bool = None) -> "Page":
对象属性(方法) | 说明 |
---|---|
click | 在页面上定位后点击,click(待点击元素的selector) |
dblclick | 双击 |
drag_and_drop | 拖拽 |
evaluate | 执行js |
fill | 在页面上定位后输入,ϐill(selector,'要输入的内容') |
frame_locator | 定位frame |
get_attribute | 获取属性 |
go_back | 后退 |
go_forward | 前进 |
goto | 打开URL |
hover | 悬停 |
keyboard | 键盘 |
locator | 定位器 |
mouse | 鼠标 |
screenshot | 截图,注意要传参path='1.png' |
title | 页面title |
text_content | 文本信息 |
url | 页面url |
wait_for_timeout | 超时等待,类似于time.sleep,不建议在Playwright中使用 |
★定位locator
定位方式
定位方式 | 示例 | 备注 |
---|---|---|
id | page.locator('id=ls_username').fill('admin') | |
css | page.locator('input#ls_username.pn.vm') | css是默认的语法直接写,也可以用css= |
xpath | page.locator("xpath=//a") | 注意一定不要'//a'加引号 |
text | page.locator("text=百度") | 同样text部分也不要加引号 |
页面布局定位 | page.locator("text=百度:near(表达式)") | |
page.locator("text=百度:above(表达式)") | ||
page.locator("text=百度:below(表达式)") | ||
page.locator("text=百度:left-of(表达式)") | ||
page.locator("text=百度:right-of(表达式)") | ||
下标定位 | page.locator('input >> nth=0').fill('admin') | 第一个input中输入admin |
组合定位 | page.locator('td>.xi2.xw1 >> text=立即注 | text可以去其他方式组合起来 |
定位Element
定位方式 | 示例 | 备注 |
---|---|---|
query_selector | page.query_selector('input').fill('admin') | 获取页面xxx节点,多个时返回第一个 |
query_selector_all | page.query_selector_all('input')[0].fill('admin') | 获取页面所有xxx节点,返回对象是list,每个元 |
鼠标操作
操作 | 示例 |
---|---|
单击 | page.click("[value='click me']") |
右击 | page.click('[value="right click me"]',button='right') |
双击 | page.dblclick("[value='dbl click me']") |
按住shift点击 | page.click('元素selecotr', modifiers=['Shift']) |
元素对象Locator
username = page.locator('#ls_username')
对象属性(方法) | 说明 |
---|---|
all_inner_texts | |
all_text_contents | 所有文本内容 |
click | 单击 |
count | 定位到的元素的个数 |
dblclick | 双击 |
evaluate | 执行js |
fill | 输入内容(没有间隙) |
filter | 定位再定位 |
ϐirst | 多个中的第1个 |
get_attribute | 获取元素的属性 |
last | 多个中的最后一个 |
locator | 定位再定位 |
text_content | 文本内容 |
type | 可以通过delay参数指定输入的间隔,单位注意是毫秒 |