(selenium学习日志一)
学习selenium,个人的感觉是主要任务在【找元素】。而对于查找页面元素,有以下几个方法:
(以上方法的具体解析,网上很多,建议查看 虫师 作品 http://www.cnblogs.com/fnng/p/3183777.html)
如果有id,自然用find_element_by_id,如果没有,建议使用find_element_by_xpath,这个可以应付页面上的所有元素。而很多时候,常常会出现 No Such Element的报错。
针对这个问题,我归纳有以下几点:
1、元素处在不同的frame、iframe;
2、元素处在不同的window窗口;
3、页面未加载成功,元素不存在;
4、(也算第三点的一部分)由于网络线路等等原因,导致与服务器中断(又或者,你的这个请求得到的结果不正确,只是服务器只以为正确了),部分元素没来得及加载。
请注意,这里我强调的是浏览器“放弃”请求。
我的解决方案如下:
1、可以使用switch_to_frame一层层迭代,再查找元素;
2、可以使用switch_to_window;
3、网上的建议有两点:第一,使用WebDriverWait智能等待,如WebDriverWait(self.driver,7000).until(EC.alert_is_present(),"Time out,alert not appear");
第二,设置页面加载等待时间,如self.driver.implicitly_wait(10);
以上两点,我建议第一点,但在我实际操作中,依然没有很智能,还是会报No Such Element的错误。因此,我建议自己写一个函数等待,用起来顺心,如下:
def WaitAndFindElement(self,by,value=0,timedeta=5,timeout=300):
element = None
endtime = timeout
while endtime > 0:
try:
element = self._driver.find_element(by, value)
except:
pass
if element:
break
else:
time.sleep(timedeta)
endtime = endtime - timedeta
return element
同时,页面加载时间是不固定的,会因为你的网络而有所变化,所以强烈建议以上方法,智能等待。
另外,有网上有不少人问:WebDriver如何判断一个页面是否加载成功?
对这个问题,我想没有现成的函数实现。有人回答,len(driver.page_source) > 200,或者查找某个元素是否存在用来判断页面是否加载成功.....
个人感觉,问这个问题的思路错了。因为,WebDriver页面测试应着眼于元素上,而不应该死死盯在页面上。所以,我们应该想的是元素是否加载成功。
4、 当你使用第三点中的方法,智能等待元素出现的时候,如果没有发现【返回结果不正确】或者【已和服务器断开】,好吧,你就傻傻地等待。我曾遇到
这种情况,此时只需要重新请求即可,即driver.refresh()。如果你有想法,可以改写第三点的方法,请不要死循环或者多次请求,服务器会骂娘的。
html dom 弹出有以下几种:
1、window.open(新页面.html) 弹出一个新的页面,不常用;
2、window.showModalDialog 弹出子窗口,有父子关系;
3、alert 、 confirm、prompt,弹出子窗口,有父子关系;
4、通过javascript控制div弹出,属于原来的页面,不存在父子关系,现在最流行的弹窗方式
第一到第三点,组合使用switch_to_window、switch_to_frame、driver.switch_to_alert().accept()都能解决问题,也没什么好说的。我想强调的是这几点的区分,
很多时候,我们一看到弹出,就立刻使用driver.switch_to_alert().accept()处理。最烦的是,程序报错了也没醒悟,一直忙着去问度娘。亲,度娘也没想到你会这样子啊。
请看,左边的是confirm弹窗,右边是div弹出,很明显嘛。如果再无法区分,可以查看html,因为第四点不存在父子关系,所以【确定】按钮可以从html中找到。
在这里插个题外话,html隐藏元素有两种:
1、display:none 相当于元素从页面中被移走,它下面所在的元素跟上填充,即消失
2、visibility=false 元素被隐藏,但位置还在
(以下方法有针对第一种实践过,第二种在理论上方法适用)
先模拟第一点:(A为隐藏元素Element)当鼠标移动元素B上时,元素A出现;等鼠标离开,元素A隐藏
解决方法:
方案一:使用ActionChains(driver).move_to_element(B) 。也许,此时你会讶异,A元素没出现。其实,A元素出现,只是在你看到她之前,她又匆匆离去。
原因在于move_to_element在执行时,鼠标在B上,执行后,鼠标已离开B。为了达到鼠标悬停的效率,可以使用如下方法:
ActionChains(driver).move_to_element(B).click_and_hold()
可没想到的是,元素B竟然是个链接,当点击后,driver发生了页面跳转,鼠标去到一个新的页面,你只有悲伤地看着她离你越来越远了。
如果你不放弃,可以考虑【循环】,即是,你尝试千万次的接触,纵使千万次都擦肩而过,只为A的一次回眸。
但这种方法成功的概率很低,且耗时多,不管你有多痴情。代码如下:
def ClickA():
try:
favs_close = fs.find_element_by_xpath('../preceding-sibling::a[@class="S_close"]') #元素B的xpath
except:
return False
return True
def MoveToAndClickA():
while True:
driver.move_to_element(B)
result = ClickA()
if result:
break
节点。js脚本中,你可以使用
var elementA= document.getElementByClassName(A) (或者使用getElementsByTagName等等)
do something at A
以上为个人经验所谈,如有错误,望各位指出