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定位邮箱账号的输入框
代码:根据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")
执行结果如下:
报错完整信息:
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 中,如下图:
二、切入到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邮箱,输入邮箱账号和密码后,点击页面的基本版按钮
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()