Playwright常用知识点

1.playwright2.配置要求3.安装4.打开浏览器4.1 上下文模式4.2 交互模式4.3 异步打开

5.常用对象5.1 Browser5.2 BrowserContext5.3 Page

6.元素定位器(Locator)6.1 css、xpath、text定位器6.2 文本定位器6.3 get_by_role6.4 get_by_label6.5 get_by_placeholder6.6 get_by_text6.7 get_by_alt_text6.8 get_by_title6.9 filter

7.交互7.1 文本输入7.2 鼠标操作7.3 多选框和单选框7.4 键盘操作7.5 拖动元素7.6 对话框弹窗7.7 期待元素状态

8.操作cookie8.1 cookie8.2 storage_state

9.frame交互9.1 FrameLocator对象9.2 Frame对象

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

# pip install pytest-playwright

pip install playwright

Anaconda

conda config --add channels conda-forge

conda config --add channels microsoft

conda install playwright

安装浏览器

playwright install # 安装默认浏览器,Chromium、Firefox、Webkit

# playwright install webkit # 安装webkit浏览器

# playwright install chrome # 安装chrome浏览器

# playwright install firefox # 安装firefox浏览器

4.打开浏览器

4.1 上下文模式

使用上下文管理器启动浏览器

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

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是支持异步,这样可以在并发时有更高的性能表现

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的时候给它一些参数,例如关闭无头模式

browser = await p.chromium.launch(headless=False)

因为browser的参数太多了,我这里只列出比较常用的几种

参数默认值说明executable_pathNone要运行的浏览器可执行文件的路径channelNone使用的浏览器通道,例如chrome、chrome-beta、chrome-dev、msedge、msedge-beta等headlessTrue是否使用无头模式,如果是,则不会显示浏览器devtoolsNone是否打开开发者工具面板,如果是,则无头模式会被设置FalseproxyNone使用代理,传入一个ProxySettings对象即可downloads_pathNone下载文件的路径,如果不指定,它会创建临时目录并在浏览器关闭时被删除chromium_sandboxFalse是否允许Chromium沙盒模式envprocess.env设置浏览器的环境变量timeout30000(毫秒)启动浏览器的超时时间handle_sigintTrue按下Ctrl-C则关闭浏览器argsNone启动浏览器时的额外参数,比如说抹除自动化测试的特征隐藏爬虫

注意:如果启动浏览器的时候不指定channel参数,则默认是使用chromium打开而不是Chrome,如果想要用Chrome打开,需要指定channel="chrome"

5.2 BrowserContext

BrowserContext即上下文,类似于浏览器的“新的窗口”,就是在同一个浏览器实例里打开互不影响的上下文对象(不共用cookie),比打开两个浏览器更省内存。当然,在你关闭浏览器之前建议先把上下文对象也关闭一下,这样它会帮忙清理掉一些缓存垃圾

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()方法的参数很多,我这里只列出一些比较常用的参数

参数默认值说明viewport1280x720页面大小no_viewportNone不强制使用固定视口,允许在头模式下调整窗口大小screenNone屏幕大小,只有设置了viewport时才会生效ignore_https_errorsFalse是否忽略HTTPS请求错误java_script_enabledTrue是否允许执行JS脚本user_agentNone自定义用户代理offlineFalse是否使用离线模式proxyNone使用代理,给一个ProxySettings对象即可record_video_dirNone设置录制页面时保存视频文件的目录record_video_sizeNone录制视频的大小,实际上与是否指定viewport有关(800x800、800x450)base_urlNone根URL,若指定了,则以后得URL都只需要指定路径部分,它会自动拼接上base_urlaccept_downloadsTrue是否自动下载文件(当下载文件时不用点确认)

5.3 Page

Page对象就是一个页面,一个context可以有多个页面,只需要调用BrowserContext对象的new_page()方法即可新建一个页面,也就是实例化一个Page对象

