点击名片关注阿尘blog,一起学习,一起成长
本文主要分享由微软开发的实现Web UI自动化测试工具Playwright库,相比于之前学习过selenium库,playwright对于编写自动化代码绝对是更轻松了,因为它支持脚本录制,如果只求简单点可以不用写一行代码就能够实现自动化,而且playwright有许多强大的api,很多功能比起selenium都轻松简单,好了话不多说,开启正文~
playwright简介和初步使用
1.1 playwright简介
playwright优点(这里就直接摘抄一下官网的哈,不是重点)
任意浏览器 • 全平台 • 同一套 API
跨浏览器。 Playwright 支持所有现代渲染引擎,包括:Chromium、WebKit 和 Firefox。
跨平台。 适用于 Windows、Linux、macOS、本地运行、 CI、headless 和 headed。
跨语言。 在 TypeScript, JavaScript, Python, .NET, Java 中使用 Playwright API
测试移动端 Web 。 对 Android 和 Mobile Safari 的 Google Chrome 原生移动端模拟。与你的移动端和云端应用采用相同的渲染引擎。
强适应性 • 测试不再容易失效
自动等待(auto-waits)。 Playwright 能够自动等待元素达到可操作的状态,外加一系列丰富的内置事件。不用再人工定义超时(timeouts) —— 这是测试容易失效的主要原因。
Web 优先的断言。 Playwright 断言专门为动态加载的 web 应用设计。能够在满足需要的条件前自动重试。
可追踪。 通过配置重试策略,采用捕捉执行轨迹、视频、截图来解决测试容易失效的问题。
不用再权衡取舍 • 不再有限制
浏览器在不同进程中运行属于不同来源的 Web 内容。Playwright 与现代浏览器架构保持一致,并在进程外运行测试。这使 Playwright 摆脱了典型的进程内测试运行程序限制。
一切并行。 跨越多个 tabs, 多个 origins 和多个 users 的测试场景。在一个测试中能够为不同的用户创建具有不同上下文的场景,并能在你的服务器上运行。
可信事件。 元素悬停(hover)、动态控件的交互、生产可信事件。Playwright 使用与真实用户一致的输入方式(pipeline)。
测试 frames,穿透 Shadow DOM。 Playwright 的选择器能够穿透 shadowDOM 和允许无缝输入 frame。
完全隔离 • 快速执行
浏览器上下文。 Playwright 为每个测试创建一个浏览器上下文。浏览器上下文相当于一个全新的浏览器配置文件。这提供了零开销的完整测试隔离。创建一个新的浏览器上下文只需要几毫秒。
一次登录。 保存上下文的身份验证状态并在所有测试中重用它。这绕过了每个测试中的重复登录操作,但提供了独立测试的完全隔离。
强大的工具
Codegen 。 通过记录您的操作来生成测试。将它们保存为各种语言。
Playwright inspector 。 检查页面,生成选择器,逐步执行测试,查看点击点,浏览执行日志。
Trace Viewer 。 捕获所有的信息来调查失败了的测试,Playwright 追踪包含测试运行截屏视频、实时 DOM 快照、动作浏览器、测试源等信息。
1.2 playwright安装与使用
playwright的安装(python3.7+)
pip install playwright
Playwright 安装驱动,相比起selenium就简单多了
python -m playwright install
Playwright 录制脚本
python -m playwright codegen
通过–help 查看可以用哪些参数
python -m playwright codegen --helpUsage: playwright codegen [options] [url]open page and generate code for user actionsOptions:-o, --output saves the generated script to a file--target language to generate, one of javascript, playwright-test, python, python-async, python-pytest, csharp, csharp-mstest, csharp-nunit, java (default: "python")--save-trace record a trace for the session and save it to a file--test-id-attribute use the specified attribute to generate data test ID selectors-b, --browser browser to use, one of cr, chromium, ff, firefox, wk, webkit (default: "chromium")--block-service-workersblock service workers--channel Chromium distribution channel, "chrome", "chrome-beta", "msedge-dev", etc--color-scheme emulate preferred color scheme, "light" or "dark"--device emulate device, for example"iPhone 11"--geolocation specify geolocation coordinates, for example "37.819722,-122.478611"--ignore-https-errorsignore https errors--load-storage load context storage state from the file, previously saved with --save-storage--lang specify language / locale, for example "en-GB"--proxy-server specify proxy server, for example "http://myproxy:3128" or "socks5://myproxy:8080"--proxy-bypass comma-separated domains to bypass proxy, for example ".com,chromium.org,.domain.com"--save-har save HAR file with all network activity at the end--save-har-glob filter entries in the HAR by matching url against this glob pattern--save-storage save context storage state at the end, for later use with --load-storage--timezone time zone to emulate, for example "Europe/Rome"--timeout timeout for Playwright actions in milliseconds, no timeout by default--user-agent specify user agent string--viewport-size specify browser viewport size in pixels, for example "1280, 720"-h, --help display help for commandExamples:$ codegen$ codegen --target=python$ codegen -b webkit https://example.com
有很多,这里只挑几个简单的常用的来说
-o:指定脚本录制输出位置;
–target:指定脚本语言,告诉他用什么语言写,后面一大堆,还有个python-pytest!,默认用python
-b:指定浏览器驱动,默认用的谷歌
那我们来小试牛刀:
python -m playwright codegen -o "D:\PythonProject\playwright_project\playwright_code.py"
运行之后我们用它自动打开的谷歌浏览器,打开百度,输入漂亮小姐姐并查找,结束录制,看看录制脚本
from playwright.sync_api import Playwright, sync_playwright, expectdef run(playwright: Playwright) -> None:browser = playwright.chromium.launch(headless=False)context = browser.new_context()page = context.new_page()page.goto("https://www.baidu.com/")page.locator("#kw").click()page.locator("#kw").fill("漂亮小姐姐")page.get_by_role("button", name="百度一下").click()# ---------------------context.close()browser.close()with sync_playwright() as playwright:run(playwright)
查看是否成功运行
OK,完全可以,但是我们对它的脚本,有哪些功能怎么使用还完全不了解,下面来系统学习一下
1.3 playwright的脚本编写
playwright代码的编写,有两种模式:同步模式和异步模式
同步模式就如同selenium,上面录制脚本的示例就采用的同步模式,同步模式的语法如下
# 同步模式# 导入Playwright类和sync_palywright 同步类from playwright.sync_api import Playwright,sync_playwrightdef main(playwright):browser = playwright.chromium.launch(headless=False)context = browser.new_context()page = context.new_page()page.goto("https://www.baidu.com/")print(page.title())context.close()browser.close()with sync_playwright() as p:main(p)
同步模式主要用的sync_playwright的api
异步模式语法:
# 异步模式import asynciofrom playwright.async_api import Playwright,async_playwrightasync def main():async with async_playwright() as p:browser = await p.chromium.launch(headless=False)context = await browser.new_context()page = await context.new_page()await page.goto("https://www.baidu.com/")print(await page.title())await context.close()await browser.close()asyncio.run(main())
它俩很相似,异步模式主要用了async_playwright的api,主要采用async/await 关键字
接下来详细解释下里面的方法、类:
1、Playwright类
主要用于定义设备的信息,为page服务或者context服务
2、生成浏览器驱动:
browser = playwright.chromium.launch(headless=False)
可支持的浏览器有‘chromium’,
‘webkit’ or
‘firefox‘
launch函数的使用
def launch(self,*,executable_path: typing.Optional[typing.Union[str, pathlib.Path]] = None,# 传入一个浏览器可执行的文件必须绑定支持的浏览器channel: typing.Optional[str] = None,#传入浏览器的版本,有"chrome", "chrome-beta", "chrome-dev", "chrome-canary",# "msedge", "msedge-beta", "msedge-dev", "msedge-canary",msedge是Microsoft edge,还有其他版本可以查看官网args: typing.Optional[typing.List[str]] = None,#传递给浏览器的其他参数,以列表形式传入ignore_default_args: typing.Optional[typing.Union[bool, typing.List[str]]] = None,# 如果为'true',Playwright不会传递自己的配置参数,而只使用来自'args'的配置参数。如果数组是# 给定,然后过滤掉给定的默认参数。危险选项;小心使用。默认为“False”。handle_sigint: typing.Optional[bool] = None,# 通过Ctrl+c关闭浏览器的进程,默认开启handle_sigterm: typing.Optional[bool] = None,# 收到SIGTERM信号正常关闭浏览器进程,默认开启handle_sighup: typing.Optional[bool] = None,# 收到SIGHUP信号终止浏览器进程,默认开启timeout: typing.Optional[float] = None,# 等待浏览器实例启动的最长时间(以毫秒为单位)。默认为“30000”(30秒)。传递“0”以禁用超时。env: typing.Optional[typing.Dict[str, typing.Union[str, float, bool]]] = None,# 指定浏览器可见的环境变量。默认为process. envheadless: typing.Optional[bool] = None,# 是否在没有窗口下运行浏览器,默认开启,开启后你就看不到程序打开浏览器,一般传入Falsedevtools: typing.Optional[bool] = None,# **仅Chromium**是否为每个选项卡自动打开开发人员工具面板。如果此选项为“真”,则“无头”选项将设置为“false”。proxy: typing.Optional[ProxySettings] = None,# 网络代理设置downloads_path: typing.Optional[typing.Union[str, pathlib.Path]] = None,# 如果指定,接受的下载将下载到此目录中。否则,将创建临时目录并当浏览器关闭时被删除。在任何一种情况下,下载都会在它们所在的浏览器上下文关闭时被删除。slow_mo: typing.Optional[float] = None,# 将Playwright操作减慢指定的毫秒数。这个很有用,以便您可以看到正在发生的事情。traces_dir: typing.Optional[typing.Union[str, pathlib.Path]] = None,# 如果指定,跟踪将保存到此目录中。chromium_sandbox: typing.Optional[bool] = None,# 启用Chromium沙盒。默认为Falsefirefox_user_prefs: typing.Optional[typing.Dict[str, typing.Union[str, float, bool]]] = None# 一些火狐偏好设置) -> "Browser":
3、生成浏览器上下文(context)对象
浏览器上下文对象是浏览器实例中一个独立隐身会话,资源、cookie缓存这些不与其他上下文共享,对于自动化多用户、多场景测试非常有意义,相当于打开两个浏览器,两个进程,可以每个测试用例单独开一个上下文,需要注意的是,浏览器上下文最好显式的关闭,也就是
context.close()
上下文的方法,这里就简单说一下两个参数,其余不详细说了,如果有需要可以查看api
viewport : Union[{width: int, height: int}, None]# 为每个页面设置一致的视口。默认为1280x720视口screen : Union[{width: int, height: int}, None]# 通过“window.screen”模拟网页内可用的一致窗口屏幕大小 ,只能在viewport设置之后使用
context常用操作
context.pages
:获取context所有page对象
context.new_page()
:生成一个新的page对象
context.close()
:关闭context
context.add_cookies()
:将cookie添加到此浏览器上下文中。此上下文中的所有页面都将安装这些cookie。
只能传入列表
List[{name: str, value: str, url: Union[str, None], domain: Union[str, None], path: Union[str, None], expires: Union[float, None]
context.clear_cookies()
:清除context的cookie
context.grant_permissions()
:授予浏览器上下文的指定权限,具体见api
context.clear_permissions()
:清除授权
4、生成浏览器页面page
page = context.new_page()
page就相当于浏览器的选项卡,一般在浏览器context上创建,后续打开网页 ,业绩元素定位,页面操作都是基于page
首先来了解一下page的常用参数
async def new_page(self,viewport: ViewportSize = None,#为每个页面设置一致的视口。默认为1280x720视口screen: ViewportSize = None, # 通过“window.screen”模拟网页内可用的一致窗口屏幕大小 ,只能在viewport设置之后使用noViewport: bool = None,# 不强制固定视口,允许在标题模式下调整窗口大小ignoreHTTPSErrors: bool = None,javaScriptEnabled: bool = None,bypassCSP: bool = None,userAgent: str = None, # 设置代理用于上下文locale: str = None, #指定用户区域,设置将影响Accept-Language'请求标头值以及数字和日期格式规则timezoneId: str = None,geolocation: Geolocation = None,permissions: List[str] = None,extraHTTPHeaders: Dict[str, str] = None,offline: bool = None,httpCredentials: HttpCredentials = None,deviceScaleFactor: float = None,isMobile: bool = None, #设备相关,不用管hasTouch: bool = None,colorScheme: ColorScheme = None, #Union["dark", "light", "no-preference", "null", None]#设置颜色主题forcedColors: ForcedColors = None, #Union["active", "none", "null", None]reducedMotion: ReducedMotion = None,acceptDownloads: bool = None,defaultBrowserType: str = None,proxy: ProxySettings = None,recordHarPath: Union[Path, str] = None,recordHarOmitContent: bool = None,recordVideoDir: Union[Path, str] = None,recordVideoSize: ViewportSize = None,storageState: Union[StorageState, str, Path] = None,baseURL: str = None,strictSelectors: bool = None,serviceWorkers: ServiceWorkersPolicy = None,recordHarUrlFilter: Union[Pattern[str], str] = None,recordHarMode: HarMode = None,recordHarContent: HarContentPolicy = None,) -> Page:
page常用操作
page.goto(url,timeout,waitUntil,referer)
:打开一个新的网页
url传入一个字符串,导航到该地址
timeout 最大等待时间,传入毫秒,默认30s,为0则禁用,不等待
waitUntil
:定义触发事件,当定义事件触发将被认为操作成功
可选[“commit”, “domcontentloaded”, “load”, “networkidle”, None]
domcontentloaded:出现【文件加载中】就被认为操作成功
load:出现【加载】事件就被认为操作成功
networkidle:当发生【没有网络(网络空闲)】被认为操作成功,超过500ms没有网络就触发了【不建议使用】
commit:当网络响应被接受,文件开始加载,就认为操作成功了
referer:可以传入str或者none,引用头部,如果设置就有限用这个作为header
page.locator()
:playwright的核心功能之一,元素定位器,常用的元素定位方法在后面单独拎出来讲
元素定位的常用操作
page.locator().click():点击元素
page.locator().dblclick():双击元素,double click
page.locator().fill():输入str
click和fill操作只可以直接在页面操作
比如
page.fill('css=[name="username"]',"017575863") page.fill('css=[name="password"]',"06523244")
page.locator().count():返回匹配元素的个数
page.locator().clear():清空input的内容
page.locator().drag_to():把一个元素拖到另一个元素位置然后释放
page.locator().frame_locator():使用iframe时,您可以创建一个帧定位器,该定位器将进入iframe并允许选择iframe中元素。
示例:
locator = page.frame_locator(\"#my-iframe\").get_by_text(\"Submit\")await locator.click()locator = page.frame_locator(\"#my-iframe\").get_by_text(\"Submit\")locator.click()
page.locator().all_text_contents():返回对应元素所有文本内容,基于代码不会格式化,返回的是列表
page.locator().all_inner_texts():返回对应元素所有文本内容,基于页面,格式化,返回列表
page.locator().get_attribute():返回匹配元素的属性值
page.locator().wait_for():等待元素加载,没必要,playwright会自动等待直到触发load事件。
page.locator().filter():此方法根据选项缩小现有定位器,例如按文本过滤。它可以多次过滤。
示例:
await row_locator.filter(has_text=\"text in column 1\").filter(has=page.get_by_role(\"button\", name=\"column 2 button\")).screenshot()
page.frame()
:返回指定的frame,必须传入name 或者urlpage.frame_locator()
:定位一个frame,并可以切换进去定位元素
locator = page.frame_locator(\"#my-iframe\").get_by_text(\"Submit\")await locator.click()
page.content()
:返回页面内容
page.set_default_navigation_timeout()
:设置超时默认时间
page.keyboard.press()
:键盘操作(直接在page页面),可以输入的键有以下
F1
– F12
, Digit0
– Digit9
, KeyA
– KeyZ
, Backquote
, Minus
, Equal
, Backslash
, Backspace
, Tab
,Delete
, Escape
, ArrowDown
, End
, Enter
, Home
, Insert
, PageDown
, PageUp
, ArrowRight
, ArrowUp
,etc.
page.screenshot()
:截屏
page.press(selector,key)
:找到元素,然后调用键盘的按下、放开某个键的操作
page.keyboard.press(\"Shift+O\")page.press(\"body\", \"Shift+O\")
page.close()
:关闭页面
page.wait_for_load_state(state)
:当达到所需的加载状态时返回。state有[“domcontentloaded”, “load”, “networkidle”]
当页面达到所需的加载状态时,默认为“加载”。调用此方法时导航必须是已经发送请求了。如果当前文档已经达到所需状态,则立即解析。
page.route()
:网络劫持,路由提供了修改页面发出的网络请求的能力。一个强大api
page = await browser.new_page()await page.route(re.compile(r\"(\\.png$)|(\\.jpg$)\"), lambda route: route.abort())await page.goto(\"https://example.com\")await browser.close()
劫持响应结果
我们要让百度详情结果为我们的定义的页面:custom_response.html
hack test hack test
from playwright.sync_api import sync_playwrightwith sync_playwright() as p:browser = p.chromium.launch(headless=False)page = browser.new_page()page.route('**/*',lambda route: route.fulfill(path='./custom_response.html'))page.goto("https://www.baidu.com")browser.close()
page.expect_download():下载文件
示例
# 开始下载with page.expect_download() as download_info:# 点击下载的按钮page.locator("button#delayed-download").click()download = download_info.value# 等待下载print(download.path())# 保存文件download.save_as("/path/to/save/download/at.txt")
5、定位方法
playwright定位主要通过slector选择器定位支持文本定位、css定位、xpath定位、组合定位
文本选择器
page.click('text=登录') # 没有加引号(单引号或者双引号),模糊匹配,对大小写不敏感 page.click('text="登录"')# 有引号,精确匹配,对大小写敏感
has_text()查找子代或后代所有包含对应文本的,相反的也有has_not_text()
text()查找第一个文本等于…的元素
比如:Playwright