元素定位和定位辅助工具

2020-12-02 15:52:00 浏览数 (1)

Web页面组成-代码

代码语言:javascript复制
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>python_web页面_20200226</title>
</head>
<body>
<input type="text" readonly placeholder="请输入你的名字"></input>
喜欢的歌手:
<input type="checkbox">萧亚轩</input_type>
<input type="checkbox" checked>邓丽君</input_type>
<input type="checkbox">毛不易</input_type>
<input type="checkbox">霉霉</input_type>
<input type="checkbox">李健</input_type>

<br>

性别:
<input  type="radio" name="sex" >男
<input  type="radio" name="sex" >女
<input  type="radio" name="sex" checked>未知

<br>
上传文件:
<input  type="file">

<br>

<input type="button" value="hello html" disabled>
<button>点我就有惊喜</button>

<br>
<!--链接--->
<a href="http://map.baidu.com">地图</a>

<br>
<img src="//www.baidu.com/img/bd_logo1.png" height="129" width="270">

<br>
年龄:<select>
    <option>20岁以下</option>
    <option>20-25岁</option>
    <option>25-30岁</option>
    <option>30岁以上</option>

</select>


<br>
<form>
    <input type="text">
    <table border="2">
        <tr>
            <td>11<td>
            <td>22</td>
            <td>33</td>
        </tr>
        <tr>
            <td>11<td>
            <td>22</td>
            <td>33</td>
        </tr>
        <tr>
            <td>11<td>
            <td>22</td>
            <td>33</td>
        </tr>
        <tr>
            <td>11<td>
            <td>22</td>
            <td>33</td>
        </tr>
    </table>
</form>

<iframe src="http://www.baidu.com">
</iframe>

<textarea></textarea>

<h1 id="title">大家好!!!</h1>
<h2>大家好!!!</h2>
<h3>大家好!!!</h3>
<h4>大家好!!!</h4>
<h5>大家好!!!</h5>
<h6>大家好!!!</h6>

<script >
    //function aaa(){
       // var a=[1,2,3,4,555];
       // alert(a[1]);
    //}
    //aaa()
  //  window.onload=function(){
    //    alert("everything is ready")
  //  };
#选择console中这段代码,鼠标从左往右选中变蓝色后,复制过来
    a=document.getElementById("title");
    a.onmouseover=function(){
    a.style.color="red";
};
a.onmouseout=function(){
    a.style.color="green";
};



</script>
</body>
</html>

Web页面-简单元素定位和定位辅助工具

学习目的:DOM对象 webdriver背后运行的原理。

Web自动化是通过驱动程序模拟自己是页面点点点。

1.如何打开一个浏览器?

selenium里面有很多东西,第一个就是webdriver,web自动化中主流用的东西,它可以支持非常多的语言。它有个录制工具是selenium ide,短期内一周内有个效果可以用录制,录制是非常简单的。但是正经做项目的时候,是从来不用selenium ide的。

自己设计自动化框架,自己写webdriver相关的事情。调用它实现比较长远的自动化框架。不需要花时间了解selenium ide,知道有这个录制的东西就可以了。

selenium grid,如果有ie,火狐,谷歌三大浏览器,想让三大浏览器同时执行我的代码。在不同的机器上执行,做这种分布式的模式,可以用这种selenium grid。

selenium grid要做webdriver能做出来的基础上再去做分布式执行才有意义。

2.webdriver是怎么工作的?

环境安装的时候,每个浏览器都有自己的驱动,如果现在想启动一个浏览器,要在代码中选择对应的浏览器模块来启动。

3.有ie,火狐,谷歌,怎么启动其中一个呢?

不但驱动实现了与浏览器的一一对应,代码层面也实现了与浏览器的一一对应。浏览器之间有些设置上的差异。

driver=webdriver.Chrome()

这段代码是怎么和驱动程序通信的呢?

有python,java,ruby,c#版本的webdriver。都是第三方库,都需要和chrome driver驱动程序进行通信。是通过http进行通信。

