python+playwright 学习-52 iframe 定位与操作元素,监听事件,执行JS脚本总结
前言
本篇全面总结关于iframe 的定位,iframe上元素的操作(输入框,点击等),iframe 上的事件监听 与iframe上执行JS脚本的总结。
iframe 对象的定位
定位iframe 对象,总的来说有四种方法
- page.frame_locator(selector) 通过page对象直接定位iframe 对象,传selector 选择器参数
- page.locator(selector).frame_locator(selector) 通过page对象定位某个父元素,通过locator定位frame_locator(selector)
- page.frame(name,url) 通过page对象直接定位iframe 对象,传name 或者url参数
- page.query_selector(selector).content_frame() 通过query_selector方式,定位到元素,转成frame 对象
page 对象还有2个跟frame 相关的方法
- page.frames 获取page对象全部iframes,包含page本身的frame对象
- page.main_frame 获取page的main_frame (page对象本身也是一个frame对象)
什么是iframe
iframe 简单来说就是一个 html 嵌套了另外一个 html。在页面元素上最简单的识别方法,就是看你需要定位的元素外层有没有iframe的标签名称
比如以下网页看到外层就有3个iframe
官网上写了个示例,可以快速查看iframe的层级结构
使用示例
from playwright.sync_api import sync_playwright
# 上海悠悠 wx:283340479
# blog:https://www.cnblogs.com/yoyoketang/
def dump_frame_tree(frame, indent):
print(indent + frame.name + '@' + frame.url)
for child in frame.child_frames:
dump_frame_tree(child, indent + " ")
with sync_playwright() as p:
browser = p.chromium.launch(headless=False)
page = browser.new_page()
page.goto("file:///C:/Users/dell/Desktop/home.html")
dump_frame_tree(page.main_frame, "")
browser.close()
于是可以看到层级结构如下
也就是主页面(主页面其实也可以看成一个iframe 对象)下有3个iframe,其中最后一个iframe2下又嵌套了一层iframe。
下面示例用到了3个基本方法
- page.main_frame 获取page对象本身的 frame 对象
- page.frames 获取page对象全部frames 包含page本身的frame对象
- frame.child_frames 获取frame下的全部子 frame 对象
from playwright.sync_api import sync_playwright
# 上海悠悠 wx:283340479
# blog:https://www.cnblogs.com/yoyoketang/
with sync_playwright() as p:
browser = p.chromium.launch(headless=False)
page = browser.new_page()
page.goto("file:///C:/Users/dell/Desktop/home.html")
print('获取page对象本身的frame对象')
print(page.main_frame)
print('获取page对象全部frames 包含page本身的frame对象 ')
print(page.frames)
print('获取page对象子frame ')
print(page.main_frame.child_frames)
browser.close()
运行结果
获取page对象本身的frame对象
<Frame name= url='file:///C:/Users/dell/Desktop/home.html'>
获取page对象全部frames 包含page本身的frame对象
[<Frame name= url='file:///C:/Users/dell/Desktop/home.html'>, <Frame name=yoyo url='http://127.0.0.0/login.html'>, <Frame name=iframe-auto2834976.42 url='file:///C:/Users/dell/Desktop/down.html'>, <Frame name=yoyo2 url='file:///C:/Users/dell/Desktop/iframe.html'>, <Frame name= url='file:///C:/Users/dell/Desktop/down.html'>]
获取page对象子frame
[<Frame name=yoyo url='http://127.0.0.0/login.html'>, <Frame name=iframe-auto2834976.42 url='file:///C:/Users/dell/Desktop/down.html'>, <Frame name=yoyo2 url='file:///C:/Users/dell/Desktop/iframe.html'>]
从运行结果可以看出,iframe 对象有2个重要的属性name和url, 可以直接打印出来看看
for frame in page.frames:
print(frame.name)
print(frame.url)
运行结果
file:///C:/Users/dell/Desktop/home.html
yoyo
http://47.108.155.10/login.html
iframe-auto9389828.64
file:///C:/Users/dell/Desktop/down.html
yoyo2
file:///C:/Users/dell/Desktop/iframe.html
file:///C:/Users/dell/Desktop/down.html
从结果可以看出。iframe 元素的name和id属性,都会被作为那么属性打印出来,如果2个属性都没有,那么获取的name属性为空字符
page.frame_locator(selector) 使用
如下图定位iframe上的输入框,并输入内容
基本语法
page.frame_locator(selector)
使用示例,可以直接定位到frame对象,继续定位元素操作
# 直接定位输入
page.frame_locator('[name="yoyo"]').locator("#username").fill('yoyoketang')
page.frame_locator('[name="yoyo"]').locator("#password").fill('123456')
或者先定位到iframe对象,再通过frame对象操作
# frame 对象操作
frame = page.frame_locator('[name="yoyo"]')
frame.locator("#username").fill('yoyoketang')
frame.locator("#password").fill('123456')
只需要定位到frame 对象,后面的元素定位操作都基本一样了。
也可以通过先定位外层的元素,再定位到frame对象,使用基本语法
page.locator(selector).frame_locator(selector)
page.frame(name,url) 的使用
page.frame 和 page.frame_locator 使用差异
- page.frame_locator('') 返回的对象只能用locator() 方法定位元素然后click()等操作元素
- page.frame() 返回的对象能直接使用fill() 和 click() 方法
page.frame(name,url) 方法可以使用frame的name属性或url属性定位到frame对象
方法一:name 属性可以是iframe 元素的name 或id属性
使用name属性定位示例
# name 属性定位
frame = page.frame(name="yoyo")
print(frame)
运行结果
<Frame name=yoyo url='http://47.108.155.10/login.html'>
name 属性不能模糊匹配,只能绝对匹配字符串
iframe元素没有那么属性,有id属性,也可以用
# id 属性也能定位
frame = page.frame(name="yoyo2")
print(frame)
运行结果
<Frame name=yoyo2 url='file:///C:/Users/dell/Desktop/iframe.html'>
方法二:url属性定位
url属性的值,就是我们看到页面上的src属性,可以支持模糊匹配
# url 支持模糊匹配
frame = page.frame(url='login.html')
print(frame)
iframe 上的动态id属性如何定位
有时候,我们看到的iframe 的id 不是固定的,是动态的一个id, 每次刷新,它的值都不一样(一般前面一部分是固定的)
可以用css的正则匹配元素属性
css的正则匹配
语法 | 描述 |
---|---|
$('[name^="value"]') |
匹配 name 以 value 开头的元素 |
$('[name$="end"]') |
匹配 name 以 end 结尾的元素 |
$('[class*="text"]') |
匹配class属性包含text的元素 |
使用示例
# css 正则匹配属性
frame = page.frame_locator('[id^="iframe-auto"]')
print(frame)
frame.locator('#username').fill('yoyo')
也可以使用xpath的contains 包含属性
# xpath的contains 包含属性
frame = page.frame_locator('//*[contains(@id, "iframe-auto")]')
print(frame)
frame.locator('#username').fill('yoyo')
2层iframe 如何操作
iframe 下嵌套另外一个iframe
解决办法没什么技巧,一层一层定位即可
# 一层一层定位
frame = page.frame_locator('#yoyo2').frame_locator('[src="down.html"]')
frame.locator('#username').fill("yoyoketang")
page.query_selector(selector).content_frame() 方法
还有一个不怎么常用的方法,使用page.query_selector(selector)
元素句柄的方式定位到iframe,然后使用content_frame() 方法切换到iframe对象上
语法规则
page.query_selector(selector).content_frame()
使用示例
# query_selector 方法
iframe = page.query_selector('[src="down.html"]').content_frame()
print(iframe)
监听 iframe 上的事件
事件可以通过page对象直接监听到
使用示例
from playwright.sync_api import sync_playwright
# 上海悠悠 wx:283340479
# blog:https://www.cnblogs.com/yoyoketang/
def handler(dialog):
print("监听dialog 事件")
print(dialog.message)
# dialog.accept()
with sync_playwright() as p:
browser = p.chromium.launch(headless=False)
page = browser.new_page()
page.goto("file:///C:/Users/dell/Desktop/home.html")
page.on('dialog', handler)
# 一层一层定位
frame = page.frame_locator('#yoyo2')
frame.locator('#alert').click()
page.pause()
browser.close()
运行结果可以看到page.on()可以截图到iframe上的事件
监听dialog 事件
删除后无法还原!
其它的下载事件,文件上传监听方法都一样。
在iframe 上执行JavasScript 代码
page.evaluate(js代码)
方法可以直接在page对象上执行JavasScript 代码
from playwright.sync_api import sync_playwright
# 上海悠悠 wx:283340479
# blog:https://www.cnblogs.com/yoyoketang/
def handler(dialog):
print("监听dialog 事件")
print(dialog.message)
# dialog.accept()
with sync_playwright() as p:
browser = p.chromium.launch(headless=False)
page = browser.new_page()
page.goto("file:///C:/Users/dell/Desktop/home.html")
page.on("dialog", handler)
# 执行JavaScript
page.evaluate("alert('hello world')")
page.pause()
browser.close()
在iframe上执行JavaScript代码,需在iframe对象上执行
from playwright.sync_api import sync_playwright
# 上海悠悠 wx:283340479
# blog:https://www.cnblogs.com/yoyoketang/
with sync_playwright() as p:
browser = p.chromium.launch(headless=False)
page = browser.new_page()
page.goto("file:///C:/Users/dell/Desktop/home.html")
iframe = page.frame(url='down.html')
# 执行js 给输入框输入内容
js = "document.getElementById('username').value='yoyo';"
iframe.evaluate(js)
page.pause()
browser.close()
如果需要在iframe上执行js代码,必须使用page.frame()方法定位到iframe对象,才有iframe.evaluate(js)
方法执行js。
page.frame_locator()
方法只能定位元素操作元素,没有执行js的方法