Page对象有一些比较常用的属性或者方法,但是我这里先不列出与元素交互有关的方法,后面会讲到元素交互

属性或方法说明url页面当前URLviewport_size窗口大小set_viewport_size设置窗口大小context所属上下文对象frames页面中的所有Frame对象main_frame页面的主Frame对象content()返回页面内容即HTML字符串set_content()设置页面HTMLgoto()加在某个urlreload()重写加载页面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选择器

...

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定位器。这种定位方式,你得注意是不是需要精确匹配

# 文本选择,注意是否模糊匹配

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"

举个栗子,我们定位一下“百度一下”的按钮

page.get_by_role("button", name="百度一下").click()

6.4 get_by_label

如果你要定位的元素标签是配合label标签使用的,那你可以直接通过page.get_by_label()方法进行定位

page.get_by_label("Password").fill("secret")

6.5 get_by_placeholder

如果你要定位的元素有placeholder,比如说一些input标签,你也可以通过get_by_placeholder()方法进行定位

page.get_by_placeholder("User ID").fill("冰冷的希望")

6.6 get_by_text

通过文本选择,类似于前面提到的text选择器,是否精确匹配由exact参数控制

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()方法进行定位

page.get_by_alt_text("点击一下,了解更多").click()

6.8 get_by_title

如果要定位的元素是title元素,也可以试一下get_by_title()方法

page.get_by_title("点击一下,了解更多").click()

6.9 filter

如果定位到多个元素,你可以使用Locator的first、last属性获取第一个、最后一个元素,另外我们还可以通过filter()方法进一步过滤

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输入框

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()方法进行操作

# page.locator('css=#kw').fill("冰冷的希望")

page.fill('css=#kw', "冰冷的希望")

还有很多类似的用法,比如说click、dbclick等都可以直接调用Page对象的操作方法,后面不再强调

如果需要清空输入框,可以用clear()方法

page.locator('#kw').clear()

7.2 鼠标操作

Locator对象的click()方法用于点击鼠标按键,如果不填任何参数,就是点击一次鼠标左键,我们也可以通过传入其他操作实现不同的鼠标操作

# 单击鼠标左键

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()一样,这里就不多进行演示了

page.get_by_text('百度一下').dblclick()

7.3 多选框和单选框

如果有需要勾选CheckBox或者RadioButton,我们可以使用check()方法

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(向左方向)等

# 填充文字

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()方法了

page.locator("#start").drag_to(page.locator("#end"))

我们可以看到drag_to()只支持把一个元素拖到到另一个元素里,但是如果没有目标元素或者不好定位目标元素,那你就只能手动控制鼠标的按下、移动、抬起等动作了

7.6 对话框弹窗

如果一个页面弹出了对话框,可能会导致无法继续操作,就需要先点击确认或者取消按钮,这种情况对我们来说是非常不利的,所以Playwright会自动帮我们关闭所有弹窗确认框。如果想要自己处理,我们可以通过监听弹窗事件来处理

def handle_dialog(dialog):

print(dialog.message)

print(dialog.type)

# dialog.dismiss()

dialog.accept()

page.on('dialog', lambda: handle_dialog)

注意,如果你监听了但是没有调用accept()或者dismiss()方法处理对话框,则可能会导致Playwright无法正常工作

7.7 期待元素状态

Playwright默认带有隐式等待机制,而且很多方法都有timeout参数设置超时,但是有些场景,比如说等待某个元素出现,或者等待某个禁用元素恢复可用状态,这些等待可以配合expect()方法,官方文档称之为“自动重试断言”

from playwright.sync_api import sync_playwright, expect

locator = page.locator("#myElement")

expect(locator).to_be_attached() # 元素添加到文档中

expect(locator).to_be_checked() # Checkbox被选中

expect(locator).to_be_disabled() # 元素不可用

expect(locator).to_be_editable() # 元素可编辑

expect(locator).to_be_empty() # 容器是空的

expect(locator).to_be_enabled() # 元素可用

