From: B站 白月黑羽编程
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
一.CSS元素定位(95%的问题都能解决)
# 打印所有搜索内容
lcs = page.locator(".result-item").all()
for lc in lcs:
print(lc.inner_text())
# 或者直接使用这个方法all_inner_text()
# text = page.locator(".result-item").all_inner_text()
# print(text)
# 使用.class来定位时,有可能有两个class属性, 就可以用任意一个值。如果定位不到,可以把两个属性都加进去。
# <span class="chinese student">张三</span>
# page.locator(.chinese) 或者 page.locator(.student)
# 或者 page.locator(.chinese.student), 这种精确度也更高
# 但绝对不能写 page.locator(.chinese student)
# 匹配多个元素
locators = page.locator('.plant').all()
# 获取某种表达式对应元素的数量,使用count()
count = page.locator('.plant').count()
# 获取某种表达式对应元素的第一个或最后一个元素,使用first, last
lct = page.locator('.plant')
print(lct.first.inner_text(), lct.last.inner_text())
# 也可以用nth方法,获取指定次序元素,参数0表示第一个
lct = page.locator('.plant')
print(lct.nth(0).inner_text())
# 元素内部定位
# 前面都是通过Page对象调用的locator方法,定位的范围时整个网页。如果想在某个元素内部定位,可以通过Locator对象调用locator方法。
lct = page.locator('#bottom')
# 在#bottom对应元素范围内寻找标签名为span的元素
eles = lct.locator('span').all()
for e in eles:
print(e.inner_text())
# 根据属性选择某元素
a[href="http://www.miitbeian.gov.cn"] #a是标签名,href是属性
# 也可以用包含,模糊匹配
a[href*="miitbeian"]
# 还可以选择属性值以某个字符串开头
a[href^="http"]
# 还可以选择以什么结尾
a[href$="gov.cn"]
# 多个属性
# <div class="misc" ctype="gun">沙漠之鹰</div>
div[class=misc][ctype=gun]
二.Xpath元素定位
CSS基本能解决95%以上的元素定位。
只有对父节点和兄弟节点的选择,CSS做不了,需要使用xpath来做。
1.对父节点的选择:
//*[@id='china']/..
还可以继续向上找爷爷节点:
//*[@id='china']/../..
2.兄弟节点的选择:
后续兄弟节点:
following-sibling::
比如选class为single_choice的元素的所有后续兄弟节点:
//*[@class='single_choice']/following-sibling::*
等同于css选择器的:
.single_choice ~ *
如果要选择后续节点中的div节点, 写成:
//*[@class='single_choice']/following-sibling::div
前面兄弟节点语法:
preceding-sibling::
三.常用的元素选择方法(代码助手生成时能理解就可以):
1.根据文本内容选取:
elements = page.get_by_text('11').all()
for ele in elements:
print(ele.inner_text())
2.正则表达式:
import re
elements = page.get_by_text(re.compile("11$")).all() #指以"11"结尾的文本
3.视觉定位 - ARIA属性:
<div class="alert-message" role="alert">
您已经成功注册,很快您将收到一份确认电子邮件
</div>
# 这时就可以用role定位(元素唯一):
lc = page.get_by_role('alert')
print(lc.inner_text())
有些特定语义元素被ARIA规范认定为自带该属性。比如:
<progress value="75" max="100">75 %</progress>
等于隐含了如下信息:
<progress values="75" max="100"
role="progressbar"
aria-valuenow="75"
aria-valuemax="100">75 %</div>
所以直接用如下代码定位该元素:
lc = page.get_by_role('progressbar')
print(lc.get_attribute('value'))
再比如search类型的输入框,默认就有searchbox role
<input type="search">
直接用如下代码定位:
lc = page.get_by_role('searchbox')
print(lc.fill('黑月白羽'))
<h1>text1</h1>
<h2>text2</h2>
h1隐含了role="heading" aria-level="1"属性
h2隐含了role="heading" aria-level="2"属性
这时就可以用下面代码定位h2:
lc = page.get_by_role('heading',level=2)
print(lc.inner_text())
一些常见的
<a> <td> <button> Accessible Name值就是内部文本内容
<textarea> <input> 这些输入框,他们的Accessible Name值就是和他们关联的文本
比如:
<label>
<input type="checkbox" /> Subscribe
</label>
这个checkbox的Accessible Name却是Subscribe, 应该这样定位:
page.get_by_role("checkbox", name="Subscribe")
Accessible Name不一样,他是元素界面可见的文本名。
比如上面的元素,暗含的Accessible Name值就是"白月黑羽教程",当然也暗含了ARIA role值为link。
所以可以这样定位:
lc = page.get_by_role('link',name='白月黑羽教程')
print(lc.click())
上面写法,只要Accessible Name包含参数name的字符串内容即可,而且不区分大小写,并不需要完全一致。
所以这样也能定位到:
lc = page.get_by_role('link',name='白月黑羽')
如果要精确匹配,可以指定exact=True,代码如下:
lc = page.get_by_role('link',name='白月黑羽',exact=True)
name值还可以通过正则表达式,进行复杂匹配:
lc = page.get_by_role('link',name=re.compile("^白月.*黑羽"))
input元素通常有关联的label
可以使用Page/Locator对象的get_by_label方法,根据元素关联的label定位
比如源代码是:
<input aria-label="Username">
<label for"password-input">Password:</label>
<input id="password-input">
可以这样定位:
page.get_by_label("Username").fill("john")
page.get_by_label("Password").fill("secret")
page.get_by_title("byhy首页").click()
四.缺省等待时间
Playwright中,当我们定位元素(比如通过locator/get_by_text等方法)后,对元素进行操作(比如click,fill),如果当时根据定位条件,找不到元素,playwright并不会立即抛出错误,而是缺省等待30秒,如果元素在30秒内出现了,就立即操作成功返回。
如果想自己设定缺省等待时间(10秒)可以在代码中这样做
browser = p.chromium.launch(headless=False)
context = browser.new_context()
context.set_default_timeout(10000)
page = context.new_page()
五.界面操作
1.元素通用操作
获取文本内容
通过locator对象的inner_text()方法可以获取可见内部文本,多个元素的用all_inner_texts()
有些文本被设置为不可见的,比如下面代码
<p id="source">
<span id='text'>看一下<br>这个内容</br>如何变化</span>
<span style="display:none">隐藏内容</span>
</p>
要获取p元素内部所有内容,包含隐藏内容,可以用Locator对象的text_content()或者all_text_contents()方法获取单个或者多个匹配对象文本
如下所示:
lc = page.locator("#source")
print('innerText', lc.inner_text())
print('---------------------------')
print('textContent', lc.text_content())
获取元素属性: locator.get_attribute
获取元素内部html: locator.inner_html
点击: dbclick
悬停: hover
等待元素可见: page.locator("#dynamic").wait_for()
lc = page.locator("#dynamic + div") #再继续对该元素进行操作
print(lc.inner_text()) #打印该元素的inner_text()
判断元素是否可见: page.locator("#source").is_visible() ->不做等待,仅立即返回True或False
输入框输入: 单行文本框input或者多行文本框textarea都可以使用locator对象的fill方法
输入框情空: 单行文本框input或者多行文本框textarea都可以使用locator对象的clear方法
获取输入框输入的内容,一定要用 input_value()而不是inner_text()
例如:
lc = page.get_by_placeholder('captcha')
input('...')
print(lc.input_value())
文件输入框(上传文件用的那种): set_input_files()
例如:
lc = page.locator('input[type=file]')
lc.set_input_files('d:/a1/a2/1.png') # 单选一个文件
lc.set_input_files(['d:/a1/a2/1.png', 'd:/a1/a2/2.png']) # 多选文件(放列表里)
2.radio点选元素, checkbox多选, select框
# 2.1.radio点选元素 例子
点选radio框,locator.check()
取消点选radio框,locator.uncheck()
判断radio框是否选中,locator.is_checked()
# 获取当前选中的元素
lcs = page.locator('#s_radio input[name="teacher"]:checked').all()
teachers = [lc.get_attribute('value') for lc in lcs ]
print('当前选中的是: ', ' '.join(teachers))
# 确保点选小雷老师
page.locator("#s_radio input[value='小雷老师']").check()
# 2.2.checkbox多选 例子
checkbox是常见的勾选元素
<div id="s_checkbox">
<input type="checkbox" name="teacher" value="小江" checked="checked">小江<br>
<input type="checkbox" name="teacher" value="小雷">小雷<br>
<input type="checkbox" name="teacher" value="小凯" checked="checked">小凯
</div>
# 和radio input一样
如果要点选checkbox框,使用locator.check()
取消选择checkbox框,使用locator.uncheck()
判断checkbox框是否选中,使用locator.is_checked()
# 获取当前选中的元素
lcs = page.locator('#s_checkbox input[name="teacher"]:checked').all()
teachers = [lc.get_attribute('value') for lc in lcs ]
print('当前选中的是: ', ' '.join(teachers))
# 确保点选小雷老师
page.locator("#s_checkbox input[value='小雷老师']").check()
# 2.3.select框 例子
1)对于select单选框,不管原来选的是什么,直接用select方法选择即可。
page.locator('#ss_single').select_option('小江老师')
这里select_option参数是选项option元素的value或者选项文本,要完全匹配。
也可以使用关键字参数index, value, label指定分别根据 索引,value属性,选项文本进行匹配。
比如:
a)#根据索引选择,从0开始,但是为0的时候,好像有bug
page.locator('#ss_single').select_option(index=1)
b)#根据value属性选择
page.locator('#ss_single').select_option(value='小江老师')
c)#根据选项文本选择
page.locator('#ss_single').select_option(label='小江老师')
d)#清空所有选择
page.locator('#ss_single').select_option([])
2)对于select多选框,选某几个选项,同样使用以上方法,参数改为多个值的列表即可。
a)#根据value属性或者选项文本多选
page.locator('#ss_single').select_option(['小江老师', '小雷老师'])
b)#根据value属性多选
page.locator('#ss_single').select_option(value=['小江老师', '小雷老师'])
c)#根据选项文本选择
page.locator('#ss_single').select_option(label=['小江老师', '小雷老师'])
d)#清空所有选择
page.locator('#ss_single').select_option([])
3)对于select选中选项
同样可以通过css selector表达式:checked伪选择获取所有选中的select选项,如:
page.locator('#ss_multi').select_option(['小江老师', '小雷老师'])
lcs = page.locator('#ss_multi option:checked').all_inner_texts()
print(lcs)
六.网页操作
1.常用方法:
page.get_by_role('link',name='白月黑羽教程').click()
page.go_back() # 后退
page.go_forward() # 前进
page.reload() # 刷新
page.title() # 获取整个网页标题栏文本
page.set_viewport_size({"width": 640, "height": 480}) # 设置页面可见区(不包含地址栏那部分)大小,宽度/高度的单位是像素
2.frame切换:
# 产生一个FrameLocator对象
frame = page.frame_locator("iframe[src='sample1.html']")
# 再在其内部进行定位
lcs = frame.locator('.plant').all()
for lc in lcs:
print(lc.inner_text(timeout=1000))
3.窗口切换:
pw = sync_playwright().start()
browser = pw.chromium.launch(headless=False)
# 创建BrowserContext对象
context = browser.new_context()
# 通过context创建page
page = context.new_page()
page.goto("https://cdn2.byhy.net/files/selenium/sample3.html")
# 点击链接,打开新窗口
page.locator("a").click()
# 等待2秒,不能用time.sleep
page.wait_for_timeout(2000)
# page属性是所有窗口对应Page对象的列表
newPage = context.pages[1]
# 打印新网页窗口标题
print(newPage.title())
# 打印老网页窗口标题
print(page.title())
如果自动化打开了很多链接窗口,不知道目标窗口的次序号,这时可以根据标题栏定位到要操作的page.
那么我们就可以通过类似下面的代码来操作
for pg in context.pages:
# 得到该窗口的标题栏字符串,判断是不是我们要操作的那个窗口
if '必应' in pg.title():
break
print(pg.title())
设置当前tab
如果当前界面有很多窗口,要把某个窗口作为当前活动窗口显示出来,可以调用该窗口对应的Page对象的bring_to_front方法
关闭当前网页
page.close()
4.冻结界面
用一段JS的代码解决该问题,在浏览器的console里输入如下代码,鼠标移动到要查看的文本上,3秒后就会定住
setTimeout(function(){debugger}, 3000)
5.截屏
a)截屏当前页面可见内容,保存到当前工作目录下的s1.png
page.screenshot(path='s1.png')
b)截屏完整页面,页面内容长度超过窗口高度时,包括不可见部分
page.screenshot(path='s1.png', full_page=True)
c)也可只针对某个页面的显示内容进行截屏,使用locator对象的screenshot方法
page.locator('input[type=file]').screenshot(path='s2.png')
page.locator('[id="1"]').screenshot(path='s2.png') # id是单纯数字时不能用#1的方法定位
6.拖拽
# 选中'span#t1'文本内容
page.locator('#t1').select_text()
# 拖拽到输入框'[placeholder="captcha"]'里面去
page.drag_and_drop('#t1', '[placeholder="captcha"]')
如果被拖动元素的Locator对象已经产生,可以直接调用其drag_to方法进行拖动
# 选中'span#t1'文本内容
lc = page.locator('#t1')
lc.select_text()
# 拖拽到输入框'[placeholder="captcha"]'里面去
lc.drag_to(page.locator('[placeholder="captcha"]'))
7.弹出框
7.1.alert
# 处理弹出对话框的回调函数
def handleDlg(dialog):
# 等待1秒
page.wait_for_timeout(1000)
# 点击确定
dialog.accept()
# 打印弹出框提示信息
print(dialog.message)
# 设置弹出对话框时间回调函数
page.on("dialog", handleDlg)
# 点击alert按钮
page.locator('#b1').click()
# 备注:注册的处理函数中一定要调用accept或者dismiss方法让对话框消失。
# playwright在界面有弹出框时,发现如果没有任何注册的处理函数,会自动点击取消。
7.2.confirm
取消的按钮直接用dialog.dismiss()
7.3.prompt
dialog.accept('Hello!!!') # 输入信息并确定