回顾:
还记得登录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 。
三、再来看下163邮箱登录页
该登录输入框果然在一个ifame下,问题是找到了,不过我觉得你应该有个疑问?究竟什么时候该去元素上面看看,其是不是在一个ifame下呢?当定位方式没错,又找不到的时候就该去看看了?关键隔着要定位的元素好远,找起来还真有点费劲。
小技巧:
使用Firefox 浏览器提供的插件,可以方便的看到一个元素是否依托于一个iframe,上两张截图,大家就明白了。
截图一:输入框在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() 方法在使用的时候被横线划掉,说明不建议使用,现在虽然能用,但是以后版本升级后可能会废弃。
六、其它切 frame 方法
这个 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,进去的时候一层层进,出来的时候可以一层层出,也可以直接跳到最外层。