playwright是由微软开发的Web UI自动化测试工具, 支持Node.js、Python、C# 和 Java语言。
playwright特性
playwright具有以下特点:
一、支持所有主流浏览器
支持所有主流浏览器:基于Chromium内核的Google Chrome 和 Microsoft Edge浏览器), WebKit内核的Apple Safari 和 Mozilla Firefox浏览器,不支持IE11。
跨平台:Windows、Linux 和macOS
可用于模拟移动端WEB应用的测试,不支持在真机上测试。
支持无头模式(默认)和有头模式
二、快速可靠的执行
自动等待元素
Playwright基于Websocket协议,可以接受浏览器(服务端)的信号。selenium采用的是HTTP协议,只能客户端发起请求。
浏览器上下文并行:单个浏览器实例下创建多个浏览器上下文,每个浏览器上下文可以处理多个页面。
有弹性的元素选择:可以使用文本、可访问标签选择元素。
三、强大的自动化能力
playwright是一个进程外自动化驱动程序,它不受页面内JavaScript执行范围的限制,可以自动化控制多个页面。
强大的网络控制:Playwright 引入了上下文范围的网络拦截来存根和模拟网络请求。
现代web特性:支持Shadow DOM选择,元素位置定位,页面提示处理,Web Worker等Web API。
覆盖所有场景:支持文件下载、上传、OOPIF(out-of-process iframes),输入、点击,暗黑模式等
安装
Playwright有Node.js、Python、C# 和 Java语言版本,本文介绍Python版本的Playwright使用方法
Playwright的Python版本仓库地址:https://github.com/microsoft/playwright-python
官方文档地址:Getting started | Playwright Python
Playwright安装简单,pip安装时会自动下载浏览器驱动:
pip install playwright
playwright install # 安装支持的浏览器:cr, chromium, ff, firefox, wk 和 webkit
playwright install chromium # 安装指定的chromium浏览器
安装时会自动下载浏览器依赖,windows系统在%USERPROFILE%\AppData\Local\ms-playwright 路径下。
脚本录制
在命令行窗口使用如下语法格式进行脚本录制:
npx playwright codegen [options] [url]
options参数:
-o, --output <file name> :保存生成脚本
--target <language> :生成的脚本语言,可以设置javascript, test, python, python-async和csharp,默认为python。
-b, --browser <browserType> :要使用的浏览器,可以选择cr, chromium, ff, firefox, wk和webkit,默认chromium。
--channel <channel>:chromium版本,比如chrome, chrome-beta, msedge-dev等,
--color-scheme <scheme>:模拟器的颜色主题,可选择light 或者 dark样式。
--device <deviceName> :模拟的设备,比如iPhone 11。
--save-storage <filename> :保存上下文状态,用于保存cookies 和localStorage,可用它来实现重用。例如playwright codegen --save-storage=auth.json
--load-storage <filename> :加载--save-storage 保存的数据,重用认证数据。
--proxy-server <proxy> :指定代理服务器
--timezone <time zone> : 指定时区
--geolocation <coordinates> :指定地理位置坐标
--lang <language> :指定语言/地区,比如中国大陆:zh-CN
--timeout <timeout> :超时时间,定位毫秒,默认10000ms
--user-agent <ua string> :用户代理
--viewport-size <size> :浏览器窗口大小
-h, --help :查看帮助信息
录制模式
Playwright 带有命令行工具(录制功能),可用于记录用户交互并生成代码(Java、Python等)。其实就是类似于 Selenium IDE。
1、常规录制
打开命令行,输入
1 |
playwright codegen
|
自动打开浏览器和录制界面
通过操作(点击、输入等)浏览器页面,脚本也会自动增加操作的步骤。
此外,录制工具还可以获取元素的定位。点击停止录制,之后再点击 Explore 后,在页面点击想要定位的元素,即可获取到该元素定位的值。
作为演示,输入百度网址打开百度页面,搜索框中输入“playwright”,点击“百度一下”按钮,录制代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
from playwright.sync_api import sync_playwright
def run(playwright):
browser = playwright.chromium.launch(headless = False )
context = browser.new_context()
# Open new page
page = context.new_page()
# Go to https://www.baidu.com/
page.goto( "https://www.baidu.com/" )
# Click input[name="wd"]
page.click( "input[name=\"wd\"]" )
# Fill input[name="wd"]
page.fill( "input[name=\"wd\"]" , "playwright" )
# Click text=百度一下
page.click( "text=百度一下" )
# assert page.url == "https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&rsv_idx=1&tn=baidu&wd=playwright&fenlei=256&oq=playwright&rsv_pq=bf1abd6c000029f7&rsv_t=1937PYyfHvfyS6fay57V1zS1iCIiYC4%2B8I6srjLqYYkXrf8H9kce%2BLQKVzA&rqlang=cn&rsv_dl=tb&rsv_enter=0&rsv_btype=t&prefixsug=playwright&rsp=5"
# Click text=百度一下
# with page.expect_navigation(url="https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&rsv_idx=1&tn=baidu&wd=playwright&fenlei=256&oq=playwright&rsv_pq=a03207ba00008498&rsv_t=ecf2ko5wPyHrjSHwUBLAZZwxkyObcfsg5ge7apN1BeAdigW%2BzzxD%2F3CJI7k&rqlang=cn&rsv_dl=tb&rsv_enter=0&rsv_btype=t&prefixsug=playwright&rsp=5"):
with page.expect_navigation():
page.click( "text=百度一下" )
# Click text=百度一下
page.click( "text=百度一下" )
# assert page.url == "https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&rsv_idx=1&tn=baidu&wd=playwright&fenlei=256&oq=playwright&rsv_pq=bf1abd6c000029f7&rsv_t=1937PYyfHvfyS6fay57V1zS1iCIiYC4%2B8I6srjLqYYkXrf8H9kce%2BLQKVzA&rqlang=cn&rsv_dl=tb&rsv_enter=0&rsv_btype=t&prefixsug=playwright&rsp=5"
# ---------------------
context.close()
browser.close()
with sync_playwright() as playwright:
run(playwright)
|
最后将录制的脚本复制出来,可做适当的调整。
调整后的脚本代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
from playwright.sync_api import sync_playwright # 导入playwright同步api
def run(playwright): # 定义run方法
browser = playwright.chromium.launch(headless = False ) # 创建chromium的browser对象,当前使用的是playwright安装的自带的chromium
context = browser.new_context() # 创建context对象,context之间是相互隔离的,可以理解为轻量级的浏览器实例
page = context.new_page() # 创建page对象,真正打开浏览器界面
page.goto( "https://www.baidu.com/" ) # 跳转到百度url
page.fill( "input[name=\"wd\"]" , "playwright" ) # 通过css定位在搜索框中输入"playwright"
with page.expect_navigation(): # 预期结果,点击"百度一下"按钮后会发生页面导航
page.click( "text=百度一下" ) # 通过playwright自定义的文字定位器定位"百度一下"按钮并点击
# ---------------------
context.close() # 关闭context
browser.close() # 关闭browser
with sync_playwright() as playwright: # playwright使用入口,通过上下文方式
run(playwright) # 调用run方法,将playwright实例传入
|
2、模拟移动设备录制
open 可以模拟移动设备和平板设备
例如模拟 iPhone 14 访问博客园。
1 |
playwright open - - device = "iPhone 14" home.cnblogs.com / u / keima /
|
通过以上代码可以了解到:
- playwright支持同步和异步两种使用方法
- 不需要为每个浏览器下载webdriver
- 相比selenium多了一层context抽象
- 支持无头浏览器,且较为推荐(headless默认值为True)
- 可以使用传统定位方式(CSS,XPATH等),也有自定义的新的定位方式(如文字定位)
- 没有使用selenium的先定位元素,再进行操作的方式,而是在操作方法中传入了元素定位,定位和操作同时进行(其实也playwright也提供了单独的定位方法,作为可选)
- 很多方法使用了with的上下文语法
六、编写模式
使用 IDE(如 PyCharm、Visual Studio Code 等) 进行编写代码并运行程序。
1、启动浏览器(无头模式)
Playwright 可以启动三种浏览器中的 chromium、firefox、webkit 任何一种。
示例操作如下,打开浏览器、跳转百度、屏幕截图、输出页面标题、关闭浏览器。
1 2 3 4 5 6 7 8 9 |
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
browser = p.chromium.launch()
page = browser.new_page()
page.goto( "https://www.baidu.com/" )
page.screenshot(path = "example.png" )
print (page.title())
browser.close()
|
2、启动浏览器(有头模式)
默认情况下,Playwright 以无头模式运行浏览器。要查看浏览器 UI(有头模式),请在启动浏览器时传递 headless=False 标志,还可以使用 slow_mo 来减慢执行速度。
1 2 3 4 5 6 7 8 9 |
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
browser = p.chromium.launch(headless = False , slow_mo = 50 )
page = browser.new_page()
page.goto( "https://www.baidu.com/" )
page.screenshot(path = "example.png" )
print (page.title())
browser.close()
|
3、异步
Playwright 支持 API 的两种变体:同步和异步。
支持异步,如果你的项目使用 asyncio,则应该使用 async API。
1 2 3 4 5 6 7 8 9 10 11 |
import asyncio
from playwright.async_api import async_playwright
async def main():
async with async_playwright() as p:
browser = await p.chromium.launch()
page = await browser.new_page()
await page.goto( "https://www.baidu.com/" )
print (await page.title())
await browser.close()
asyncio.run(main())
|
4、context
Playwright 支持上下文管理:一个浏览器实例下可以有多个context,将浏览器分割成不同的上下文,以实现会话的分离。
如需要不同用户登录同一个网页,不需要创建多个浏览器实例,只需要创建多个context即可。
1 2 |
context1 = browser.new_context()
context2 = browser.new_context()
|
5、page
一个context下可以有多个page,一个page就代表一个浏览器的标签页或弹出窗口,用于进行页面操作。
1 2 3 4 5 6 7 8 9 10 |
page = context.new_page()
# 显式导航,类似于在浏览器中输入URL
page.goto( 'https://www.baidu.com/' )
# 在输入框中输入字符
page.fill( '#search' , '百度' )
# 点击提交按钮
page.click( '#submit' )
# 打印当前url
print (page.url)
|
6、browser
Playwright内置了很多支持的浏览器驱动,不用再像selenium那样去寻找对应匹配版本的浏览器驱动版本下载。
只需要创建相应的browser实例。
1 2 |
browser = playwright.chromium.launch() #Chrome
browser = playwright.firefox.launch() #火狐
|
7、frame
一个页面至少包含一个主frame,新的frame通过iframe标签定义,frame之间可以进行嵌套,只有先定位到frame才能对frame里面的元素进行定位和操作。playwright默认使用page进行的元素操作会重定向到主frame上。
1 2 3 4 5 6 7 8 9 10 11 12 |
# 通过名称获得frame
frame = page.frame( 'frame-login' )
# 通过frame的url获得frame
frame = page.frame(url = r '.*domain.*' )
# 通过选择器获得frame
frame_element_handle = page.query_selector( '.frame-class' )
frame = frame_element_handle.content_frame()
# 操作frame中的元素
frame.fill( '#username-input' , 'JoJo' )
|
8、选择器
所有元素操作都需要使用选择器定位到要操作的元素,playwright同时支持css、xpath和自定义的选择器,使用时无需指定类型,playwright会自动进行判断。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
# Using data-test-id= selector engine
page.click( 'data-test-id=foo' )
# CSS and XPath selector engines are automatically detected
page.click( 'div' )
page.click( '//html/body/div' )
# Find node by text substring
page.click( 'text=Hello w' )
# Explicit CSS and XPath notation
page.click( 'css=div' )
page.click( 'xpath=//html/body/div' )
# Click an element with text 'Sign Up' inside of a #free-month-promo.
page.click( '#free-month-promo >> text=Sign Up' )
# Capture textContent of a section that contains an element with text 'Selectors'.
section_text = page.eval_on_selector( '*css=section >> text=Selectors' , 'e => e.textContent' )
|
9、自动等待
像page.click(selector)、page.fill(selector, value)之类的元素操作会自动等待元素可见且可操作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
# Playwright 会等待 #search 元素出现在 DOM 中
page.fill( '#search' , 'query' )
# Playwright 会等待元素停止动画并接受点击
page.click( '#search' )
# 等待 #search 出现在 DOM 中
page.wait_for_selector( '#search' , state = 'attached' )
# 等待 #promo 可见, 例如具有 `visibility:visible`
page.wait_for_selector( '#promo' )
# 等待 #details 变得不可见, 例如通过 `display:none`.
page.wait_for_selector( '#details' , state = 'hidden' )
# 等待 #promo 从 DOM 中移除
page.wait_for_selector( '#promo' , state = 'detached' )
|
七、实例
1、网易云签到
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
import time
from playwright.sync_api import Playwright, sync_playwright, expect
def run(playwright: Playwright) - > None :
browser = playwright.chromium.launch(headless = False )
context = browser.new_context(viewport = { 'width' : 1920 , 'height' : 1080 })
# Open new page
page = context.new_page()
# Go to https://music.163.com/
page.goto( "https://music.163.com/" )
# Click text=用户登录
page.frame_locator( "iframe[name=\"contentFrame\"]" ).locator( "text=用户登录" ).click()
# Click text=选择其他登录模式
page.locator( "text=选择其他登录模式" ).click()
# Check input[type="checkbox"]
page.locator( "input[type=\"checkbox\"]" ).check()
# Click text=QQ登录
with page.expect_popup() as popup_info:
page.locator( "text=QQ登录" ).click()
page1 = popup_info.value
# Click #img_out_****
page1.frame_locator( "iframe[name=\"ptlogin_iframe\"]" ).locator( "#img_out_****" ).click()
# token用*代替
page1.wait_for_url(f "https://music.163.com/back/sns?key=*" )
# Close page
page1.close()
# Click text=我的音乐
page.locator( "text=我的音乐" ).click()
page.wait_for_url( "https://music.163.com/#/my/m/music/playlist?id=152392364" )
time.sleep( 3 )
# Click a:has-text("播放")
page.frame_locator( "iframe[name=\"contentFrame\"]" ).locator( "a:has-text(\"播放\")" ).click()
time.sleep( 10 )
# Click text=网易云音乐
page.locator( "text=网易云音乐" ).click()
page.wait_for_url( "https://music.163.com/#" )
# Click a:has-text("签到")
page.frame_locator( "iframe[name=\"contentFrame\"]" ).locator( '//*[@id="discover-module"]/div[2]/div[1]/div/div/div/div/a/i' ).click()
time.sleep( 10 )
# Close page
page.close()
# ---------------------
context.close()
browser.close()
print ( '******************************* 签到完成 *******************************' )
with sync_playwright() as playwright:
run(playwright)
|
点击
左键点击:page.click(“id=su”)
点击元素左上角:page.click(‘id=su’, position={‘x’: 0, ‘y’: 0})
Shift + click:page.click(“id=su”, modifiers=[‘Shift’])
强制点击:page.click(“id=su”, force=True)
右键点击:page.click(“id=su”, button=‘right’)
双击:page.dblclick(“id=su”)
悬停在元素上:page.hover(‘id=su’)
————————————————
参考:https://blog.csdn.net/qq_40279560/article/details/129297181?spm=1001.2101.3001.6650.4&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-4-129297181-blog-131596058.235%5Ev43%5Epc_blog_bottom_relevance_base2&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-4-129297181-blog-131596058.235%5Ev43%5Epc_blog_bottom_relevance_base2&utm_relevant_index=9
https://blog.csdn.net/qq_40279560/article/details/129297181?spm=1001.2101.3001.6650.4&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-4-129297181-blog-131596058.235%5Ev43%5Epc_blog_bottom_relevance_base2&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-4-129297181-blog-131596058.235%5Ev43%5Epc_blog_bottom_relevance_base2&utm_relevant_index=9 标签:playwright,浏览器,text,page,测试,自动化,click,browser From: https://www.cnblogs.com/klb561/p/17998923