14、Selenium + Python 实现 UI 自动化测试-操作Frame(iFrame)

回顾:

还记得登录163邮箱那篇文章中遇到的问题吗?(http://blog.csdn.net/duzilonglove/article/details/78083344),今天我们来解决掉他。


一、概念

先来看下这篇文章中对Frame和iFrame的介绍:

原文地址:http://blog.csdn.net/lyr1985/article/details/6067026

这里摘抄一小段:

frame是把网页分成多个页面的页面。它要有一个框架集页面frameset   
  iframe是一个浮动的框架,就是在你的页面里再加上一个页面, 

<frame>用来把页面横着或竖着切开,   
  <iframe>用来在页面中插入一个矩形的小窗口 

Frame一般用来设置页面布局,将整个页面分成规则的几块,每一块里面包含一个新页面.   
  iframe用来在页面的任何地方插入一个新的页面.   
    
  因此,Frame用来控制页面格式,比如一本书,左边是章节目录,右边是正文,正文很长,看的时候要拖动,但又不想目录也被拖动得开不到了.因此最好将页面用Frame分成规则的2页,一左一右.   
    
  而iframe则更灵活,不要求将整个页面划分,你可以在页面任何地方用iframe嵌入新的页面. 

我个人认为:   
  <frame>用于全页面   
  <iframe>只用于局部


二、再放张图,解释下

下面这张图,黑框是一个web页面,页面下有4个元素,元素1、元素2、页面iframe1、页面iframe2,从web页面只能找到上面4个元素;如果你想找(操作)元素3,那么你需要先切换到页面 iframe 1,然后再定位元素3 。如果这时候想操作元素4,你必须先切回web页面,然后切到页面 iframe 2 ,然后再操作元素4 。

14、Selenium + Python 实现 UI 自动化测试-操作Frame(iFrame)


三、再来看下163邮箱登录页

14、Selenium + Python 实现 UI 自动化测试-操作Frame(iFrame)

该登录输入框果然在一个ifame下,问题是找到了,不过我觉得你应该有个疑问?究竟什么时候该去元素上面看看,其是不是在一个ifame下呢?当定位方式没错,又找不到的时候就该去看看了?关键隔着要定位的元素好远,找起来还真有点费劲。


小技巧:

使用Firefox 浏览器提供的插件,可以方便的看到一个元素是否依托于一个iframe,上两张截图,大家就明白了。

截图一:输入框在iframe上

14、Selenium + Python 实现 UI 自动化测试-操作Frame(iFrame)

截图二:图片在顶层页面下

14、Selenium + Python 实现 UI 自动化测试-操作Frame(iFrame)


四、模拟163邮箱输入用户名、密码

from selenium import webdriver
from time import sleep

driver = webdriver.Chrome()
driver.get('http://mail.163.com/')
driver.implicitly_wait(20)
ele = driver.find_element_by_id('x-URS-iframe')  #先定位这个 iframe 页面
driver.switch_to.frame(ele)   #然后切到这个 iframe 页面
driver.find_element_by_name('email').send_keys('hellopython')
sleep(3)
driver.quit()


五、解析

(1)selenium 提供了 switch_to.frame() 方法来切 frame / iframe;

(2)switch_to_frame() 方法在使用的时候被横线划掉,说明不建议使用,现在虽然能用,但是以后版本升级后可能会废弃。

14、Selenium + Python 实现 UI 自动化测试-操作Frame(iFrame)


六、其它切 frame 方法

14、Selenium + Python 实现 UI 自动化测试-操作Frame(iFrame)

这个 frame_reference 是指什么呢?


1、在4中,我们先通过 id 定位到 frame 页面,然后通过 switch_to.frame() ,切到之前定位到的 frame上;

2、直接传id

from selenium import webdriver
from time import sleep

driver = webdriver.Chrome()
driver.get('http://mail.163.com/')
driver.implicitly_wait(20)
sleep(5)
driver.switch_to.frame('x-URS-iframe')  #这里直接传id
driver.find_element_by_name('email').send_keys('hellopython')
sleep(3)
driver.quit()

3、直接传name

163邮箱 iframe 没有name属性,所以这里没示例


4、传 index

driver.switch_to.frame(0)  #这里直接传index,从0开始算第一个 iframe

好,这里我们自己写个html,然后总结下切 frame 、iframe 的用法

html页面源码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>测试</title>
</head>
<body>
<iframe src="http://www.baidu.com/" id="frame1" name="myframe"></iframe>
</body>
</html>

切 frame 方法如下:

from selenium import webdriver
driver = webdriver.Firefox()
driver.switch_to.frame(0)  # 1.用frame的index来定位,第一个是0
# driver.switch_to.frame("frame1")  # 2.用id来定位
# driver.switch_to.frame("myframe")  # 3.用name来定位
# driver.switch_to.frame(driver.find_element_by_tag_name("iframe"))  # 4.用WebElement对象来定位

通常采用id和name就能够解决绝大多数问题。但有时候frame并无这两项属性,则可以用index和WebElement来定位:
index从0开始,传入整型参数即判定为用index定位,传入str参数则判定为用id/name定位
WebElement对象,即用find_element系列方法所取得的对象,我们可以用tag_name、xpath等来定位frame对象
举个栗子:

<iframe src="test.gif" />

用xpath定位,传入WebElement对象:
driver.switch_to.frame(driver.find_element_by_xpath("//iframe[contains(@src,'test')]"))


七、再看下我们第二段中的图片,如果已经切到了frame 1 ,现在想操作 元素4 怎么办?

selenium 给我们提供了下面2种方法:

1、driver.switch_to.parent_frame()  切回父 frame
2、driver.switch_to.default_content()  切回 默认 frame ,主frame

from selenium import webdriver
from time import sleep

driver = webdriver.Chrome()
driver.get('http://sahitest.com/demo')
driver.implicitly_wait(20)
driver.find_element_by_link_text('IFrames Test').click()

driver.switch_to.frame(0) #进入第一个frame,默认frame
driver.find_element_by_link_text('Alert Test').click() #点击一个link
sleep(3)

driver.switch_to.parent_frame()  #切回父窗口
driver.switch_to.frame(1)  #切到第二个frame
driver.find_element_by_link_text('Confirm Page').click() #点击一个连接
sleep(3)
driver.switch_to.default_content() #切回主窗口,这里主窗口和父窗口是一个
driver.switch_to.frame(0)  #切回第一个frame
driver.find_element_by_xpath('/html/body/a').click() #点击返回连接
sleep(3)
driver.quit()

总之,记住,想操作iframe 、frame 里面的元素,就要先切到这个 frame 上,然后进行操作。想操作frame 外面的元素,就必须跳出这个 frame。对于嵌套的frame,进去的时候一层层进,出来的时候可以一层层出,也可以直接跳到最外层。