02 playwright 操作页面元素
在前面的介绍中,我们只是简单讲了一下playwright常用的一些方法和属性,在本文中,我们将会更加详细地介绍
一、文本内容的获取
在界面中,有些时候html文件会写一些隐藏的内容,并给style="display:none",这样一写页面上就看不到对应的内容,因此我们如果通过之前讲的方式,其实是获取不了这种隐藏内容的,因为:
inner_text():获取单个元素的内部文本,文本必须可见
all_inner_texts:获取所有元素的文本,文本必须可见(这个适合于返回多个对象的时候使用)
上面两个方法都有一个共同的缺陷,就是不包含隐藏的文本,因此如果需要同时打印隐藏文本,我们可以使用:
text_content():获取单个元素的内部文本,文本包含可见文本和不可见文本
all_text_contents():用于获取所有返回对象的可见+不可见文本
文本除了会出现在label,span这些常见地点,还有可能会存在于文本框中,因此我们可以通过input_value()进行获取
| result = page.locator("input [type='submit']")
print(result.input_value())
|
而对于CSS的属性的获取,我们可以使用get_attribute进行获取
| result = page.locator("input [type='submit']")
print(result.get_attribute("value"))
|
之前讲的都是返回页面可见的文字或者属性,那如果想要直接返回html代码,直接使用inner_html()方法,这个方法会返回内层的所有html代码,方便我们精细化分析页面结构,配合正则表达式定位最终内容。
二、页面元素常见的动作
除了我们之前经常讲的click方法,fill方法,还有以下多种不同的页面操作方法:
dblclick: 双击动作,有些内容双击才能进入下一个界面,就可以用这个动作
hover:悬停动作,内容在悬停时出现,则可以使用这个动作
clear:常用在输入框,对已输入内容进行清空
set_input_files: 可以对文件上传按钮进行操作,然后通过传入文件路径上传本地文件
| file_btn = page.locator("input[type='file']")
file_btn.set_input_files(["test.txt","test2.txt","1.jpg"]) # 上传多个文件
|
check: 常用于单选框或者复选框,此方法都是通用的,用于确保此单选/多选框选中(注意是确保)
uncheck: 和上面用法刚好相反,判断是否选中也可以用 is_checked 方法
| # 选中所有已选中的复选框
checkboxes = page.locator("input[type='checkbox']:checked")
# 选中所有未选中的复选框
checkboxes = page.locator("input[type='checkbox']:not(:checked)")
|
同时我们可以通过上面的方式来快速定位已经选中或者没有选中的内容
select_option:用于对下拉单选或者多选进行操作,可以根据index,lable和value等进行取值
| lca = page.locator("#select_op") # 这一步只需要定义到select级即可
# 根据value选择多个选项
lca.select_option(value=["john","jane"])
# 根据索引选择选项
lca.select_option(index=[0,1])
# 根据文本选择选项
lca.select_option(label=["john","jane"])
# 清空所有已选择的选项
lca.select_option(values=[])
|
注意下拉列表都是通过select > option来组织结构的,我们定位的时候只定位到最上级的select即可
drag_and_drop 和 drag_to: 对页面元素进行拖拽,注意drag_to 方法需要填入新的locator对象,而不是仅用表达式
| page.locator("#container").select_text() # 选择容器中的文本
page.drag_and_drop("#container", "input[type='text']") # 拖动容器中的文本到输入框中
tx = page.locator("#container")
tx.drag_to(page.locator("input[type='text']")) # 拖动容器中的文本到输入框中
|
三、关于页面的等待
Playwright通过Locator对元素进行操作时,如果元素当前还没有出现,不会立马抛出错误,而是会等待30秒,如果还没有出现,则抛出异常,我们也可以自己设置等待时间:
| lca = page.locator("#mainpic img",timeout=10000) # 由于单位是ms,因此这里代表10s
|
但是上面的方法只是设置了对单个元素的等待时间,如果你想整体修改对每个元素的默认等待时间,则可以在程序开始的时候,让page由context创建,然后设置默认等待时间,如下:
| context = browser.new_context()
context.set_default_timeout(10000) # 设置默认超时时间为 10 秒
page = context.new_page()
|
有的时候我们可能希望等页面某个元素出现再进行下一步操作,比如验证窗口,这个时候我们就可以使用wait_for方法,这个方法会等待需要出现的元素出现了,再进行后面的操作(但是实际我们知道这个元素会出现,只是早晚问题):
| # 等待验证码加载完成
lca = page.locator("#container div[class='verify']").wait_for(state="visible")
# 等待验证码加载完成,超时时间为 10 秒
lca = page.locator("#container div[class='verify']").wait_for(state="visible",timeout=10000)
|
而有的时候我们需要及时判断(就当下立马判断)某个元素是否已经加载出来可见了,可以使用is_visible实现
四、网页整体内容和动作
除了对于页面元素的操作,我们经常还会对整个页面进行操作,常用的有以下几种方式:
| page.goto("https://movie.douban.com/top250") # 前往某个网址
page.go_back() # 返回上一页
page.go_forward() # 前往下一页
page.reload() # 刷新当前页面
page.close() # 关闭当前页面
|
除此之外,还可以设置页面的大小,打印页面整体的html代码等,如下:
| page.set_viewport_size({"width": 1280, "height": 720}) # 设置浏览器窗口大小
print(page.content()) # 获取当前页面的 HTML 内容
print(page.title()) # 获取当前页面的标题
print(page.url) # 获取当前页面的 URL
|
在实际的操作中,我们可能点击一个链接之后会出现另外一个界面,这个时候我们可以通过context.pages搭配下标来定位界面,如果页面太多,则可以根据标题遍历,找到对应的对象,如下:
| context = browser.new_context()
context.set_default_timeout(10000) # 设置默认超时时间为 10 秒
page = context.new_page()
page.goto("https://movie.douban.com/top250") # 前往某个网址
page.locator("xpath= /html/body/div[1]/div/div[3]/ul/li[1]/a").click() # 点击第一个电影的链接
page.wait_for_timeout(2000) # 等待第一个电影的链接出现
new_page = context.pages[1] # 获取新打开的页面
print(new_page.title()) # 获取新页面的标题
# 如果页面比较多,可以遍历所有页面对象,找到标题为"豆瓣"的页面对象
for pg in context.pages:
if page.title() == "豆瓣":
break
print(pg.title()) # 获取当前页面的标题,此时pg为新的页面对象
|
有的时候我们调试代码发现总是做不对,想要看看操作到这一步的时候,界面是什么样子,或者想看一下定位的元素是否准确,这个时候我们还可以使用screenshot方法,如果页面过大,需要上下滑动才能显示完全,这个时候可以给定full_page=True代表对整个页面截图,同样此方法也可以针对页面的单一元素。
| page.screenshot(path="first_movie.png") # 截图并保存为 first_movie.png
page.screenshot(path="first_movie.png", full_page=True) # 截图并保存为 first_movie.png, 包含完整页面
lca = page.locator("xpath= /html/body/div[1]/div/div[3]/ul/li[1]/a") # 获取第一个电影的链接
lca.screenshot(path="first_movie_link.png") # 截图并保存为 first_movie_link.png
|
对于页面原生的提示框,我们可以通过dialog来处理,需要注意的是一定需要使用dismiss或者accept回应了原生弹窗之后才可以进行后续代码的处理,如果不进行任何操作,过了等待时间就会抛出异常
| def hint_ope(dialog):
print(dialog.message)
dialog.dismiss() # 关闭弹窗
# dialog.accept() # 确认弹窗
page.on("dialog", hint_ope) # 监听弹窗事件,触发 hint_ope 函数
|
另外如果我们不写hint_ope函数,不写对于dialog的回应,默认界面是点击取消按钮的,而如果dialog想要一些输入内容,我们可以在accept中填入对应的参数,这样文本就会直接填入:
| def hint_ope(dialog):
print(dialog.message) # 打印弹窗的提示信息
dialog.accept("这是你输入的内容") # 确认弹窗
page.on("dialog", hint_ope) # 监听弹窗事件,触发 hint_ope 函数
|
最后说一个检查的技巧,页面上有些元素是在其他元素hover的时候才进行显示,这个时候我们可以在控制台(Console)去输入debugger 或者 延时debug setTimeout(function(){debugger}, 3000) 进入调试模式,冻结页面,这样我们就能更方便地定位这些在特定场景下才显示的内容,比如下方的这个界面,下拉菜单只在鼠标悬浮在“移动客户端”上才进行显示
这里就是playwright经常会用到的一些动作和元素获取方法了,以供参考,更多方法可以参考官方文档