Playwright常用知识点
-
-
- 1.playwright
- 2.配置要求
- 3.安装
- 4.打开浏览器
-
- [4.1 上下文模式](#4.1 上下文模式)
- [4.2 交互模式](#4.2 交互模式)
- [4.3 异步打开](#4.3 异步打开)
- 5.常用对象
-
- [5.1 Browser](#5.1 Browser)
- [5.2 BrowserContext](#5.2 BrowserContext)
- [5.3 Page](#5.3 Page)
- 6.元素定位器(Locator)
-
- [6.1 css、xpath、text定位器](#6.1 css、xpath、text定位器)
- [6.2 文本定位器](#6.2 文本定位器)
- [6.3 get_by_role](#6.3 get_by_role)
- [6.4 get_by_label](#6.4 get_by_label)
- [6.5 get_by_placeholder](#6.5 get_by_placeholder)
- [6.6 get_by_text](#6.6 get_by_text)
- [6.7 get_by_alt_text](#6.7 get_by_alt_text)
- [6.8 get_by_title](#6.8 get_by_title)
- [6.9 filter](#6.9 filter)
- 7.交互
-
- [7.1 文本输入](#7.1 文本输入)
- [7.2 鼠标操作](#7.2 鼠标操作)
- [7.3 多选框和单选框](#7.3 多选框和单选框)
- [7.4 键盘操作](#7.4 键盘操作)
- [7.5 拖动元素](#7.5 拖动元素)
- [7.6 对话框弹窗](#7.6 对话框弹窗)
-
1.playwright
Playwright是一个由微软推出的浏览器测试框架,支持所有现代渲染引擎,包括 Chromium、WebKit和Firefox。可以在Windows、Linux和macOS上进行本地或CI测试,支持无头测试或使用本机移动模拟进行测试。比起selenium,playwright好像更容易上手
2.配置要求
- Python 3.8或更高版本
- Windows 10及以上版本、WindowsServer 2016及以上版本
- MacOS 12及以上版本
- Debian 11、Debian 12、Ubuntu 20.04及以上版本
3.安装
pip
shell
# pip install pytest-playwright
pip install playwright
Anaconda
shell
conda config --add channels conda-forge
conda config --add channels microsoft
conda install playwright
安装浏览器
shell
playwright install # 安装默认浏览器,Chromium、Firefox、Webkit
# playwright install webkit # 安装webkit浏览器
# playwright install chrome # 安装chrome浏览器
# playwright install firefox # 安装firefox浏览器
4.打开浏览器
4.1 上下文模式
使用上下文管理器启动浏览器
python
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
browser = p.chromium.launch(headless=False) # 打开chromium浏览器,并且显示浏览器
# browser = p.firefox.launch() # 打开firefox浏览器
# browser = p.webkit.launch() # 打开webkit浏览器
page = browser.new_page() # 打开一个页面
page.goto('https://baidu.com') # 打开URL
browser.close() # 关闭浏览器
4.2 交互模式
使用上下文的方式打开浏览器,最大的好处就是不用手动关闭Playwright,但是由于代码需要缩进,如果是在命令行交互式操作那就显得不方便,这时候我们也可以手动打开和关闭Playwright
python
from playwright.sync_api import sync_playwright
playwright = sync_playwright().start()
browser = playwright.chromium.launch(headless=False)
page = browser.new_page()
page.goto("https://baidu.com")
browser.close()
playwright.stop()
4.3 异步打开
Playwright是支持异步,这样可以在并发时有更高的性能表现
python
import asyncio
from playwright.async_api import async_playwright
async def main():
async with async_playwright() as p:
browser = await p.chromium.launch(headless=False)
# browser = await p.firefox.launch()
# browser = await p.webkit.launch()
page = await browser.new_page()
await page.goto('https://baidu.com')
await browser.close()
asyncio.run(main())
5.常用对象
5.1 Browser
Browser是浏览器对象,代表打开的浏览器实例。我们可以在launch的时候给它一些参数,例如关闭无头模式
python
browser = await p.chromium.launch(headless=False)
因为browser的参数太多了,我这里只列出比较常用的几种
参数 | 默认值 | 说明 |
---|---|---|
executable_path | None | 要运行的浏览器可执行文件的路径 |
channel | None | 使用的浏览器通道,例如chrome、chrome-beta、chrome-dev、msedge、msedge-beta等 |
headless | True | 是否使用无头模式,如果是,则不会显示浏览器 |
devtools | None | 是否打开开发者工具面板,如果是,则无头模式会被设置False |
proxy | None | 使用代理,传入一个ProxySettings对象即可 |
downloads_path | None | 下载文件的路径,如果不指定,它会创建临时目录并在浏览器关闭时被删除 |
chromium_sandbox | False | 是否允许Chromium沙盒模式 |
env | process.env | 设置浏览器的环境变量 |
timeout | 30000(毫秒) | 启动浏览器的超时时间 |
handle_sigint | True | 按下Ctrl-C则关闭浏览器 |
args | None | 启动浏览器时的额外参数,比如说抹除自动化测试的特征隐藏爬虫 |
注意:如果启动浏览器的时候不指定channel参数,则默认是使用chromium打开而不是Chrome ,如果想要用Chrome打开,需要指定channel="chrome"
5.2 BrowserContext
BrowserContext即上下文,类似于浏览器的"新的窗口",就是在同一个浏览器实例里打开互不影响的上下文对象(不共用cookie),比打开两个浏览器更省内存。当然,在你关闭浏览器之前建议先把上下文对象也关闭一下,这样它会帮忙清理掉一些缓存垃圾
python
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
browser = p.firefox.launch(headless=False)
context = browser.new_context(viewport={'width': 1080, 'height': 1080})
page = context.new_page()
page.goto('https://baidu.com')
context.close()
browser.close()
new_context()方法的参数很多,我这里只列出一些比较常用的参数
参数 | 默认值 | 说明 |
---|---|---|
viewport | 1280x720 | 页面大小 |
no_viewport | None | 不强制使用固定视口,允许在头模式下调整窗口大小 |
screen | None | 屏幕大小,只有设置了viewport时才会生效 |
ignore_https_errors | False | 是否忽略HTTPS请求错误 |
java_script_enabled | True | 是否允许执行JS脚本 |
user_agent | None | 自定义用户代理 |
offline | False | 是否使用离线模式 |
proxy | None | 使用代理,给一个ProxySettings对象即可 |
record_video_dir | None | 设置录制页面时保存视频文件的目录 |
record_video_size | None | 录制视频的大小,实际上与是否指定viewport有关(800x800、800x450) |
base_url | None | 根URL,若指定了,则以后得URL都只需要指定路径部分,它会自动拼接上base_url |
accept_downloads | True | 是否自动下载文件(当下载文件时不用点确认) |
5.3 Page
Page
对象就是一个页面,一个context可以有多个页面,只需要调用BrowserContext
对象的new_page()
方法即可新建一个页面,也就是实例化一个Page对象
Page对象有一些比较常用的属性或者方法,但是我这里先不列出与元素交互有关的方法,后面会讲到元素交互
属性或方法 | 说明 |
---|---|
url | 页面当前URL |
viewport_size | 窗口大小 |
set_viewport_size | 设置窗口大小 |
context | 所属上下文对象 |
frames | 页面中的所有Frame对象 |
main_frame | 页面的主Frame对象 |
content() | 返回页面内容即HTML字符串 |
set_content() | 设置页面HTML |
goto() | 加在某个url |
reload() | 重写加载页面 |
go_back() | 回到上一个页面 |
go_forward() | 回到下一个页面 |
title() | 页面标题 |
locator() | 元素定位 |
pause() | 停止执行JS代码 |
pdf() | 把页面导出为PDF文件 |
close() | 关闭页面 |
is_closed() | 页面是否已关闭 |
screenshot() | 截屏 |
set_default_timeout() | 设置默认超时时间(毫秒) |
6.元素定位器(Locator)
操作页面元素的前提是先获取到要操作的元素,所以我们需要学习已如何定位到你要操作的元素。我们调用一个Page对象的locator()方法即可定位元素,它会返回一个Locator
对象
6.1 css、xpath、text定位器
说到元素定位,相信很多人都优先想到css选择器、xpath选择器
python
...
page = browser.new_page()
page.goto("https://baidu.com")
# css选择器
page.locator('css=#kw').fill("冰冷的希望")
page.locator('input:has-text("百度一下")').click() # 伪类,包含某个文本 :has-text()
# page.locator('input', has_text="百度一下").click() # 等价于上面的写法
# xpath选择器
page.locator('xpath=//*[@id="kw"]').fill("冰冷的希望")
关于xpath和css选择器的用法这里不再赘述,有需要的话可以看一下之前的博文
【爬虫】元素定位(xpath、css)
6.2 文本定位器
如果你想直接通过页面中的某些文字进行定位,可以试一下text定位器。这种定位方式,你得注意是不是需要精确匹配
python
# 文本选择,注意是否模糊匹配
page.locator('text=百度一下').click() # 文本选择器,模糊匹配文字"百度一下"
page.locator('text="百度一下"').click() # 文本选择器,精确匹配文字"百度一下"
6.3 get_by_role
当然,除了传统的css和xpath选择器,playwright还给我们提供了其他更方便的定位方式,比如说get_by_role()
,可以通过某些角色进行定位,注意一下,元素标签不一定都是角色 ,Playwright支持的角色目前只有"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"
举个栗子,我们定位一下"百度一下"的按钮
python
page.get_by_role("button", name="百度一下").click()
6.4 get_by_label
如果你要定位的元素标签是配合label
标签使用的,那你可以直接通过page.get_by_label()
方法进行定位
python
page.get_by_label("Password").fill("secret")
6.5 get_by_placeholder
如果你要定位的元素有placeholder,比如说一些input
标签,你也可以通过get_by_placeholder()
方法进行定位
python
page.get_by_placeholder("User ID").fill("冰冷的希望")
6.6 get_by_text
通过文本选择,类似于前面提到的text选择器,是否精确匹配由exact
参数控制
python
page.get_by_text("设置", exact=True).last.click() # 如果定位到多个元素,你可以通过first、last等方法获取某个元素
# 注意,如果元素在页面不可见则会报错的,所以你可以等它显示,默认5000毫秒超时
expect(page.get_by_text("设置", exact=True)).to_be_visible()
6.7 get_by_alt_text
如果是img
或者area
元素,如果带有alt文本提示,也可以通过get_by_alt_text()
方法进行定位
python
page.get_by_alt_text("点击一下,了解更多").click()
6.8 get_by_title
如果要定位的元素是title
元素,也可以试一下get_by_title()
方法
python
page.get_by_title("点击一下,了解更多").click()
6.9 filter
如果定位到多个元素,你可以使用Locator的first
、last
属性获取第一个、最后一个元素,另外我们还可以通过filter()
方法进一步过滤
python
page.get_by_role("listitem").filter(has_text="Product 2").get_by_role(
"button", name="Add to cart"
).click()
7.交互
7.1 文本输入
调用Locator对象的fill()
方法即可输入文本,前提是该Locator支持输入文本,比如说input输入框
python
from playwright.sync_api import sync_playwright, expect
playwright = sync_playwright().start()
browser = playwright.chromium.launch(headless=False)
page = browser.new_page()
page.goto('https://baidu.com')
page.locator('css=#kw').fill("冰冷的希望")
当然,除了Locator对象的fill()方法,我们也可以直接调用Page对象的fill()方法进行操作
python
# page.locator('css=#kw').fill("冰冷的希望")
page.fill('css=#kw', "冰冷的希望")
还有很多类似的用法,比如说click、dbclick等都可以直接调用Page对象的操作方法,后面不再强调
如果需要清空输入框,可以用clear()
方法
python
page.locator('#kw').clear()
7.2 鼠标操作
Locator对象的click()
方法用于点击鼠标按键,如果不填任何参数,就是点击一次鼠标左键,我们也可以通过传入其他操作实现不同的鼠标操作
python
# 单击鼠标左键
page.get_by_text('百度一下').click()
# 鼠标按键,默认是left,可选left、middle、right
page.get_by_text('百度一下').click(button="right")
# 辅助按键,可选Alt、Control、Meta、Shift
page.get_by_text('百度一下').click(modifiers=["Shift"])
# 点击位置,相对定位,元素的左上角为坐标系原点
page.get_by_text('百度一下').click(position={"x": 0, "y": 0})
# 鼠标按下和抬起之间的时间间隔,默认是0,单位是毫秒
page.get_by_text('百度一下').click(delay=0.2)
# 整个操作的最大超时时间,单位是毫秒,默认是30000毫秒,0则不限时
page.get_by_text('百度一下').click(timeout=0.2)
# 点击次数
page.get_by_text('百度一下').click(click_count=1)
如果想要双击,可以试一下click(click_count=2)
,当然Playwright也给我们封装了一个dblclick()
用于双击,参数基本上与click()
一样,这里就不多进行演示了
python
page.get_by_text('百度一下').dblclick()
7.3 多选框和单选框
如果有需要勾选CheckBox或者RadioButton,我们可以使用check()
方法
python
from playwright.sync_api import expect
# 勾选
page.get_by_label('记住密码').check()
# 确保被勾选上
expect(page.get_by_label('记住密码')).to_be_checked()
# 下拉框选项
page.get_by_label('#sexBox').select_option('Man')
7.4 键盘操作
如果fill()和鼠标按键不够用,可能需要再按一下键盘也是可以的。目前支持的按键,除了数字键、字母键(区分大小写)、F1-F12,还有一些常用按键
Backspace(退格), Tab(制表), Delete(删除), Escape(退出), End(结束), Enter(回车), Home(主页), Insert(插入), PageDown(下一页), PageUp(上一页), ArrowRight(向右方向), ArrowUp(向上方向),ArrowDown(向下方向),ArrowLeft(向左方向)等
python
# 填充文字
page.locator('#kw').fill("冰冷的希望")
# 按下回车
page.locator('#kw').press("Enter")
# 按下a
page.locator('#kw').press("a")
# 按下组合键:Ctrl和右方向键
page.locator('#kw').press("Control+ArrowRight")
7.5 拖动元素
如果需要拖转,比如说一些验证码,需要把元素拖动到合适的位置,这时候我们就需要调用drag_to()
方法了
python
page.locator("#start").drag_to(page.locator("#end"))
我们可以看到drag_to()
只支持把一个元素拖到到另一个元素里,但是如果没有目标元素或者不好定位目标元素,那你就只能手动控制鼠标的按下、移动、抬起等动作了
7.6 对话框弹窗
如果一个页面弹出了对话框,可能会导致无法继续操作,就需要先点击确认或者取消按钮,这种情况对我们来说是非常不利的,所以Playwright会自动帮我们关闭所有弹窗确认框。如果想要自己处理,我们可以通过监听弹窗事件来处理
python
def handle_dialog(dialog):
print(dialog.message)
print(dialog.type)
# dialog.dismiss()
dialog.accept()
page.on('dialog', lambda: handle_dialog)
注意,如果你监听了但是没有调用accept()
或者dismiss()
方法处理对话框,则可能会导致Playwright无法正常工作