先看一个例子:
这是 163 邮箱登录页面,我们想模拟一下邮箱登录。
driver.find_element_by_name('email').send_keys('nemo')
额,报错了!Selenium 告诉我们:Message: no such element: Unable to locate element。
检查定位方式对的啊,name 属性嘛。可为什么就是要报错呢?
仔细观察页面结构,我们发现要操作的登录元素都是放在一个叫 iframe 的元素中,而且还是一个完整的 HTML(有 HTML 声明和 html 根节点):
<iframe>
标签创建包含另一个文档的行内框架。
iframe 用来包含一个独立的 HTML 文档。相当于在一个 HTML 页面中包含了另一个 HTML 页面。所以也称为内嵌页面,由于其定义是 HTML 中的一个框架,所以也称为内联框架。
现代网页中主要使用 iframe 来解决跨域的问题。比如这个登录是 163 的单点登录,邮箱只是 163 账号可登录站点中的一个,所以登录站点和邮箱不在同一个域下面,需要用 iframe 来解决跨域问题。
当你想操作 iframe 中内嵌的页面中的元素时,已经脱离了当前页面。
如何判断是否是当前页面?
你可以尝试在页面上右键单击,然后选择“查看网页源码”,看到的 HTML 代码就是当前页面。
对于脱离于当前页面的元素,WebDriver 提供了 switch_to.frame() 方法,用来跳转到需要操作的页面。(注意,只有frame()
方法没有iframe())
要跳转到对应的 iframe 元素,可以通过以下四种方式来指定:
方式 | 说明 | 举例 |
---|---|---|
index | 通过 iframe 在页面中出现的顺序 | driver.switch_to.frame(0) 选择第一个 |
id | 通过 iframe 的 id 属性 | driver.switch_to.frame('frame-id') |
name | 通过 iframe 的 name 属性 | driver.switch_to.frame('frame-name') |
WebElement | 没有合适的 id,name 属性 通过 find_element() 找到 iframe 元素再跳转 |
iframe = driver.find_element_by_xpath('//*[id="login"]/iframe') driver.switch_to.frame(iframe) |
这里 163 邮箱登录的案例,没有 id 也没有 name ,我们选择第四种方式:
# 定位到 iframe 元素
iframe = driver.find_element_by_css_selector('#loginDiv>iframe')
# 跳转到 iframe
driver.switch_to.frame(iframe)
# 操作
driver.find_element_by_name('email').send_keys('nemo')
# 跳出 iframe
driver.switch_to.default_content()
在 iframe 中操作之后,操作外面的元素需要跳出来。跳出方式有两种:
driver.switch_to.parent_frame() # 跳到父级 frame 元素
driver.switch_to.default_content() # 跳到最外层页面
如果有多级 iframe 的情况下,通过driver.switch_to.parent_frame()
可以只跳一级。而driver.switch_to.default_content()
是在任何情况下都跳转到最外层页面。
注意,在 iframe 操作后一定要跳出 iframe,如果没有跳出 Firefox 浏览器可能会出现异常。