selenium webdriver库,chrome driver,谁是客户端谁是服务端?

http通信是一个客户端去连接一个服务端,向服务端发送各种请求,等待服务端的响应。作为服务端要随时准备好接收客户端的请求。

4.看chrome driver的源码解析:

selenium webdriver库向chrome driver这个驱动程序去进行http请求,将chrome driver启动起来。

chrome driver是服务端。 service代表chrome driver这个服务。

默认启动的是个什么都没有的浏览器,希望在启动的时候带一些数据,保持一些什么样的配置等等。可以配置options和chrome options这两个选项。这两个选项可以暂时不用考虑。

在参数准备好后,第一件事就是启动服务端,根据端口号和Ip地址启动chrome driver。保证服务端在线,才可以发送请求。

第二进行连接。

第三发送请求。

和服务器连接之后,我让你做什么事,那么就是我们间定义好的一套协议。

代码和chrome driver之间通信的协议。

什么样的请求代表访问网址,什么样的请求代表点击操作,什么样的请求代表输入操作。

这套标准通用于APP测试。

web自动化和selenium webdriver用的是http请求,http协议。

访问个网址,点击个元素,相当于都是在发送一条http请求。

就像做接口测试一样,发送一个http请求,等待它给我的响应结果。然后对响应结果字段进行解析,成功就成功,没成功就抛出异常。

5.浏览器的操作:

获取浏览器的属性:

窗口,网页地址,窗口的id。

能操作窗口之后,就把目标瞄准页面。

1.元素查找。2.元素操作。

webdriver只能操作网页。windows浏览器自带的设置,webdriver是不能直接去操作这些东西的,这属于一个窗口控件,不是html页面。

webdriver只能操作html页面,超出范围不行!

ChromeOption可以用变相的方式加载windows浏览器自带的这些数据,但是在页面上不能看到操作效果。

6.代码如下:

代码语言:javascript复制
from selenium import webdriver

#将它实例化之后得到一个实例化对象,运行代码打开谷歌浏览器
# driver=webdriver.Chrome()
'''
此处有个坑:
python selenium自动化测试~打开浏览器报TypeError: 'module' object is not callable
原因是Chrome的首字母没有大写,写成了chrome
'''
#打开的谷歌浏览器是一个全新的浏览器,没有任何的用户数据,就像网站中第一次下载下来安装后,第一次使用是一样的。

#启动谷歌浏览器,开启与浏览器之间的会话。
driver=webdriver.Chrome(service_log_path="D://chromedriver_service.log")

#访问网页
driver.get("http://www.baidu.com")#写全网址的路径。
#windows10里面没有chromedriver进程,windows7可能会看到好几个chromedriver进程,这样会导致串门,
# 界面卡住不动

#窗口最大化
driver.maximize_window()

#访问
driver.get("http://www.taobao.com")

#回退上一页
driver.back()

#回到下一页(前进的意思)
driver.forward()

#刷新
driver.refresh()

#属性
#获取标题
print(driver.title)
'''
如果是页面点击打开,它会自动打开,但是想额外再打开一个,就要用js去执行。
'''

#获取网址
print(driver.current_url)


#窗口的句柄(就是窗口的id)
print(driver.current_window_handle)


#关闭当前的窗口,没有杀进程也没有退出浏览器进程。
# driver.close()

#代码执行完毕后,杀进程,清理一些配置数据,彻底结束会话。
# driver.quit()

复杂元素定位

元素定位的各种方式

class="index-logo-src"

html页面中的元素允许设置多个class的。样式叠加起来的时候,可以设置多个class值。

如果想用find_elements_by_class_name()或者find_element_by_class_name()的时候,只能选三个其中的一个class值,否则会报错。

elements中的对象是所有符合这个条件的元素。web element对象,根据下标选择对应的值去操作就好了。

1.与DOM对象对应的四种方式:

代码语言:javascript复制
#方式一
ele=driver.find_element_by_id("kw")
# find_element_by_id返回的是个web element对象。
print(ele)
print(ele.get_attribute("class"))