expect(locator).to_be_focused() # 元素被聚焦

expect(locator).to_be_hidden() # 元素被隐藏

expect(locator).to_be_in_viewport() # Element intersects viewport

expect(locator).to_be_visible() # 元素可见

expect(locator).to_contain_text() # 元素包含某个文本

expect(locator).to_have_attribute() # 元素有某个属性

expect(locator).to_have_class() # 元素有某个类

expect(locator).to_have_count() # 确保有确定数量的子节点

expect(locator).to_have_css() # 元素有某个css属性

expect(locator).to_have_id() # 元素有一个Id

expect(locator).to_have_js_property() # 确保元素有某个JS属性,例如loaded

expect(locator).to_have_text() # 确保有某些文本的元素

expect(locator).to_have_value() # 输入有文本值

expect(locator).to_have_values() # 针对下拉框,至少有一个option选中

expect(page).to_have_title() # 页面有指定的title

expect(page).to_have_url() # 确保页面导航到给定的URL

expect(response).to_be_ok() # 确保Response的状态码是200~299

常见元素状态说明 Visible(可见的) 指的是元素在页面上是可见的,即使它的透明度是0(opacity:0 )。如果尺寸设置为0,或者“display:none”则是不可见的。

Stable(稳定的) 指的是页面中的元素不发生运动。当页面中的元素至少2帧边界不动则认为是稳定的。

Enabled(可以使用的) 指的是元素处于可使用状态,例如可点击。如果元素带有disabled属性则是不可使用的

Editable(可编辑的) 指的是元素处于可编辑状态,例如可输入。元素处于“Enabled”状态并且没有“readonly”属性

8.操作cookie

对于需要登录的网站,如果不想每次都登录,可以把cookie保存下来,然后下次再加载,这样就可以免去每次登录的麻烦了

8.1 cookie

我们可以使用BrowserContext对象的cookies()方法获取全部cookie,然后使用add_cookies()方法把cookie添加到BrowserContext

context = browser.new_context()

page = context.new_page()

page.goto("https://baidu.com")

# 获取全部cookie

cookie_list = context.cookies()

# 清空cookie

context.clear_cookies()

# 添加cookie

context.add_cookies(cookie_list)

page.reload()

8.2 storage_state

除了手动操作cookie的方式,Playwright还提供了一种可以把Cookie保存到本地的方法storage_state(),调用一下就会返回cookie和本地快照信息,如果指定path参数则可以保存到本地

context = browser.new_context()

page = context.new_page()

page.goto("https://baidu.com")

context.storage_state(path="./cookies.json")

读取storage_state也很简单,只需要在创建BrowserContext对象的时候指定storage_state的路径即可

context = browser.new_context(storage_state="./cookies.json")

page = context.new_page()

page.goto("https://baidu.com")

9.frame交互

如果你要操作的元素位于某个Frame中(iframe标签),通过普通的Page定位器是无法获取到的,你需要访问或者进入到对应的Frame才能操作。

9.1 FrameLocator对象

Page对象有一个frame_locator()方法可以访问到某个Frame,返回一个FrameLocator对象,之前学过的Locator对象的所有方法它都有

# 通过选择器定位到Frame

main_frame = page.frame_locator("#main")

# 通过FrameLocator对象交互frame中的元素

main_frame.get_by_text('Enquire Transaction History').click()

9.2 Frame对象

也可以使用Page对象的frame()方法获取到Frame,返回一个Frame对象,Frame对象的用法与Page对象类似

# 使用name属性的方式

frame = page.frame(name="main")

frame.content()

frame.locator('input[type="radio"][name="txnPeriod"]').first.click()

frame.select_option('select[name="presetPeriod"]', value="60")

# 使用url的方式

frame = page.frame(url="**/IB/Welcome**")

frame.select_option('select[name="presetPeriod"]', index=0)

好文链接

评论可见,请评论后查看内容,谢谢!!!评论后请刷新页面。