Selenium之iframe操作

在Selenium中使用元素定位的时候,有时候会遇到定位不到元素的问题。这种情况下有可能是因为所定位的元素是在frame中。

frame标签有iframe、frame、frameset三种,frameset 跟其他普通标签没有区别,不会影响到正常的定位,而 iframe 与 frame 对 selenium 定位而言是一样的,selenium 有一组方法对 frame 进行操作。frame、frameset基本上已经弃用。

iframe:iframe 标签是 HTML 的一个内联框架,它能够将另一个 HTML 页面嵌入到当前页面中,且所有主流浏览器都支持iframe标签。

基本语法:<iframe src="文件路径"></iframe>


一、案例:

以qq邮箱(https://mail.qq.com/)为例,如下图根据元素的id定位邮箱账号的输入框
image

代码:根据id定位在邮箱账号输入框输入邮箱账号

from selenium import webdriver

# 打开Chrome浏览器
driver = webdriver.Chrome("../login/chromedriver.exe")

# 浏览器访问qq邮箱地址
driver.get("https://mail.qq.com/")

# 根据id定位邮箱账号输入框,输入邮箱账号123456@qq.com
driver.find_element_by_id("u").send_keys("123456@qq.com")

执行结果如下:
image

报错完整信息:

selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element: {"method":"css selector","selector":"[id="u"]"}
  (Session info: chrome=111.0.5563.111)

总结:查看qq邮箱登录页面的 HTML 代码,整个登录的窗口实际是在一个 iframe 中,如下图:
image


二、切入到iframe中

注:如果所定位的元素是在 iframe 中,那么必须先切入到 iframe 中再对元素进行定位。

切入 iframe 中的方法:switch_to.frame(frame_reference)

driver.switch_to.frame(frame_reference)

frame_reference 是传入的参数,用来定位 frame ,可以传入 id、name、index 以及 selenium 的 WebElement 对象,假设有如下 HTML 代码 index.html:

<html lang="en">
<head>
    <title>iframetest</title>
</head>
<body>
<iframe src="a.html" id="fid" name="fname">
</iframe>
</body>
</html>

想要定位其中的 iframe 并切入 iframe 中,可以通过如下代码:

from selenium import webdriver

# 打开Chrome浏览器
driver = webdriver.Chrome("../login/chromedriver.exe")

# 浏览器访问地址
driver.get("https://mail.qq.com/")

# 1.用id来定位
driver.switch_to.frame("fid")

# 2.用name来定位
driver.switch_to.frame("fname")

# 3.用frame的index来定位,第一个是0
driver.switch_to.frame(0)

# 4.用WebElement对象来定位
driver.switch_to.frame(driver.find_element_by_tag_name("iframe"))

通常采用 id 和 name 就能够解决绝大多数问题。但有时候iframe并无这两项属性,则可以用 index 和 WebElement 来定位:

  • index 从 0 开始,传入整型参数即判定为用 index 定位,传入 str 参数则判定为用 id/name 定位

  • WebElement 对象,即用 find_element 系列方法所取得的对象,我们可以用 css、xpath 等来定位 iframe 对象


实例:
以访问qq邮箱,输入邮箱账号和密码为例,采用不同的定位方式

from selenium import webdriver


# 打开Chrome浏览器
driver = webdriver.Chrome("../login/chromedriver.exe")

# 浏览器访问qq邮箱地址
driver.get("https://mail.qq.com/")

# 1、id定位,通过iframe的id="login_frame"
driver.switch_to.frame("login_frame")

# 2、name定位,通过iframe的name="login_frame"
# driver.switch_to.frame("login_frame")

# 3、index定位,通过iframe的index来定位,第一个是0,当前的iframe是第二个,所以index=1
# driver.switch_to.frame(1)

# 4、WebElement对象定位,此处使用css
# driver.switch_to.frame(driver.find_element_by_css_selector("#login_frame"))

# 5、WebElement对象定位,此处使用xpath
# driver.switch_to.frame(driver.find_element_by_xpath("//*[@id='login_frame']"))

# 根据id定位邮箱账号输入框,输入邮箱账号123456@qq.com
driver.find_element_by_id("u").send_keys("123456@qq.com")

三、从iframe中切出

注:切入到 iframe 中之后,如果想对 iframe 外的元素进行操作,必须先从 iframe 中切出后才能操作元素。

从 iframe 中切出的方法:switch_to.default_content()

driver.switch_to.default_content()

实例:
访问qq邮箱,输入邮箱账号和密码后,点击页面的基本版按钮
image

from selenium import webdriver


# 打开Chrome浏览器
driver = webdriver.Chrome("../login/chromedriver.exe")

# 浏览器访问qq邮箱地址
driver.get("https://mail.qq.com/")

# 1、id定位,通过iframe的id="login_frame"
driver.switch_to.frame("login_frame")

# 根据id定位邮箱账号输入框,输入邮箱账号123456@qq.com
driver.find_element_by_id("u").send_keys("123456@qq.com")

# 从当前的iframe中切出
driver.switch_to.default_content()

# 根据超链接使用link_text方法定位"基本版"并点击
driver.find_element_by_partial_link_text("基本版").click()

四、嵌套iframe的操作

有时候我们会遇到 iframe 嵌套 iframe 的情况,如下:

<html>
    <iframe id="iframe1">
        <iframe id="iframe2" / >
    </iframe>
</html>

1、从 HTML 的主文档先切入到 iframe1 再切入到 iframe2,一层层切入进去。

driver.switch_to.frame("iframe1")
driver.switch_to.frame("iframe2")

2、从 iframe2 再切回 iframe1,这里 selenium 给我们提供了一个方法能够从子 iframe 切回到父 iframe,而不用我们切回主文档再切进来。

driver.switch_to.parent_frame()  # 如果当前已是html主文档,则无效果

总结:iframe常用的方法

# 从html主文档切入到iframe中,使用id、name、index以及selenium的 WebElement对象
driver.switch_to.frame(frame_reference)

# 从子iframe切入到父iframe中
driver.switch_to.parent_frame()

# 从iframe中切出到html主文档中
driver.switch_to.default_content()

注意有的python版本中使用的方法是:driver.switch_to_frame()

posted @ 2023-03-29 17:10  ll=ll  阅读(1819)  评论(0编辑  收藏  举报