说明:本篇博客基于selenium 4.1.0
场景说明
场景:页面存在frame、iframe嵌套结构。frame是html中的一种标签,可在一个页面中拼接多个网页
问题:selenium不能直接定位和操作处于frame、iframe内的元素
解决:使用selenium的frame切换功能,切换到frame内后再进行操作
切换步骤
# 步骤1:根据frame定位,创建frame对象
ele_frame = driver.find_element(By.XPATH, '/html/body/iframe')
# 步骤2:传入frame对象,切换到对应frame中
# 备注:
# 1.可直接传入frame的id、name信息
# 2.可直接传入frame的frame编号,dom结构中的第一个frame编号为0
# 3.存在frame嵌套,即frame中的frame,需要一层层的进入
driver.switch_to.frame(ele_frame)
# 步骤3:退出当前frame
driver.switch_to.default_content() # 切换到默认frame
driver.switch_to.parent_frame() # 切换到父级frame
示例
import time
from selenium import webdriver
from selenium.webdriver.common.by import By
driver = webdriver.Chrome()
driver.implicitly_wait(10)
driver.get('http://sahitest.com/demo/iframesTest.htm')
locator_link = (By.CSS_SELECTOR, '[href="linkTest.htm"]')
print(len(driver.find_elements(*locator_link))) # 未切换frame,元素列表长度为0,说明selenium查询元素失败
# 切换到frame内
ele_frame = driver.find_element(By.XPATH, '/html/body/iframe')
driver.switch_to.frame(ele_frame)
print(len(driver.find_elements(*locator_link))) # 切换frame后,元素列表长度为1,说明selenium查询元素成功
driver.find_element(*locator_link).click() # 元素可正常点击
# 返回主页面
driver.switch_to.parent_frame()
driver.find_element(By.CSS_SELECTOR, '[value="Click me"]').click() # 主页面元素可正常点击
time.sleep(3)
driver.quit()
driver.switch_to.frame()源码
def frame(self, frame_reference) -> None:
"""
Switches focus to the specified frame, by index, name, or webelement.
Args:
- frame_reference: The name of the window to switch to, an integer representing the index,
or a webelement that is an (i)frame to switch to.
Usage:
driver.switch_to.frame('frame_name')
driver.switch_to.frame(1)
driver.switch_to.frame(driver.find_elements(By.TAG_NAME, "iframe")[0])
"""
# 传入参数为str,selenium会尝试进行定位获取frame元素对象
if isinstance(frame_reference, str):
try:
frame_reference = self._driver.find_element(By.ID, frame_reference)
except NoSuchElementException:
try:
frame_reference = self._driver.find_element(By.NAME, frame_reference)
except NoSuchElementException:
raise NoSuchFrameException(frame_reference)
# 切换到frame
self._driver.execute(Command.SWITCH_TO_FRAME, {'id': frame_reference})