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

在做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框'
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,012评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,589评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,819评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,652评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,954评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,381评论 1 210
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,687评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,404评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,082评论 1 238
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,355评论 2 241
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,880评论 1 255
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,249评论 2 250
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,864评论 3 232
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,007评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,760评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,394评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,281评论 2 259