# 方式二 class
eles=driver.find_elements_by_class_name("s_ipt")
driver.find_element_by_class_name()#在html页面,从上往下,找到第一个符合class值的元素。

#方式三 name
driver.find_element_by_class_name("wd")
driver.find_elements_by_name("wd")

#方式四 tagname
driver.find_element_by_tag_name("input")
driver.find_elements_by_tag_name("input")

其实也有find_elements_by_id(),但是id只有一个,所以基本上不用这个。

针对链接这样的元素,前面四种都适用,selenium webdriver额外多提供了两种。

driver.find_element_by_link_text("更多产品")不一定我找的链接只有一个,可能有多个一样的链接,所以这样的方式一样可以找到多个元素。

driver.find_element_by_partial_link_text("产品")#部分匹配

2.怎么确定在这个html页面中有这样一个name属性,class属性,标签名,其它元素都没有呢?

需要掌握xpath表达式或者css表达式。

以上六种方式,仅仅针对某一个属性。

有些情况下,光靠属性,根本就找不到它。因为开发人员开发出来的都不一样。

xpath和css是万能定位方式,支持多种定位方式的组合。

不一定只通过标签名,可多种条件组合筛选。

项目做自动化的时候,尽量做到唯一定位,而不是在一堆元素中选一个。

xpath和css让各种使用进行唯一定位的。

driver.find_element_by_xpath("xpath表达式")

3.xpath表达式分为两种。

相对定位

绝对定位:以/开头,非常依赖页面的顺序和位置。父/子

绝对路径:从顶层目录开始,一层一层,所有经历的层级全部都要列出来。绝对定位也是一样的。

/html/head/script[1]

1代表第一个元素。

是从1开始的。

如果鼠标放上去了,页面没有任何地方与它对应,可能这个元素是隐藏的,没有显示出来,也许是不是我要的元素。

右键拷贝path,是绝对定位,只要稍微改动下,马上就不行了。如果开发人员添加了元素,那么马上就会失效了。

系统也不是一层不变的,测试人员在上面测试,会新增修改删除数据,删除新增会导致页面结构发生变化。

如果项目比较大,元素定位比较多,有好几百个的时候,就要哭了。

写自动化用例要的是长期的效果,需要回归用例的,这个东西需要运行半年以上,一年,两年,三年的。正常做项目里面不会用绝对定位。

都会采用相对定位。

框架是可以永久应用的,但是元素定位这个东西是和测试和系统相关的。所以想办法改的越少越好。

4.相对定位为什么比绝对定位好用呢?

相对定位中也是有个参照物的。相对于某个路径,对于整个html页面而言,它的相对定位就是相对根目录。

相对定位:以//开头不依赖页面的顺序和位置。只看整个页面中有没有符合表达式的元素。

不管是谁的后代,不管是爷爷还是爷爷的爷爷,只看整个html页面有没有。

既然没有顺序也没有位置,只要页面没有太大的变化,都可以定位到,而且不需要长期改。

写xpath表达式,要检测表达式到底能不能定位到元素。希望它实时检测我的表达式能否真的定位到这个元素。

在Elements工具中,大家可以用一个底部弹出这个东西:

辅助我元素定位的。

5.要检测相对定位怎么做呢?

相对定位是//开头,这是标准,这是语法分隔。

以//开头,第一件事是要找下有没有这个元素。

//后面首先跟的就是元素的标签名也就是元素类型。

先把范围锁定起来,所有的属性依赖于元素本身。首先确定下,这个类型的元素,页面到底有几个。

//input

find Element by xpath 默认找到的就是第一个元素。

例如:

1 of 37表示一共有37个,当前是第一个。

要的不是当前第一个这种感觉,要的是完全绝对定位。

6.想绝对定位到它,一共只找到一个元素怎么办?

通过类型筛选已经不能够唯一锁定它,在这37个input当中再通过一些其它的特征,再将这个范围缩小到一个。

如果属性是变动的就不要选,选不变动的属性。

//标签名称[@属性名="属性值"]

