今天抽点时间总结下Selenium WebDriver找不到元素的情况。
当然这里说的是css或者XPath都没写错,定位准确,也并非使用了不稳定的定位语句。
情况一:(StaleElementReferenceException: Message: Element not found in the cache...)
页面刷新
原因:页面被刷新了。
在当前页面找不到这个元素了,但是你自己手动复制到页面开发者工具上查看明明有啊,为啥在代码里面就找不到了呢?这时,你还可能会问“可是明明元素就在那里,没有变,甚至我是回退回来的,页面都没有变,怎么会说是新页面?”。
其实呢是在操作的过程中页面发生了变化,刷新了,虽然表面上看起来两个元素长得一模一样,事实上是每一个元素都有自己的一个ID号。
用代码(Python)来证明!
# -*- coding: utf-8 -*-
from selenium import webdriver
driver = webdriver.Chrome()
driver.get('https://cn.bing.com/')
print(driver.find_element_by_id('sb_form_q')) # sb_form_q before refresh
driver.refresh() #刷新
#driver.back() #此处不管是刷新还是点击了其他操作又会回到这个页面都是一样的
print(driver.find_element_by_id('sb_form_q')) # sb_form_q after refresh
driver.quit()
结果如下图:很明显,element有一个对应的ID是不一样的,只能在当前页面时去使用、存取才会有效。
分析:
refresh,不论你是主动刷新还是页面自动刷新
back,已经跳转到了其他页面,然后你用driver.back()跳回来,这也是一张新的页面了
跳转到了新的页面,但这张新页面上有一些元素跟之前页面是长得一样的,这也是一张新的页面了。比如:一排分页按钮,你点击下一页跳转到了第二页,想要还用原来的元素操作到下一页,那也是不可能的了。
解决:
只要刷新页面之后重新获取元素就行,不要提前获取一组元素,然后去循环操作每一个元素,这种情况还是获取元素的个数,然后在循环中获取相应位置的元素,在用的时候才去获取,这样你就获取到最新的id了,也不会出现找错人的尴尬了。
我今天就遇到一个,其实之前也遇到了,只是没有着重记录一下而已。
有一个四个菜单,分别要去带四个传入的数据点击四次,检查是否能到另外一个页面,页面返回是否正常。
我就使用了一个循环,但是最开始没细看,直接循环成了元素,到新页面验证完成之后又返回原来的页面继续定位,发现定位不了了;这时我才想起来不应该循环元素,应该循环元素的个数,在这个循环的过程中再来定位获取元素。
情况二:iframe原因定位不到元素需要切换Iframe
【参考此文】这种情况一般发生在有内嵌的iframe的情况下,需要切换一下iframe
另外注意的是有的页面会有多个iframe,找不到元素同样是没有切换iframe,切换即可。
driver.switchTo()
driver.switchTo(iframeName)
情况三:点击速度过快,页面没有加载出来就需要点击页面上的元素。
这个需要增加一定等待时间,显示等待时间可以通过WebDriverWait 和util来实现
- 添加固定的休眠时间,引入time包
这个只能大概估算一下,给个固定值,不是很推荐使用这个,不灵活。
Python:time.sleep(10)
Java:Thread.sleep(1000);//单位是毫秒,1000毫秒=1秒
- 添加智能等待,隐式的等待一个元素被发现或一个命令完成
webdriver提供的超时等待,implicitly_wait()方法
Python:driver.implicitly_wait(20)
- 添加智能等待时间,在设置的时间内,默认每隔一段时间检测一次当前页面元素是否存在,如果超过设置时间检测不到则抛出异常。
可参考博文:Selenium使用之——添加等待时间的三种方式