Playwright 是什么
微软在 2020 年初开源的新一代自动化测试工具,它的功能类似于 Selenium,可以驱动浏览器进行各种自动化操作。它的功能也非常强大,对市面上的主流浏览器都提供了支持,API 功能简洁又强大。虽然诞生比较晚,但是现在发展得非常火热。 Playwright 支持大部分的语言,Node.js,Python,Java,.net,并且支持谷歌,火狐浏览器,WebKit,对于移动端也支持,可以在 Windows、Linux、MacOs 等机器上运行。脚本执行支持同步或者异步的方式。
官方网站:https://playwright.dev/docs/intro
Github源码:https://github.com/microsoft/playwright-python
Playwright 的优势
跨浏览器和平台
- 跨浏览器。Playwright 支持所有现代渲染引擎,包括 Chromium、WebKit 和 Firefox。
- 跨平台。在 Windows、Linux 和 macOS 上进行本地测试或在 CI 上进行无头或有头测试。
- 跨语言。在TypeScript、JavaScript、Python、.NET、Java中使用 Playwright API 。
- 测试移动网络。适用于 Android 和 Mobile Safari 的 Google Chrome 浏览器的本机移动仿真。相同的渲染引擎适用于您的桌面和云端。
稳定性
- 自动等待。Playwright 在执行动作之前等待元素可操作。它还具有一组丰富的内省事件。两者的结合消除了人为超时的需要——这是不稳定测试的主要原因。
- Web优先断言。Playwright 断言是专门为动态网络创建的。检查会自动重试,直到满足必要的条件。
- 追踪。配置测试重试策略,捕获执行跟踪、视频、屏幕截图。
运行机制
浏览器在不同进程中运行属于不同来源的 Web 内容。Playwright 与现代浏览器架构保持一致,并在进程外运行测试。这使得 Playwright 摆脱了典型的进程内测试运行器的限制。
- 多重一切。测试跨越多个选项卡、多个来源和多个用户的场景。为不同的用户创建具有不同上下文的场景,并在您的服务器上运行它们,所有这些都在一次测试中完成。
- 可信事件。悬停元素,与动态控件交互,产生可信事件。Playwright 使用与真实用户无法区分的真实浏览器输入管道。
- 测试框架,穿透 Shadow DOM。Playwright 选择器穿透影子 DOM 并允许无缝地输入帧。
完全隔离-快速执行
- 浏览器上下文。Playwright 为每个测试创建一个浏览器上下文。浏览器上下文相当于一个全新的浏览器配置文件。这提供了零开销的完全测试隔离。创建一个新的浏览器上下文只需要几毫秒。
- 登录一次。保存上下文的身份验证状态并在所有测试中重用它。这绕过了每个测试中的重复登录操作,但提供了独立测试的完全隔离。
强大的工具
- 代码生成器。通过记录您的操作来生成测试。将它们保存为任何语言。
- 调试。检查页面、生成选择器、逐步执行测试、查看点击点、探索执行日志。
- 跟踪查看器。捕获所有信息以调查测试失败。Playwright 跟踪包含测试执行截屏、实时 DOM 快照、动作资源管理器、测试源等等。
Playwright主要特点有
- 跨浏览器支持
- 跨平台
- 多语言支持
- 支持无头和有头浏览器支持。
- 提供了同步和异步API。
- 支持自动化脚本录制
- 测试过程跟踪(路径、截图)
- 强大网络控制
- 丰富的调试(截图、日志、录屏)
安装Playwright
pip install playwright
playwright install # 安装支持的浏览器:cr, chromium, ff, firefox, wk 和 webkit
playwright install chromium # 安装指定的chromium浏览器
# 安装时会自动下载浏览器依赖,windows系统在%USERPROFILE%\AppData\Local\ms-playwright 路径下
如果安装报错,提示缺少Visual C++, 解决办法:安装Microsoft Visual C++ Redistributable 2019:"https://aka.ms/vs/16/release/VC_redist.x64.exe"。
离线下载
下载单个离线包
下载单个离线包:下载单个离线包: pip download -d 文件夹名或者路径
pip download playwright -d ./down
批量下载离线包
确认依赖包名与版本:在其他环境中找到要安装的依赖包名及版本并导出:pip freeze > requirements.txt,requirements.txt中即为要的包信息。就以上边的playwright包为例。本地已经安装了一些依赖包了,可以通过pip freeze > requirements.txt
, 导出本地的全部依赖包到requirements.txt文件。
进入依赖包的文件夹中,输入命令: pip freeze > requirements.txt 。
pip download -r requirements.txt -d ./down
离线安装
单个离线安装
安装单个离线包: pip install --no-index --find-links=/资源文件夹/
把前面下载的down文件下全部包上传到你局域网的电脑上。本地离线单个安装依赖包pip install --no-index --find-links=D:\software\Python\Python37\Lib\site-packages -r greenlet-2.0.1-cp37-cp37m-win_amd64.whl
批量离线安装
批量安装离线包:pip install --no-index --find-links=/资源文件夹/ -r requirements.txt
把前面下载的down文件下全部包,以及requirements.txt文件上传到你局域网的电脑上。本地离线批量安装依赖包pip install --no-index --find-links=D:\software\Python\Python37\Lib\site-packages -r requirements.txt
离线安装浏览器
playwright install --dry-run
它会根据你当前安装的playwright版本,给出对应的浏览器最近匹配版本,以及下载地址
安装chromium
这个和在线安装一样,就是下载对应的安装包,然后安装到在线安装浏览器的那个路径下即可。
1、以 chromium 安装为例,从上边的docs命令窗口我们可以清楚的看到chromium的Download url: https://playwright.azureedge.net/builds/chromium/1060/chromium-win64.zip
2.先下载: https://playwright.azureedge.net/builds/chromium/1060/chromium-win64.zip
3.下载后是一个chromium-win64.zip压缩包。
4.接着看Install location 安装位置:
%USERPROFILE%\AppData\Local\ms-playwright\chromium-1060
按照这个路径依次创建文件夹,把压缩包放到chromium-1060下解压即可
5.还有个 ffmpeg 包也需要按上面的路径正确解压,此包跟录制视频有关。
使用本地浏览器
只需指定channel='chrome'
就可以启动本地chrome 浏览器。
# coding=utf-8
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
browser = p.chromium.launch(channel="chrome", headless=False)
browser = p.chromium.launch(channel="msedge", headless=False)
browser = p.webkit.launch(headless=False)
browser = p.firefox.launch(headless=False)
page = browser.new_page() # 打开一个标签页
page.goto("https://www.baidu.com") # 打开百度地址
print(page.title()) # 打印当前页面title
page.click("input[name=\"wd\"]") # 点击输入框
page.fill("input[name=\"wd\"]", "chromium") # 在输入框输入浏览器名字
page.screenshot(path=f'example-{p.chromium.name}.png')
browser.close() # 关闭浏览器对象
# 另一种方法
from playwright.sync_api import sync_playwright
playwright = sync_playwright().start()
browser = playwright.chromium.launch(headless=False)
page = browser.new_page()
page.goto("https://www.baidu.com/")
browser.close()
playwright.stop()
playwright的API
Playwright支持同步和异步两种API,使用异步API需要导入asyncio库,它是一个可以用来实现Python协程的库,更详细介绍可参考Python协程 。我们可以根据自己的偏好选择适合的模式。
同步与异步模式原理
同步操作方式:在代码执行时,程序会阻塞等待每个操作执行的结果,直到该操作执行结束才能继续执行后面的代码。同步代码容易理解和编写,但如果在网络请求等 I/O 操作时会造成大量的等待时间,影响程序的执行效率。
异步操作方式:在代码执行时,当遇到需要等待操作执行的时候,程序不会被阻塞,而是继续执行其他的代码。当该操作执行的结果返回时,程序会自动跳回去接着执行之前被暂停的代码。异步操作虽然需要一定的学习成本,但可以提升程序的执行效率。
同步模式
- 直接顺序执行测试逻辑,直到完成。
- 使用上下文管理器或启动/关闭方法控制浏览器生命周期。
- 简单易用,适合同步测试场景。
- 但无法实现异步或重叠的测试逻辑。
异步模式
- 利用asyncio模块以异步非阻塞方式执行测试逻辑。
- 浏览器启动/关闭和大多数Playwright API也是异步的,需要await。
- 可以实现复杂的异步或重叠测试逻辑。
- 但较难调试,有一定学习成本。
同步和异步的概念
- 同步:发送一个请求,等待返回,然后再发送下一个请求。
- 异步:发送一个请求,不等待返回,随时可以再发送下一个请求。
同步和异步实践
测试用例
这里假设一共有2条测试用例,用例1步骤如下:
1)chrome浏览器打开百度
2)搜索框输入“test”
3)点击百度一下搜索
4)点击搜索结果的第2页
用例2步骤:
1)chrome浏览器打开搜狗搜索
2)搜索框输入“test”
3)点击搜狗搜索
4)点击搜索结果的第2页
同步
这里我们使用sync_playwright上下文管理器同步启动Playwright,然后编写同步测试逻辑。
import time
from playwright.sync_api import sync_playwright
def testcase1():
print('testcase1 start')
with sync_playwright() as p:
browser = p.chromium.launch(headless=False)
page = browser.new_page()
page.goto("https://www.baidu.com/")
print(page.title())
page.fill("input[name=\"wd\"]", "test")
page.click("text=百度一下")
page.click("#page >> text=2")
browser.close()
print('testcase1 done')
def testcase2():
print('testcase2 start')
with sync_playwright() as p:
browser2 = p.chromium.launch(headless=False)
page2 = browser2.new_page()
page2.goto("https://www.sogou.com/")
print(page2.title())
page2.fill("input[name=\"query\"]", "test")
page2.click("text=搜狗搜索")
page2.click("#sogou_page_2")
browser2.close()
print('testcase2 done')
start = time.time()
testcase1()
testcase2()
end = time.time()
print('Running time: %s Seconds' % (end - start))
异步
这里我们使用asyncio模块异步启动Playwright,然后编写异步测试逻辑。需要使用await关键字标识异步操作。
import asyncio
import time
from playwright.async_api import async_playwright
async def testcase1():
print('testcase1 start')
async with async_playwright() as p:
browser = await p.chromium.launch(headless=False)
page = await browser.new_page()
await page.goto("https://www.baidu.com/")
print(await page.title())
await page.fill("input[name=\"wd\"]", "test")
await page.click("text=百度一下")
await page.click("#page >> text=2")
await browser.close()
print('testcase1 done')
async def testcase2():
print('testcase2 start')
async with async_playwright() as p:
browser2 = await p.chromium.launch(headless=False)
page2 = await browser2.new_page()
await page2.goto("https://www.sogou.com/")
print(await page2.title())
await page2.fill("input[name=\"query\"]", "test")
await page2.click("text=搜狗搜索")
await page2.click("#sogou_page_2")
await browser2.close()
print('testcase2 done')
async def main():
task1 = asyncio.create_task(testcase1())
task2 = asyncio.create_task(testcase2())
tasks = [task1, task2]
print('before await')
await asyncio.gather(*tasks)
start = time.time()
asyncio.run(main())
end = time.time()
print('Running time: %s Seconds' % (end - start))
- asyncio: 是Python标准库,用于编写异步代码,负责异步任务执行调度的。
- async: 是Python中一个关键字,用于定义异步函数的
- await:python当中一个异步编程常用到的关键字
headless 模式
在launch方法的参数中添加 headless=False playwright默认是无头模式运行,True是无头模式,False是有头模式,即在电脑上能看到浏览器的运行界面。默认情况下,Playwright 以无头模式运行浏览器。要查看浏览器 UI,请headless=False在启动浏览器时传递标志。有头模式适用于调试,而无头模式适用于CI / cloud执行。
浏览器常见的配置参数:
- headless ,设置Flase以有界面浏览器模式运行,默认为无头浏览器
- args=['--start-maximized'] : 设置浏览器启动参数,如最大化显示浏览器
- - 创建浏览器上下文实例: browser.new_context()
context=browser.new_context()
context.new_page()
- 关闭浏览器:browser.close()
页面相关的API
- 打开新页面:
browser.new_page()
或者context.new_page()
- 导航到指定的URL: page.goto(url)
页面操作:
- 点击元素:page.click(element)
- 输入文本:page.fill(element,value)
- 返回一个元素定位器:page.locator(element)
- 截图:page.screentshot("test.png")
- 等待某元素出现:page.wait_for_selector(element)
- 等待指定的时间:page.wait_for_timeout(xxx)
playwright等待
有时候我们自己忘记添加等待时间后,就是获取不到元素。而playwright为了避免我们犯错误,它对元素执行操作前,会进行一系列可操作性检查,以确保这些行动按预期运行。它会自动等待所有相关检查通过,然后才执行请求的操作。如果所需的检查未在给定的范围内通过则抛出timeout,操作将失败并显示TimeoutError。正是由于playwright添加了默认等待时间才会增加脚本稳定性。
自动等待
自动等待:playwright对元素执行操作前,会进行一系列可操作性检查,以确保这些行动按预期运行。它会自动等待所有相关检查通过,然后才执行请求的操作。如果所需的检查未在给定的范围内通过则抛出timeout,操作将失败并显示TimeoutError。
对于绝大多数的操作(点击、输入),palywright都会帮我们添加自动等待。它会在对元素进行操作之前,会自动执行一系列可操作性检查 。(checklist)
- 元素是否在DOM结构
- 元素是否是可见的
- 元素是否是动态变化的。
- 元素是否可操作。
自动等待是不需要添加额外的代码,由框架内部实现。
结合元素选择器实现等待机制:wait_for_selector
需要等待某个元素出现在页面上,就可以使用wait_for_selector
page.wait_for_selector("#kw")
page.wait_for_selector("#kw",visible=True)
等待页面所有的请求加载完成: wait_for_load_state
page.wait_for_load_state("load")
- domcontentloaded: DOM内容加载完成
- load: 页面完全加载完成
- networkidle: 网络空闲状态
页面加载状态前后时机:domcontentloaded->load->networkidle
slow_mo
Playwright 打开浏览器运行脚本的速度那就是一个字:快!因此为了便于我们查看执行的过程,我们可以加上等待来减缓执行,但是与selenium不同,playwright通过slow_mo (单位是毫秒)减慢执行速度,它的作用范围是全局的,从启动浏览器到操作元素每个动作都会有等待间隔,方便在出现问题的时候看到页面操作情况。使用方法如下:
chromium.launch(headless=False, slow_mo=50)
time.sleep()
playwright不再支持time.sleep(),而是使用page.wait_for_timeout()来实现等待,当我们调试时需要等待,即可使用该方法。Playwright 在查找元素的时候具有自动等待功能,如果你在调试的时候需要使用等待,你应该使用page.wait_for_timeout(5000) 代替 time.sleep(5)并且最好不要等待超时。
注:请使用 wait( wait_for_timeout) 方法而不是time模块。这是因为我们内部依赖于异步操作,并且在使用时time.sleep(5)无法正确处理它们。
page.wait_for_timeout: 强制等待