注意:属性值要拷贝,不要自己输入。有的时候看着没有区别,但是就是有区别的。这样一放,元素定位不到,就有点悲剧了。

提示1 of 1

这样比绝对定位方式简单太多了。

这是最最基本的一种相对定位表达式。

这样比右键拷贝的好太多了。开发要是想新增元素,没关系的,只要我这个元素本身没有变,其它的页面爱怎么变怎么变,没关系。它比绝对定位方式稳定性高很多,这个维护的成本会降低很多。

但是不代表相对定位就永远都不要改,如果页面发生了大的变化,那么还是需要改的。

7.假设这个地方的name属性不能唯一定位到它,input中有两个元素的属性都叫做userName,那该怎么办?

逻辑运算符:and or

想组合下条件,两个属性值都必须满足。

//标签名称[@属性名="属性值"空格and空格@属性名="属性值"]

根据实际需要,可以继续and。

//标签名称[@属性名="属性值"空格and或者or空格@属性名="属性值"]

套路:先看有没有,再看下有多少个,万一有多的,就通过元素本身的属性一步一步的缩小范围。

定位的时候是会有元素出来,但是首先确定是不是我要找的元素。如果不是,那就再换。

在一个html页面中,如果两个元素一模一样,通过自己的本身没办法定位到自己,就可以想点别的方法。

通过自己的各种属性都没有办法确保我是绝对唯一的,那么就这样,如果在一个家族中某一个兄弟姐妹非常优秀,或者上级(爸爸或者爷爷)某一代中非常的优秀。

首先把范围缩小到爸爸那辈或者爷爷那辈,在爷爷的子孙后代中找你就很简单了。

元素定位是逐步缩小范围的。

比如选择一个标签名是首先缩小元素的类型,再去通过属性再去缩小一个范围。

层级定位,通过优秀的上级上上级来找到。虽然两个元素是一模一样,但是它们的父辈不一样,可以现根据爸爸来找。

找到一个元素,要在它的后代找,可能是直系后代,也有可能是子孙当中。

在xpath表达式中什么代表直系后代,什么代表可以在子孙当中找,用/表达,/前后是父子关系。

//标签名称[@属性名="属性值"]/儿子

虽然儿子辈有兄弟姐妹10个,每个人都有个name,但是它们的name都不一样。

8.为什么//也行?

//div[@id="u1"]//a[@name="tj_login"]

a[@name="tj_login"]这个元素的相对参照物是它爸啊。也就是//div[@id="u1"]

//div[@id="u1"]是顶层节点,以它为基准。

以//开头,后面的范围逐步缩小的时候,用//或者/都是可以的。

9.代码如下

代码语言:javascript复制
#元素定位
#id、 classname、tagname(标签名)、

from selenium import webdriver
#启动谷歌浏览器,开启与浏览器之间的会话。
driver=webdriver.Chrome(service_log_path="D://chromedriver_service.log")

#访问网页
driver.get("http://www.baidu.com")#写全网址的路径。

#方式一
ele=driver.find_element_by_id("kw")
# find_element_by_id返回的是个web element对象。
print(ele)
print(ele.get_attribute("class"))

# 方式二 class
eles=driver.find_elements_by_class_name("s_ipt")
driver.find_element_by_class_name()#在html页面,从上往下,找到第一个符合class值的元素。

#方式三 name
driver.find_element_by_class_name("wd")
driver.find_elements_by_name("wd")

#方式四 tagname
driver.find_element_by_tag_name("input")
driver.find_elements_by_tag_name("input")

#方式五、六 针对链接
# 如果是图片的链接,第五第六种用不了。如果是纯文字的链接,可以通过文本内容来匹配。
# 通过文字匹配有两种,完全匹配,部分匹配。
driver.find_element_by_link_text("更多产品")#全部匹配
driver.find_element_by_partial_link_text("产品")#部分匹配

