【selenium】多 frame 切换定位元素

本文介绍了HTML中的frame框架导航,展示了如何使用frame实现页面局部刷新,而非全新开窗。此外,还详细讲解了web自动化测试中如何定位frame内的元素。

frame 简介

framehtml 中的框架导航。同一个框架集中,点击某一框架的超链接,内容会在另一个框架的窗口中展示。

比如后台管理页面,点击左侧导航栏按钮,在右侧区域展示加载的内容,而不是打开一个新的窗口。

frame 简介

framehtml 中的框架导航。同一个框架集中,点击某一框架的超链接,内容会在另一个框架的窗口中展示。

比如后台管理页面,点击左侧导航栏按钮,在右侧区域展示加载的内容,而不是打开一个新的窗口。

代码如下,可访问在线 html 运行网站编辑查看。a

<!-- https://www.w3school.com.cn/tiy/t.asp?f=html_frame_cols -->
<html>
    
<frameset rows="15%,*">
    
    <frame src="/example/html/frame_a.html">
    
    <frameset cols="20%,*">
    <frame src="/example/html/frame_b.html">
    <frame src="/example/html/frame_c.html" name="show">
    </frameset>

</frameset>

</html>

在左侧导航栏页面添加 href 标签和 traget 属性,即可实现页面框架跳转。

<!-- 1、定义框架集中每个框架的名称 -->
<frame src="/example/html/frame_c.html" name="show">
<!-- 2、左侧导航栏页面内添加 target 属性 -->
<a href=url target="show">

fram 定位

frame标签包含三种:

  • frameset和普通的标签定位方式一致,通过id、name等常规方式;
  • frameiframe则需要切换进入frame内,才能进行定位。

web自动化中,如果某个元素定位不到,则很有可能是隐藏在frame中。

多 frame 切换

切换 frame 方式如下。

# 通过 id 切换
driver.switch_to.frame('buttonframe')

# 通过 web element 切换
iframe = driver.find_element(By.CSS_SELECTOR, "#modal > iframe")
driver.switch_to.frame(iframe)  

# 多元素通过 index 切换
iframe = driver.find_elements(By.TAG_NAME,'iframe')[1]
driver.switch_to.frame(iframe)

# 回到默认 frame
driver.switch_to.default_content()

# 切换到父 frame
driver.switch_to.parent_frame() 

对于嵌套的 frame,需要先进入到父节点,再切换进入子节点,然后对子节点进行操作。

driver.switch_to.frame("父节点")
driver.switch_to.frame("子节点")

示例

with webdriver.Chrome() as driver:
    driver.get("https://www.runoob.com/try/try.php?filename=jqueryui-api-droppable")

    btn_locator = (By.ID, "draggable")
    # 该元素是「请拖拽我」,运行报错:NoSuchElementException
    # 因为该元素在 iframe 标签内,直接无法定位到元素
    # driver.find_element(*btn_locator).text)

    driver.switch_to.frame("iframeResult")  # 切换到 iframe 内
    assert driver.find_element(*btn_locator).text == "请拖拽我!"

    submit_locator = (By.ID, "submitBTN")
    # 点击提交按钮,运行报错:NoSuchElementException
    # 因为提交按钮在当前 iframe 外,还需要切出去
    # driver.find_element(*submit_locator).click()

    driver.switch_to.parent_frame()  # 切回父 frame
    assert driver.find_element(*submit_locator).text == "点击运行 》"

代码如下,可访问在线 html 运行网站编辑查看。a

<!-- https://www.w3school.com.cn/tiy/t.asp?f=html_frame_cols -->
<html>
    
<frameset rows="15%,*">
    
    <frame src="/example/html/frame_a.html">
    
    <frameset cols="20%,*">
    <frame src="/example/html/frame_b.html">
    <frame src="/example/html/frame_c.html" name="show">
    </frameset>

</frameset>

</html>

在左侧导航栏页面添加 href 标签和 traget 属性,即可实现页面框架跳转。

<!-- 1、定义框架集中每个框架的名称 -->
<frame src="/example/html/frame_c.html" name="show">
<!-- 2、左侧导航栏页面内添加 target 属性 -->
<a href=url target="show">

fram 定位

frame标签包含三种:

  • frameset和普通的标签定位方式一致,通过id、name等常规方式;
  • frameiframe则需要切换进入frame内,才能进行定位。

web自动化中,如果某个元素定位不到,则很有可能是隐藏在frame中。

多 frame 切换

切换 frame 方式如下。

# 通过 id 切换
driver.switch_to.frame('buttonframe')

# 通过 web element 切换
iframe = driver.find_element(By.CSS_SELECTOR, "#modal > iframe")
driver.switch_to.frame(iframe)  

# 多元素通过 index 切换
iframe = driver.find_elements(By.TAG_NAME,'iframe')[1]
driver.switch_to.frame(iframe)

