zoukankan      html  css  js  c++  java
  • 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 

  • 相关阅读:
    信息系统项目管理师2009年上午试题分析与解答
    信息系统项目管理师2005年上半年试题
    信息系统项目管理师2008年下半年试题
    信息系统项目管理师历年上午试题答案及试题和大纲
    信息系统项目管理师2008年上半年试题
    信息系统项目管理师2005年下半年试题
    信息系统项目管理师2006年下半年试题
    一个经典的问题(构造函数调用+抽象类+间接继承抽象类)
    重载构造函数+复用构造函数+原始构造与This引用的区别(一步步案例分析)
    GetType()与Typeof()的区别 举了2个案例
  • 原文地址:https://www.cnblogs.com/bigtreei/p/9974581.html
Copyright © 2011-2022 走看看