#xpath
driver.find_element_by_xpath("")
# 绝对定位 以/开头,非常依赖页面的顺序和位置。父/子
#相对定位 以//开头  不依赖页面的顺序和位置。只看整个页面中有没有符合表达式的元素。
#//标签名称[@属性名="属性值"]
# 逻辑运算符 and or    //标签名称[@属性名="属性值"空格and空格@属性名="属性值"]
# 层级定位,通过优秀的上级上上级来找到。
#text()     文本定位。
#contains(@属性名称/text(),全部文本内容或者部分文本内容)  包含


#css

web页面-复杂元素定位

xpath相对定位方式,除了我们讲的这几个之外呢,光靠这几个做个项目的话,其实还是有难度的。

因为现在的开发人员没有后面要做自动化这种意识,也没有在做的时候考虑后面做自动化要怎么做。

在公司发现元素定位特别复杂的时候,可以找开发同事吃个饭(请他吃个饭)好好聊下,让他帮你加点什么。帮你加个id,方便你做元素定位。如果一个系统中很多元素都有唯一的id的话,这样做起来非常快。

实际上,目前在做很多系统的时候你会发现,光有这些定位方式没有办法定位到所有元素。开发也是很忙的,也不搭理你。

1.xpath元素定位方式有更多的选择。还有些定位方式是通过函数的方式实现的:

text()是通过文本内容来定位。

div可以换成**代表匹配所有元素。

//*[@id="u1"]

无论页面是任何一个元素,只要id="u1"就可以。

第一种方式:

//*[@id="u1"]//a[text()="地图"]

用相对定位避免用下标作为位置,除非实在没办法,都不要用它。

第二种方式:

//a[text()="学术"]

自己靠得住的时候就不用靠关系了。

在相对定位中,可以用各种,看个人习惯,没有绝对的定位方式,没有绝对唯一的一种方式,可以有多种,但是有一些更好。

第一种方式更好,找id更快更准确一些,更稳定更快捷,不会因为时间的问题出啥幺蛾子。

有的时候光有text()定位也不能解决相关的问题。

contains(@属性/text(),value)

contains有两个参数,可以是部分文本内容匹配,也可以是部分属性匹配。

2.id的部分匹配:

可变的id: 实际做项目的时候可能遇到这样一个情况,一个元素的id由两部分组成,id的值有一部分是固定的,后面是随机数或者别的东西变化的。那这个固定的是它的一个特征,跟你元素本身作用含义相关的。

这种情况下,能不能只考虑id只包含了前面固定的部分,如果能够找到我就可以用它。

如果属性中有部分是固定不变的,有特别意义的,那就可以用它。

3.通过部分class值来匹配:

每个元素都有class,style这两个属性,一般可以看到一个元素有4-5个class值,style更长。style中有个属性叫做visibility,代表它的可见性。

如果想通过style中部分样式匹配来找元素,用contains也是可以的。

//input[contains(@class,"pass-text-input-password")]

//input[contains(@class,"pass-text-input-pass")]

像在字符串中查找内容,class值也是字符串,所以写不全也是可以的。

但是一般的做法不会取class的一部分,会取某一个完整的class值。

有目前的这些方式也不一定够用,有的时候定位不了一些特别复杂的元素,还有更多的用法。

4.轴定位:分析页面中元素之间的关系。

当每一个元素的定位表达式都是一样的,通过元素自己是定位不了,通过它的祖先定位也不行,祖先都一样,那么该怎么办呢?那就另辟门路。

我想通过我的兄弟姐妹或者后代或者先辈们来定位它,比如我和你之间没有直接关系,但是我可以通过之间的关联人来找到你。

这个是某种意义上的层级定位,只不过这种定位很复杂。

就像抢头标按钮怎么定位都是只有3个,可以通过标的名称找到抢头标。把标的名称作为一个变量。

5.轴定位包含这些东西:

百度上肯定不止这几种,但是可以分析下,其它多余的可以用别的方式来表达,没有必要去整它的复杂模式。

标红是使用率比较高的,未来使用比较靠谱的。

前面英文名字是它的轴名称,后面是对它的关系的介绍。

preceding sibling:当前元素节点标签之前的所有兄弟结点。

