美文网首页
3、Selenium:无法定位元素的几种解决方案

3、Selenium:无法定位元素的几种解决方案

作者: 小啊小狼 | 来源:发表于2020-09-24 11:08 被阅读0次

    在做web应用的自动化测试时,定位元素是必不可少的,这个过程经常会碰到定位不到元素的情况(报selenium.common.exceptions.NoSuchElementException),一般可以从以下几个方面着手解决:

    1、定位表达式错误或者定位到多个

    试了好几种定位方式了,怎么看这个元素就是这个属性,没错啊!这应该是我们最常遇到了情况。这个时候怎么办呢?很简单。检验你的定位方式到底有没有找到元素
    1、打开chrom浏览器
    2、F12打开调试模式
    3、选择元素右键检查
    4、按住ctrl+F键,调试框下方出现一个输入框


    image.png

    5、输入自己的元素定位表达式


    image.png
    • 黄色加亮为定位到的元素,2的标识处为定位到的元素个数,如果有唯一元素,说明定位表达式正确

    • 如果有多个元素,需要优化定位表达式直至唯一或用下标精准定位到你要找的元素。
      也可以把定位到的多个元素属性及下标打印出来,对应你要定位到的原元素


      image.png
    • 如果没有定位到元素,说明元素表达式错误

    2、Frame/Iframe原因定位不到元素:

    这个是最常见的原因,首先要理解下frame的实质,frame中实际上是嵌入了另一个页面,而webdriver每次只能在一个页面识别,因此需要先定位到相应的frame,对那个页面里的元素进行定位。
    解决方案:
    如果iframe有name或id的话,直接使用switch_to_frame("name值")或switch_to_frame("id值")。如下:

    #切换至id或者name为xf的iframe页面
    driver.switch_to.frame('xf')
    

    如果没有可用的id和name属性,可以先定位到frame/iframe,再将定位对象传给switch_to.frame(对象)方法。如下:

    #先定位到iframe
    xf = driver.find_element_by_xpath('//*[@class="if"]')
    #再将定位对象传给switch_to.frame()方法
    driver.switch_to.frame(xf)
    

    如果完成操作后,可以通过switch_to.parent_content()方法跳出当前iframe,或者还可以通过switch_to.default_content()方法跳回最外层的页面。

    3.页面还没有加载出来,就对页面上的元素进行的操作:

    这种情况一般说来,可以设置等待,等待页面或者元素加载完毕后再进行操作
    可用的有三种等待方式:

    • WebDriverWait() 显性等待
    • driver.implicitly_wait(秒) 全局隐式等待
    • sleep(秒) 线程等待,休眠固定的时间

    具体用法参看另外一篇文章 Selenium:3种等待方式

    4、页面元素失去焦点导致脚本运行不稳定

    解决方法:driver.switch_to.active_element 遇到脚本不稳定,有时会失去焦点导致测试失败的情况下,可以先切到焦点元素再进行操作。注意.active_element后面不带括号()。

    driver.find_element_by_class_name('fnew').click()
    time.sleep(2)
    driver.switch_to.active_element.send_keys('filename')
    

    5、元素被遮挡,不可用,不可见

    5.1窗口最大化

    driver.maximize_window() 由于窗口大小改变引起的页面元素布局发生变化,被测元素被遮挡,可以先将窗口最大化,再进行元素定位。

    5.2页面有滚动条,元素需要操作滚动条后才可见

    # 滚动元素“底端”与当前窗口的“底部”对齐,ele为定位到的元素对象
    driver.execute_script("arguments[0].scrollIntoView(false);", ele)
    
    # 滚动元素“底端”与当前窗口的“顶部”对齐
    driver.execute_script("arguments[0].scrollIntoView();", ele)
    
    # 滚动到页面底部
    driver.execute_script("window.scrollTo(0,document.body.scrollHeight)")
    
    # 滚动到页面顶部
    driver.execute_script("window.scrollTo(document.body.scrollHeight,0)")
    
    # 直接点击不可见的目标元素,不再先跳转。
    self.driver.execute_script(“arguments[0].click();”, ele) 
    

    5.3不可用

    对于有些WebDriver没有提供的方法或者无法实现的功能,WebDriver提供了driver.execute_script()方法来执行JavaScript代码。
    假设一个输入框可以通过id='text'将其定位,却不能通过send_keys()输入文本内容,可以借助JavaScript代码来实现

    text = "input text"
    driver.execute_script("var obj=document.getElementById('text'); obj.value=' " + text + " ';")
    

    假如某个元素属性display:none方法是设置元素不可见(display='block'将显示元素),导致通过定位页面元素无法定位。’
    对于这种问题,可以通过JavaScript修改页面元素属性来将元素置位可见,然后通过id、classname等方法去定位,示例代码如下

    #js改变元素的display属性为'block'
    js = "document.getElementById(\"element_id\").style.display='block';"
    # 调用js脚本
    driver.execute_script(js)
    #然后再定位元素
    driver.find_element_by_id("txtPassword").send_keys("123456")
    

    当我们想在输入框 是日期类型,并send_keys 的时候发现不能输入,输入框被禁用readonly,处理方式如下

    #js改变元素的display属性为'block'
    js = 'document.getElementById(\"element_id\").removeAttribute(\"readonly\")'
    # 调用js脚本
    driver.execute_script(js)
    #然后再输入
    

    6、页面跳转到新的标签页,或者弹出的警告框等

    在页面操作过程中有时候点击某个链接会弹出新窗口,这时就需要切换焦点到新窗口上进行操作。

    窗口切换:

    driver.switch_to.window(window_handle)切换到新窗口。
    首先获取当前窗口的句柄driver.current_window_handle,接着打开弹出新窗口,获得当前打开的所有窗口的句柄driver.window_handles。通过for循环遍历handle,如果不等于第一次打开窗口的句柄,那么一定是新窗口的句柄,因为执行过程只打开了两个窗口;改变条件,如果等于第一次打开窗口的句柄,那么可以切换回第一次打开的窗口。

    from selenium import webdriver
    import time
    current_handle = driver.current_window_handle
    all_handles = driver.window_handles
    if len(all_handles)>1:
        for handle in all_handles:
            if handle != current_handle:
                driver.switch_to.window(handle)
    
    #获取到的all_handles是一个列表,也可以用下标进行切换
    driver.switch_to.windowall_handles[0])
    

    警告框:

    对于JavaScript生成的alert、confirm以及prompt,无法使用前端工具对弹出窗口进行定位的,使用driver.switch_to.alert方法定位弹出框。alert的方法有:

    alert = driver.switch_to.alert
    
    alert .accept()    '等同于点击“确认”或“OK”'
    alert .dismiss()    '等同于点击“取消”或“Cancel”'
    alert .text        '获取alert文本内容,对有信息显示的alert框'
    alert .send_keys(text)    '发送文本,对有提交需求的prompt框'
    

    相关文章

      网友评论

          本文标题:3、Selenium:无法定位元素的几种解决方案

          本文链接:https://www.haomeiwen.com/subject/erqoyktx.html