首页 > 编程语言 >python+playwright 学习-52 iframe 定位与操作元素,监听事件,执行JS脚本总结

python+playwright 学习-52 iframe 定位与操作元素,监听事件,执行JS脚本总结

时间:2023-04-17 12:55:53浏览次数:44  
标签:playwright name python frame JS locator 对象 iframe page

前言

本篇全面总结关于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


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


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://47.108.155.10/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://47.108.155.10/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


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


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


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的方法

标签:playwright,name,python,frame,JS,locator,对象,iframe,page
From: https://www.cnblogs.com/yoyoketang/p/17325352.html

相关文章

  • Springboot使用RestTemplate发送Post请求postForEntity (application/json)的坑
    当使用RestTemplate进行http请求时,的确很方便,但是当需要进行post请求时遇到了坑1POST传递参数:采用LinkedMultiValueMap,不能使用HashMapStringurl='http://posturl';MultiValueMap<String,String>map=newLinkedMultiValueMap<String,String>();map.add(......
  • JS中Map、WeakMap和Object的区别
    JavaScript中的Map、WeakMap和Object都是用于存储键值对的数据结构:1.Map:Map是一种新的数据结构,它允许使用任何数据类型(包括对象和基本数据类型)作为键。Map的一些特性包括:-保持键的插入顺序:当遍历Map时,键值对会按照插入顺序返回。-键可以是任意类型:与Object不同,Map的键可以......
  • 【迭代器设计模式详解】C/Java/JS/Go/Python/TS不同语言实现
    简介迭代器模式(IteratorPattern),是一种结构型设计模式。给数据对象构建一套按顺序访问集合对象元素的方式,而不需要知道数据对象的底层表示。迭代器模式是与集合共存的,我们只要实现一个集合,就需要同时提供这个集合的迭代器,就像Java中的Collection,List、Set、Map等,这些集合都有自......
  • Python 深度学习架构实用指南:第三、四、五部分
    原文:Hands-OnDeepLearningArchitectureswithPython协议:CCBY-NC-SA4.0译者:飞龙本文来自【ApacheCN深度学习译文集】,采用译后编辑(MTPE)流程来尽可能提升效率。不要担心自己的形象,只关心如何实现目标。——《原则》,生活原则2.3.c第3节:序列建模在本节中,我们将学习......
  • js报错:devtools failed to load source map : could no load content for
    报错:DevToolsfailedtoloadsourcemap:Couldnotloadcontentforhttp://localhost:8000/css/bootstrap.min.css.map:HTTPerror:statuscode404,net::ERR_HTTP_RESPONSE_CODE_FAILURE 解决方法:F12-点击设置齿轮-取消勾选EnableJavaScriptsourcemaps和EnableCSS......
  • python学习之-加密字体反扒
    #coding=utf-8'''#获取实习僧招聘信息#(https://www.shixiseng.com/interns?page=2&type=intern&keyword=%E6%95%B0%E6%8D%AE%E6%8C%96%E6%8E%98&area=&months=&days=°ree=&official=&enterprise=&salary=-0&publishTime=......
  • 技术老鸟告诉你Python为什么能一跃成为世界排名第一的语言
    本文首发自「慕课网」,想了解更多IT干货内容,程序员圈内热闻,欢迎关注"慕课网"!作者:大周|慕课网讲师一、前言本文将结合个人经历为各位同学客观的分析是否有学习Python的必要、Python适合谁学、为什么要学,希望能够给看到此文章的同学一点建议,树立学习目标,让学习有结果。读完后,相信你一......
  • JSON.stringify()与JSON.parse()没有你想的那样简单
    重新学习这两个API的起因在本周五有线上的项目,16:30开始验证线上环境。开始都是顺顺利利,一帆风顺。大概17:50左右,我正在收拾东西。准备下班去王者峡谷骑着我的船溜达一圈。可是天降意外,给我派了一个bug。测试给我说:有一条数据的详情页有数据但是在页面中没有显示数据。不可......
  • 记录selenium,python自动化测试中的chromedriver.exe地址和打开后自动关闭浏览器问题
    selenium的官方地址为:https://selenium-python.readthedocs.io/index.html镜像地址:https://npmmirror.com/#导入webdriverfromseleniumimportwebdriverfromselenium.webdriver.common.byimportBy#调用键盘按键操作时需要引入的Keys包fromselenium.webdriver.common.k......
  • [python] Python枚举模块enum总结
    枚举是一种数据类型,在编程中用于表示一组相关的常量。枚举中的每个常量都有一个名称和一个对应的值,可以用于增强代码的可读性和可维护性。在Python中,枚举是由enum模块提供的,而不是Python提供专用的枚举语法。关于enum模块介绍见:enum。如需详细了解Python的enum模块,参见文章:Python......