html页面中有同一个父亲的子级都叫做亲生兄弟姐妹。兄弟姐妹之间分先后顺序也就是html页面中的先后顺序。

following sibling:当前元素节点标签之后的所有兄弟结点。

following:是没有兄弟姐妹关系的,也没有所谓的家族关系。只要在我后面出现的,都算是我后面的,无论是谁家的孩子。

preceding:只要你比我先出生,无论你是谁家的,那都是在我前面的。

followingpreceding其实是没有太大意义的,所以也不怎么用。

使用轴定位必须使用/后面再加轴定位,这样定位更加精准,不能使用//,使用//会扩大范围。

/轴名称::节点名称

6.什么是轴名称?

就是preceding sibling,ancestor,parent等这些。

7.什么是节点名称?

假如爸爸是div,爷爷是a,爷爷的爷爷是from,没有说爸爸爷爷和爷爷的爷爷都是同一个元素同一个类型。都是随机的。

如果自己是个div,我的兄弟姐妹不一定就是div,有可能是a,也有可能是img等。

8.加节点名称,方便在祖先兄弟姐妹中选一个符合你要求,比如我的兄弟姐妹中有两个div,怎么知道是哪个呢?

/轴名称::节点名称[@属性="值"]

所有的定位方式全部都可以在[]里面用,用前面的套路可以进一步的限定范围。

首先分析python10专用和抢投标之间的关系。

只能通过标名来定位它,标名根据用例的名称来传递。

如果它们有个祖先是兄弟关系,可通过这一层来关联。

方式一:

根据兄弟的后代有没有a,决定选哪个。这种情况下就是使用轴运算的方式。

文本当然是会变得,可以将它作为变量。可以在元素定位中设置一个变量,没有问题的。

实际做项目得时候,不会通过标名来选。这里只是个例子,没有路可选得时候,可以选这条路。

实际工作中,元素定位可能比这个还要长,更加复杂,主要是根据系统来决定。

但是这种套路下,需要分析页面布局和它们之间得关系。自己写元素定位得时候,需要开动脑筋,想想哪种方式是最好的。

以上元素定位方式能够定位到99%。

有些情况下比较特殊,不稳定的情况下用js,js是妥妥的最稳定的方式。js可以帮助你做元素定位,元素操作。

例如定位表格类型的数据,在某一个列表展示结果当中,表格中的列名是固定的。如果要定位某一行的数据,要获取某一行某一列的元素,那只能通过列名关系找到它对应的位置的值。这个在表格定位中应用的比较广泛,其它场景用的不多。

表格用的上是因为表格有一样的呀。

这些是xpath所有定位方式,绝对定位,相对定位,以及这些条件全部组合起来用,基本上可以解决99%以上元素定位。

实在不行还可以找到一系列元素再选下标。

这个系统设计的时候规定了首页显示的时候只显示3个标。 如果只要第二个抢头标按钮。

方式二:

find_elements()

找到符合条件的三个元素,然后通过它的返回列表当中,选第二个值,点击

find_elements()也是按照先后顺序往里面放的,先找到的元素是第一个,后找到的元素是第二个,再找到的元素是第三个,一直往后放,它也是根据页面顺序来查找的。 所以,通过find_elements()找到元素后,通过下标去选就行了。

第三种定位方式:

根据某一个条件定位另外一个元素,就用到轴定位,例如看名字对应的学号。 表格性质的全部都可以用到轴定位。

/是绝对定位的一种,少用/,实在没有选择的情况下用下标。

元素操作

不会单独介绍selenium webdriver的api,跟它的应用场景组合起来。

第一个,等待操作。

无论将来做app测试还是web自动化测试,必不可少的一部分叫做等待。

在web自动化中的三个切换操作。

第一,为什么web自动化当中要做等待?

因为代码执行的速度是非常快的,发送命令出去后,selenium chromedriver给我们回复消息的过程中,也许页面渲染还没有成功,渲染是需要时间的。

