Selenium定位不到指定元素原因之iframe(unable to locate element)

浏览过程中,图片中的内容可能太小,无法看清,可以>右键>在新标签中打开

Outline

项目原因,需要用selenium实现模拟登陆、模拟上传文件,自然就需要模拟点击【上传】按钮;

模拟点击之前需要通过selenium提供的“方法”去定位到要点击的元素;

模拟登陆过程中,全程都可以定位到需要点击的元素,但登陆后需要定位点击【上传】按钮时问题来了;

元素明明在那放着,就是定位不到,这个问题困扰了一下午还没解决,最终走到了iframe这个一步,才得以解决。

什么是iframe

解决问题之前很有必要先了解下什么是iframe:

HTML内联框架元素 <iframe> 表示嵌套的浏览上下文,有效地将另一个HTML页面嵌入到当前页面中。在HTML 4.01中,文档可能包含头部和正文,或头部和框架集,但不能包含正文和框架集。

但是,<iframe>可以在正常的文档主体中使用。每个浏览上下文都有自己的会话历史记录和活动文档。包含嵌入内容的浏览上下文称为父浏览上下文。顶级浏览上下文(没有父级)通常是浏览器窗口。

 

iframe是HTML三种结构中的框结构,框结构中还有另外两个元素:framesetframe,但它们都已废弃,不再推荐使用。

HTML中iframe展示

如下图所示,右侧代码中圈出来的iframe标签,渲染之后在前端显示的就是左侧圈出来的区域;

也就是此iframe嵌套在该HTML框架中。

如何说明iframe是一个独立部分、是被嵌套到HTML框架内部的?见下图:

将iframe标签中的 src=/default/research/redirect 复制出来在地址栏进行链接替换,会发现此时的页面只有iframe独立部分,之前页面中的banner不见了。

参考:

深入理解iframe-简书

iframe文档

selenium定位元素

 selenium模拟登陆操作

部分代码:

    def auto_login(self):
        # 获取浏览器窗口对象
        driver = webdriver.Chrome()
        # 打开浏览器进入指定地址
        driver.get('https://ycjq.95358.com/research')

        # selenium进行元素定位、填写内容
        driver.find_element_by_name("CyLoginForm[username]").send_keys("你的账号")
        driver.find_element_by_name("CyLoginForm[pwd]").send_keys("你的密码")

        # 这里图像识别获取验证码  def valideCode():
        # driver.find_element_by_name("valideCode").send_keys("")

        # selenium进行元素定位、模拟点击(登陆)
        time.sleep(10)
        driver.find_element_by_id("btnSubmit").click()

页面分析:

根据标签的“name”、“id”等,进行元素定位,然后模拟操作。

执行上述代码,你会发现会自动打开浏览器,进入指定地址,然后会自动进行账号密码的输入,并且自动点击“登陆”;

然后会进行登陆后的页面跳转。

整个流程很正确也很合理,但页面跳转之后再进行元素定位、模拟点击时就有坑了。

切换iframe

 上一步“模拟登陆”时,HTML页面并不涉及 iframe 标签,但登陆过后就含有 iframe标签了。

所以再通过selenium进行模拟点击时就要切换iframe了。

在用selenium定位页面元素的时候会遇到定位不到的问题,明明元素就在那儿,用firebug也可以看到,就是定位不到,问题很有可能就出在iframe上。

 问题复现

错误代码复现:

    def auto_login(self):
        # 获取浏览器窗口对象
        driver = webdriver.Chrome()
        # 打开浏览器进入指定地址
        driver.get('https://ycjq.95358.com/research')

        # selenium进行元素定位、填写内容
        driver.find_element_by_name("CyLoginForm[username]").send_keys("你的账号")
        driver.find_element_by_name("CyLoginForm[pwd]").send_keys("你的密码")

        # selenium进行元素定位、模拟点击(登陆)
        time.sleep(10)
        driver.find_element_by_id("btnSubmit").click()
        time.sleep(10)
     # 定位到“上传”按钮
        driver.find_element_by_id('notebook_list_info').click()

可以确定下图的元素定位位置无误,理应可以通过selenium模拟点击的,但模拟点击之后一直提示找不到标签:

问题解决

问题出现之后,进行相关问题搜索,五花八门,各种解决方案,用了一下午,各种尝试,最终确定问题出在iframe。

只有切换到iframe里面,selenium才能定位到 iframe里面的元素。

切换iframe

selenium提供了switch_to.frame()方法来切换frame

switch_to.frame(reference)

注意:

可能你会这样写:switch_to_frame(),但会发现,这段代码被加上“删除线”了;

原因是这个方法已经out了,之后可能被废弃,建议switch_to.frame()

 

switch_to.frame(reference)中的reference是传入的参数,用来定位frame,可以传入id、name、index以及selenium的WebElement对象。

如下图中的 id、name。

如果没有id、name属性的化,可以通过xpath匹配WebElement对象进行定位。

正确定位代码:

    def auto_login(self):
        # 获取浏览器窗口对象
        driver = webdriver.Chrome()
        # 打开浏览器进入指定地址
        driver.get('https://ycjq.95358.com/research')

        # selenium进行元素定位、填写内容
        driver.find_element_by_name("CyLoginForm[username]").send_keys("你的账号")
        driver.find_element_by_name("CyLoginForm[pwd]").send_keys("你的密码")

        # 这里图像识别获取验证码  def valideCode():
        # driver.find_element_by_name("valideCode").send_keys("")

        # selenium进行元素定位、模拟点击(登陆)
        time.sleep(10)
        driver.find_element_by_id("btnSubmit").click()
        time.sleep(10)
        # 切换iframe
        driver.switch_to.frame('research')
        driver.find_element_by_id('notebook_list_info').click()

执行代码之后即可正确模拟点击”上传“按钮。

 

参考:https://blog.csdn.net/huilan_same/article/details/52200586 

 

posted @ 2018-11-17 16:40  ZhuGaochao  阅读(6203)  评论(0编辑  收藏  举报