# 回到默认 frame
driver.switch_to.default_content()

# 切换到父 frame
driver.switch_to.parent_frame() 

对于嵌套的 frame,需要先进入到父节点,再切换进入子节点,然后对子节点进行操作。

driver.switch_to.frame("父节点")
driver.switch_to.frame("子节点")

示例

with webdriver.Chrome() as driver:
    driver.get("https://www.runoob.com/try/try.php?filename=jqueryui-api-droppable")

    btn_locator = (By.ID, "draggable")
    # 该元素是「请拖拽我」,运行报错:NoSuchElementException
    # 因为该元素在 iframe 标签内,直接无法定位到元素
    # driver.find_element(*btn_locator).text)

    driver.switch_to.frame("iframeResult")  # 切换到 iframe 内
    assert driver.find_element(*btn_locator).text == "请拖拽我!"

    submit_locator = (By.ID, "submitBTN")
    # 点击提交按钮,运行报错:NoSuchElementException
    # 因为提交按钮在当前 iframe 外,还需要切出去
    # driver.find_element(*submit_locator).click()

    driver.switch_to.parent_frame()  # 切回父 frame
    assert driver.find_element(*submit_locator).text == "点击运行 》"

在使用 Selenium 进行页面切换时,如果遇到无法定位元素的问题,可能是由种原因导致的。以下是几种常见的解决方法,涵盖 iframe 切换、页面加载延迟、元素遮挡和窗口大小等方面: ### 1. 检查是否需要切换 iframe 当页面中包含嵌套的 iframe 时,Selenium 默认处于主文档上下文中,无法直接定位 iframe 中的元素。此时需要使用 `switch_to.frame()` 方法切换到对应的 iframe 中。例如: ```python driver.switch_to.frame(driver.find_element_by_xpath("//iframe[contains(@src,'myframe')]")) ``` 如果当前处于某个子 iframe 中,并希望切换回父 iframe,可以使用: ```python driver.switch_to.parent_frame() ``` 切换完成后,就可以在对应的 iframe 上下文中定位元素了 [^5]。 ### 2. 等待页面加载完成 有时页面加载速度较慢,导致 Selenium元素还未加载完成时尝试定位,从而引发 `NoSuchElementException` 异常。可以通过显式等待(`WebDriverWait`)来确保元素加载完成后再进行操作。例如: ```python from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC # 等待元素出现 wait = WebDriverWait(driver, 10) element = wait.until(EC.presence_of_element_located((By.LINK_TEXT, '基本版'))) element.click() ``` 显式等待可以确保页面元素在操作前已经加载完成,从而避免因加载速度导致的定位失败 [^4]。 ### 3. 检查元素是否被遮挡或不可见 如果元素虽然存在于页面中,但被其他元素遮挡或处于不可见状态(如 `display: none` 或 `visibility: hidden`),也会导致定位失败或操作无效。可以通过以下方式检查: - **最大化浏览器窗口**:有时页面布局会因窗口大小变化而调整,导致某些元素被遮挡,可以通过最大化窗口来避免这种情况: ```python driver.maximize_window() ``` - **判断元素是否可见**:使用 `.is_displayed()` 方法检查元素是否可见: ```python element = driver.find_element(By.ID, "element_id") if element.is_displayed(): element.click() ``` - **判断元素是否可用**:使用 `.is_enabled()` 方法检查元素是否可交互(未被禁用): ```python if element.is_enabled(): element.click() ``` 这些方法可以帮助识别因布局或样式问题导致的元素不可见或不可操作问题 [^3]。 ### 4. 检查页面切换是否成功 页面切换后,Selenium 的上下文仍然可能停留在原页面,导致无法定位新页面上的元素。可以使用 `window_handles` 获取当前所有窗口句柄,并切换到最新打开的窗口: ```python # 获取当前所有窗口句柄 handles = driver.window_handles # 切换到最新打开的窗口 driver.switch_to.window(handles[-1]) ``` 确认当前窗口是否为目标页面后,再进行元素定位 [^1]。 ### 5. 检查元素是否存在或是否被动态修改 有时页面元素是通过 JavaScript 动态加载的,或者由于业务逻辑导致元素在特定条件下不存在。可以通过以下方式排查: - **确认元素是否存在**:使用 `find_elements` 而不是 `find_element` 来判断元素是否存在: ```python elements = driver.find_elements(By.LINK_TEXT, '基本版') if len(elements) > 0: elements[0].click() ``` - **检查 DOM 结构**:通过浏览器的开发者工具查看当前页面的 HTML 结构,确认目标元素是否确实存在,并检查其属性是否发生变化(如 `id`、`class` 等)。 如果元素确实不存在或被动态修改,可能是页面逻辑问题,需要与开发人员沟通确认 [^3]。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值