你要操作元素,它可能还没有出现,于是会遇到很多初学者都会遇到的问题“noSuchElement",这个问题引起的原因比较多,第一点就是没有等待元素出现,当然不仅仅是这个原因,很有可能是定位表达式在运行的过程中和你之前定位的时候是不一样的,元素有了变化。

所以第一是元素定位的问题,第二就是等待的问题,第三个就是切换的问题,它是在另外一个html页面中。

基于各种各样的原因,必须要用到等待,web自动化中有3种等待方式,这3种等待方式,app通用。

1.强制等待。 不常用。

sleep(秒)

用来辅助第二种和第三种方式。

凡是你的操作引起了页面的变化,你再要去操作的时候就一定要等待。

2.隐性等待。 不常用。

适用条件是查找元素和等待命令的执行完成。

implicitly_wait(秒)

如果单位是30秒,不会傻等30秒,如果你在30秒内找到了一个元素,比如第15秒找到了,那么后面15秒就不再等了,在找到的时候就马上去执行下一步,所以是种智能等待方式。

只要在这个时间上限之内,这个元素出现了,什么时候出现就什么时候不再等待。如果超过30秒还没有出现,就会抛出异常“TimeoutExceiption”,提示等待超时了,元素至今还没有出现。但是它是整个会话周期有效的。

3.什么是整个会话周期?是什么和什么的会话?

打开浏览器到关闭浏览器。

driver.implicitly_wait(30)

这个期间只需要调用driver.implicitly_wait(30)执行一次,在后续的过程中所有调用driver.findElement(),都适用于这条原则用来等待元素出现。

默认情况下是不等待的,如果在执行这个代码的时候发现这个元素根本没有出现,它不会立马报错,它会主动调用driver.implicitly_wait(30)这个隐性等待,在30秒之内只要出现了都是可以的,30秒之内都不会给你报错,不需要你刻意去调用,只需要在会话中设置一次就够了,可在会话启动开始就设置下。

全局等待:

但是这个等待是有限定场景的。例如切换窗口的时候能不能等待新的窗口的出现,处理alert弹框的时候,能不能等待alert弹框的出现。

这种智能等待方式并不能解决所有的问题,有的情况下是不生效的。

4.必须掌握"显性等待"

WebDriverWait(driver,等待时长,轮循周期).until()/until_not()

明确提出到底要等什么,这个就叫做显性,非常明显的条件。

明确等到某个条件满足后,再去执行下一步。

第一部分是等待,第二部分是条件。

等待:

由两个东西来完成,第一个是WebDriverWait类,它是个显性等待类,这个类中处理的事有什么呢?

WebDriverWait类初始化的条件:

driver: 第一个是会话对象,就是说它要知道在哪个会话基础上去等待什么样的条件完成,知道是在哪个页面。

等待时长: 也就是最多等多少秒,例如等20秒,20秒以内,啥时候出现都不成问题。

轮循周期: 是多久去看一次,比如轮循周期是1秒钟,就是每一秒去看下这个条件是否成立。

如果它每隔多少秒去看了下,最终在你等待的时限之内,还没有找到一样的,会报TimeoutException。

条件:

until()

until是直到某某某条件成立,条件写在()里面的。

直到什么条件成立,等到这个条件成立,until_not()就是等到这个条件不成立,直到找不到某个元素为止,直到页面没有哪个元素。

条件由谁来表达?

expected_conditions是一个模块文件,在它的模块里面有很多个类。这些类,一个类就是一个条件,有非常多的方法。

最最常用的是元素存在和元素可见。

5.使用之前引入相关的库

代码语言:javascript复制
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By

web自动化有8种定位方式在By这个类中,详情可以看源码。

6.使用方法

先确定元素的定位表达式。

也就是你希望在什么情况下等待。

一般是什么情况下等待的呢?

比如找元素的时候,等待它出现,保险手段是写个等待,如果不写等待,也不一定真的不出现,只是概率性的问题。

自动化代码运行3遍可能没有问题,但是运行5遍呢,其中有1遍是报错的,告诉你元素找不到,所以每次在使用元素之前,去等一等,这是个非常稳定和保守的用法。

不需要每一步都去等,什么情况下等呢?

点击操作导致页面发生变化,想在新出来的元素上面去操作,需要等到这个元素出现。

因为不知道页面会给我响应多久,不知道等多久才可以看到这个元素,然后去操作它,所以要等到这个元素出现。

设置时长:智能等待,设置等待时间不要太苛刻,比如被测系统,平时测试的时候应该是5秒左右基本上所有页面都能响应,但是做自动化测试最重要是追求脚本运行的稳定性,可以适当延长到7秒8秒,不要刚好卡在这个线上,有可能出现7秒8秒的现象。

轮循周期:WebDriverWait源码中解释了有个默认值,默认值是0.5秒。每0.5秒看下条件是否成立,所以使用默认值,第三个参数可以不用设置了。

条件是等到这个元素出现,直到条件成立为止。

建议安装selenium webdriver的时候提供的-u方法,用-u将新的代码升级进来了。

光看TANGRAM__PSP_10__footerULoginBtn,你不知道它是id,classname,还是name还是其它的什么东西。

光看TANGRAM__PSP_10__footerULoginBtn,你不知道它是什么类型的,所以在传参的时候一定是定位类型和定位表达式都传进来。

如果要定位类型和定位表达式两个数据,它只有一个参数,就用元组来表达,用这个类的时候就必须传一个元组性质的参数进来,实例化的同时传进来,(元素的定位类型,元素的定位表达式)

实例化就是EC.visibility_of_element_located()

定位类型就在By里面选就可以了。

id="TANGRAM__PSP_10__footerULoginBtn"WebDriverWait(driver,10).until(EC.visibility_of_element_located((By.ID,id)))

7.代码

代码语言:javascript复制
from selenium import webdriver

from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
#web自动化有8种定位方式在By这个类中,详情可以看源码。


#启动谷歌浏览器,开启与浏览器之间的会话。
driver=webdriver.Chrome(service_log_path="D://chromedriver_service.log")

# 全局等待--隐性等待
# driver.implicitly_wait(30)

#访问网页
driver.get("http://www.baidu.com")#写全网址的路径。
driver.find_element_by_xpath('//*[@id="u1"]//a[@name="tj_login"]').click()
# 这种情况下需要等待新的弹框出现,然后点击其中的用户名密码方式。

id="TANGRAM__PSP_10__footerULoginBtn"
WebDriverWait(driver,10).until(EC.visibility_of_element_located((By.ID,id)))

#点击   用户名密码方式。
# driver.find_element_by_id("TANGRAM__PSP_10__footerULoginBtn").click()

所以它是由两部分组成的,一部分表达条件,一部分表达等待。

EC.presence_of_element_located

页面存在这个元素:能找到这个元素就可以了,不需要可见,是否隐藏都无所谓,只要能找到就可以了。

只要在html页面中写出来的,都可以找到。

这3种方式并不冲突,可以3种同时用,也可以选择其中一种用,还可以选择3种中的两种,看情况用。

一般做项目用显性等待是最多的,但是有的时候页面千奇百怪,用显性等待明明通过了,但是你想做更多操作的时候,它会提示这个元素找不到。

这种情况下,你会感觉很懵,明明等待了,为什么说找不到呢?

如果遇到这种非常奇怪的现象,去组合下sleep(秒),sleep(秒)在自动化代码中使用频率不是太低。但是主要目的是协助显性等待,尽量提高运行的稳定性。

sleep(秒)的时间一般也就1秒2秒左右,不会是5秒7秒,这种用法是很浪费时间的。在显性等待后,用sleep1秒或者0.5秒,0.2秒,或者2秒来辅助一下就可以了。sleep(秒)仅仅是个辅助功能。

写多了sleep会影响效率嘛?

不会。sleep()不要等太长时间,0.5秒,1秒,2秒钟影响不大。需要的地方才用。

在你没法处理的时候用sleep(),能处理的时候就不用sleep(),如果页面中太多了,当然还是会影响执行速度的。


0 人点赞