Selenium

lesson_1——Selenium简介

一、Web测试的侧重点

1、模拟整个客户端给服务端发送请求

测试对象:仅仅是服务端

场景:性能测试,使用jmeter或Loadrunner等压力测试工具

2、模拟人操作浏览器,通过浏览器来发送请求给服务器

测试对象:整个web应用,包括前端和后端

场景:UI自动化,使用QTP或者selenium

使用selenium这个工具模拟的就是第二种情况:模拟整个客户端

二、Selenium包含哪些组件 Selenium1:seleniumRC(相当于代理服务器),seleniumCore(控制浏览器行为的JS代码)

Selenium2:整合了seleniumRC,用WebDriver来替代了他的功能

Selenium3:升级了webdriver的实现,调用方式和2相同,因此对于开发者来说是无感的

最新Selenium版本的核心是WebDriver

我们的课程以selenium3为基础,所以需要重点了解掌握WebDriver

三、认识HTML

WebUI自动化的操作对象是浏览器中的网页

构成网页的基本元素就是HTML,所以需要了解HTML的知识

自学网址:http://www.w3school.com.cn/html/index.asp

首先要学习什么是HTML标签,属性

1、HTML标签

HTML 标记标签通常被称为 HTML 标签 (HTML tag)。

· HTML 标签是由尖括号包围的关键词,比如 <html>

· HTML 标签通常是成对出现的,比如 <b> 和 </b>

· 标签对中的第一个标签是开始标签,第二个标签是结束标签

· 开始和结束标签也被称为开放标签闭合标签

2、HTML 属性

HTML 标签可以拥有属性,属性提供了有关 HTML 元素的更多的信息,属性总是以名称/值对的形式出现,比如:name="value",属性总是在 HTML 元素的开始标签中规定。

四、Webdriver的工作原理

Webdriver直接驱动浏览器来模拟一些人的操作,如点击按钮,输入字符串等。而我们的测试代码是通过发送命令给webdriver完成这些操作,

虽然不同的浏览器有不同的驱动,但是我们调用的代码API都是一样的

原理参考图:

image.png

六、通过webdriver自动化操作浏览器

1、安装selenium API库:pip install selenium

2、下载对应浏览器驱动

以谷歌浏览器为例:

chrome浏览器的web driver(chromedriver.exe),可以在以下网址访问:

https://sites.google.com/a/chromium.org/chromedriver/

不过,最终的下载链接如下, 可以直接访问

https://chromedriver.storage.googleapis.com/index.html

注意点: 不同的浏览器对于不同的webdriver,同一浏览器的不同版本同样与webdriver版本一一对应,一般越新的驱动,对应新的浏览器版本。

对应关系在驱动说明网页有,比如最新的2.33版本, 打开下面的链接

https://sites.google.com/a/chromium.org/chromedriver/downloads

image.png

就说明了要使用的chrome浏览器版本是 60 到 62.

我们通常使用最新的版本的驱动,对象的都是比较新的浏览器版本,新的chrome浏览器,可以到百度搜索下载谷歌浏览器

上面的google域名的网址需要 翻墙才能访问!!!

翻墙有困难的同学看下面:

Chromedriver国内下载地址:

http://npm.taobao.org/mirrors/chromedriver/

注意版本对应关系:

http://blog.csdn.net/huilan_same/article/details/51896672

3、代码实例

下载好了驱动,安装好selenium库之后即可写代码了。

以课堂代码为例:

import time 
webdriver  from selenium import webdriver 
# 指定是chrome 的驱动,驱动路径要写全
driver = webdriver.Chrome(r"d:\tools\webdrivers\chromedriver.exe") 
#设置隐士等待目的是为了找元素的时候动态等待页面加载,参数是最大等待时间,单位为秒  
# 隐式等待  
driver.implicitly_wait(10) 
# get 方法 打开指定网址  
driver.get('http://www.baidu.com') 
# 根据ID查找元素的方法
element_keyword = driver.find_element_by_id("kw") 
# 输入字符  
element_keyword.send_keys('松勤') 
# 找到搜索按钮  
element_search_button = driver.find_element_by_id("su") 
# 点击该元素  
element_search_button.click()
#查看搜索结果  
res_ele=driver.find_element_by_id(**'1'**) 
print(res_ele.text) 
# print(type(res_ele.text))  
if (res_ele.text.startswith(**'****松勤网** **-** **松勤软件测试****-****软件测试在线教育领跑者****'**)): 
  print('pass') 
else: 
  print('fail')
 # 最后,driver.quit让浏览器和驱动进程一起退出。不然会有好几个实例一起运行  
driver.quit()

lesson_2——选择web元素的方法

一、****通过id选择元素

写法1:element = driver.find_element_by_id("kw")

写法2:from selenium.webdriver.common.by import By

element = driver.find_element(by=By.ID, value="kw")

Tips: by=By.ID表示以id的方式定位web元素,下面的例子有类似的写法以此类推

注意动态id不能用

前面我们找排行榜歌曲的时候,寻找ID是找的这个蓝框中的,为什么不找红框子中的呢?

比我们上面的 div 更贴近我们要找的table元素, 而且它也有id啊。?

image.png

很多前端开发框架会自动生成一些元素,有动态生成的id 会变,这个是会变的id要注意,不能用来选择,怎么识别是动态的呢? 名字往往是一串随机字符,而不会变的id值通常名字是有意义的单词。

二、通过name选择元素

写法1:cheese = driver.find_element_by_name("cheese")

写法2:from selenium.webdriver.common.by import By

cheese = driver.find_element(By.NAME, "cheese")

三、通过class选择元素

写法1:cheeses = driver.find_elements_by_class_name("cheese")

Tips:注意,这里返回的是一个包含web元素的列表,下同

写法2:from selenium.webdriver.common.by import By

cheeses = driver.find_elements(By.CLASS_NAME, "cheese")

四、通过tag选择元素

写法1:

如果iframe这个tag在本html中是唯一的,可以根据iframe这个tag名来找到该元素

frame = driver.find_element_by_tag_name("iframe")

写法2:from selenium.webdriver.common.by import By

frame = driver.find_element(By.TAG_NAME, "iframe")

五、通过超链接文本选择元素

写法1:ele = driver.find_element_by_link_text("转到百度")

写法2:from selenium.webdriver.common.by import By

ele = driver.find_element(By.LINK_TEXT, "转到百度")

六、title属性

注意,通过title标签名获取title元素,打印的文本值为空:

ele2=driver.find_element_by_tag_name('title')

print(ele2.text)

我们先debug看获取到的元素属性

image.png

为什么会造成这种结果?首先和我们获取元素的方式没有任何关系

text显示的应该是网页中可见的内容。title不在网页中,所以显示不出来。

Title是一个特殊的元素,标签内的文本表示页面的标题,

<pre style="background:white">可以通过driver.title属性获取页面标题</pre>

lesson_3——获取元素信息

拿到webelement对象,我们可以对它做一些操作,比如获取元素内部信息,这个时候操作主体由webdriver变成了webelement,调用的是webelement对象的方法

一、获取元素文本---text

使用WebElement的 text属性

ele = driver.find_element_by_id("food")

print(ele.text)

二、获取元素属性值---get_attribute()方法

例1、下面的代码就是获取href属性的值

ele = driver.find_element_by_id("baidulink") print(ele.get_attribute('href'))

获取到以后,就可以判断链接是否与预期相同

例2、一个元素的 style属性,比如需要判断颜色是否是红色。

ele = driver.find_element_by_id("food") print ele.get_attribute('style')

三、获取元素对应的HTML片段---get_attribute()方法

那么怎么获取整个HTML呢?还是通过get_attribute方法,

第一种:整个web元素的HTML片段

只需要参数指定为outerHTML就可以了

ele.get_attribute('outerHTML')

第二种:web元素内部子元素HTML片段

只需要参数指定为'innerHTML'就可以了

ele.get_attribute('innerHTML')

获取的HTML片段可以用来做什么?
lesson_4——Beautifulsoup用法

Beautifulsoup简称BS 是可以从HTML或XML 中提取数据的第三方库

有的时候,感觉用Selenium获取某些元素数据不太方便,可以将其父节点的html 获取回来,得到一个hmtl片段,然后利用BS在本地做分析

BS用途:解析HTML文本,操作对象是字符串,与浏览器无关

beatufulsoup 不能驱动网页,只能获取信息

一、使用Beautifulsoup分析HTML文本

安装:pip install beautifulsoup4 -i https://pypi.douban.com/simple/

pip install html5lib

安装html5lib库,因为bs里面缺省的库对html的兼容性不够,这个库对html的兼容性基本和浏览器差不多。

首先BS操作对象是字符串,假设我要对某个HTML文本做分析,那么就要将文本的字符串读取出来

# 获取html内容字符串,进行分析with open('bs1.html',encoding='utf8') as f: html_doc = f.read()

# 导入 BeautifulSoup库,html5lib不用导入,BS会自动引用from bs4 import BeautifulSoup

# 获取一个bs对象,接下来的操作都通过这个bs对象来实现

# 指定用html5lib来解析html文档soup = BeautifulSoup(html_doc, "html5lib")

二、根据签名称获取元素信息

soup.p、soup.title、soup.div

三、获取标签文本内容

soup.title.string:获取该元素本身包含的文本内容

soup.p.get_text():获取该元素下所有子元素(如果有)的文本内容,包含自身的文本内容

# 两者的区别是???

参考https://www.crummy.com/software/BeautifulSoup/bs4/doc.zh/#string

https://www.crummy.com/software/BeautifulSoup/bs4/doc.zh/#get-text# string 获取的是该元素本身直接包含的文字内容

如果一个元素有几个子节点,

如果我们想获取包含在子节点里面的内容通常就会有问题

比如第一个div元素print(soup.div.string)

# 但是get_text()却可以print(soup.div.get_text())

空白行也被认为是一个节点,返回结果连空白行也包含在内了

四、获取元素父节点

soup.title.parent:获取父节点

soup.p.parent.name:获取父节点标签名

五、获取元素属性值

中括号内的是元素的属性

print(soup.div['id'])

print(soup.p['style']) # 等价于print(soup.p.get('style'))

六、多元查找法

结合元素属性来查找元素

# selenium 里面可以根据id属性查找a元素, bs 也可以,比如根据idprint(soup.find('a', id="link3"))

#根据其他html属性,比如 href查找 a元素print(soup.find('a', href="http://example.com/lacie"))

七、官方文档

https://www.crummy.com/software/BeautifulSoup/bs4/doc.zh/

八、作业

https://github.com/jcyrss/songqin-testdev/blob/master/selenium/task/02.md

lesson_5——等待元素出现

一、隐式等待

用WebDriver 对象的implicitly_wait()方法。 这个方法有一个参数,指明等待最长时间。

driver.implicitly_wait(5):当使用了隐士等待执行测试的时候,如果 WebDriver没有找到元素,将继续等待,超出设定时间后则抛出找不到元素的异常。

换句话说,当查找元素或元素并没有立即出现的时候,隐式等待将等待一段时间5s再查找,默认的时间是0 ,一旦设置了隐式等待,则它存在整个 WebDriver 对象实例的声明周期中,隐式的等到会让一个正常响应的应用的测试变慢,它将会在寻找每个元素的时候都进行等待,这样会增加整个测试执行的时间。

二、显式等待

Selenium里面还有一种称之为显式等待的, 可以为一个操作专门指定等待时间

from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By
ele = WebDriverWait(driver, 60).until(EC.presence_of_element_located((By.ID,'1')))

比较长,我们可以顺着读一遍,很像自然语言,大家不用强记,需要使用的时候,直接拷贝,修改红色部分就可以了。

lesson_6——Frame切换

一、frame介绍

例子:

网页中包含网页:http://music.163.com/#/discover/toplist?id=60198

iframe 就是一个特殊的html 元素, 它在原来的html 范围内,开辟了一个新的HTML。

如果一个html文档结构比作一个国家的话, iframe就像在一个国家里面建立一个附属国家。里面是一个全新的html文档,就像国中之国

W3C对frame的介绍

Iframe:http://www.w3school.com.cn/tags/tag_iframe.asp

frameset::http://www.w3school.com.cn/tags/tag_frameset.asp

两者的区别是:

iframe 用于在网页内显示网页;

和frameset不同的是,frameset内置好几个子html,而iframe 只内置一个子html

二、webdriver切换frame的方法

driver.switch_to.frame(frame_reference)

这个 frame_reference 可以是

l frame 元素的 name 属性值或者ID属性值: contentFrame(浏览器里面看一下)

l 索引值(从0开始):0 可能有人问,我咋知道索引?谁先出现就是第一个

l frame 所对应的WebElement :driver.find_element_by_tag_name("iframe")

建议优先使用第一种,如果frame元素没有 name 属性,就用下面的两种方法。

比如元素有ID,就可以根据 find_element_by_id 找到webelement对象,然后就是第三种了。

从里面的frame切换回主HTML:driver.switch_to.default_content()

嵌套frame中如何逐层切换

一层一层的切换:driver.switch_to.frame('layer2') driver.switch_to.frame('layer3')

返回上一层frame:driver.switch_to.parent_frame()

lesson_7——CSS选择器

一、css选择器是什么

css 选择器是浏览器用来选择元素的,我们selenium也要选择元素,也可以使用css 的选择器语法来选择 web 元素。 而且这种方法效率还非常的高。

二、CSS选择器基本用法

1、根据 tag 名字选择

p {color: red;}

表示选择所有的 p 元素,使其颜色变为红色,运行一下都变成红色了

如果改为 p {color: blue;} ,运行一下

2、根据 id值 选择,修改一下

food {color: blue;} 表示选择ID为 food的元素,使其颜色变为蓝色

如果改为 #food2 {color: blue;} ,运行一下

3、根据class 选择

<pre style="margin-right:10.5pt;text-indent:21.0pt;mso-char-indent-count:2.0;
background:ghostwhite">.special {color: red;} 表示选择class值为为 special的元素,使其颜色变为红色</pre>

有的元素有两个class 值, <span class="vegetable good">黄瓜</span> .good {color: red;}

.vegetable {color: blue;} 表示选择所有的 class为 vegetable 的元素 ,

注意

<span class="vegetable good">黄瓜</span>

表示这个元素有两个class 值,而不是一个 vegetable good 整体的属性

.vegetable.good

当然也可以组合写 span.vegetable {color: blue;}

这样p.vegetable 就不会被选中

<p class="vegetable">青菜</p>

以上介绍的只是css选择器的冰山一角,更多内容移步到w3c有更多资料,后续课程中也会陆续讲到css的高级使用技巧

三、使用css方法选择元素

eles = driver.find_elements_by_css_selector('#choose_car option')

四、CSS后代选择器

语法如下:s1 s2

表示选择s1 元素里面所有的s2元素,s2可以是S1的直接子节点,也可以不是,

其中s1 s2可以是我们前面学过的css 根据tag名、id 、class 描述的任何语法

比如:#choose_car option

就是选择 id为 choosecar 的元素的内部的标签为option 的子元素,到底是不是直接子元素不重要,只要是属于choose_car 的内部的option元素就可以了。

五、CSS子元素选择器

1、使用场景

不同于后代选择器,只选择同一父元素的直接子元素

后代元素:所有具有相同祖先的元素(包括子元素)

子元素:所有具有相同parent的元素(范围小于后代元素)

2、表示方法

s1 > s2 s1与s2是父子关系

示例:#choose_car >option

表示选择id=choose_car下面的所有option子元素

扩展:连续使用

many>div>p.special 元素之间不存在越级

与后代选择器组合使用

many p>span #many和p 之间存在越级

3、训练

lesson04/s1.html

http://www.w3school.com.cn/tiy/t.asp?f=csse_selector_child

或者使用51job,网易云音乐的页面训练元素定位

六、相邻兄弟元素选择器

1、使用场景

同一父元素的相邻子元素,两者挨在一起

2、表示方法

s1 + s2 s1与s2是同级关系并且紧靠一起,且s2紧接在s1后面

示例:#food + div

3、扩展

many p.special + p

匹配到一个结果:紧靠#many p.special元素的P元素

4、训练

lesson04/s1.html

http://www.w3school.com.cn/tiy/t.asp?f=csse_selector_adjacent_sibling_2

或者使用51job,网易云音乐的页面训练元素定位

七、非相邻兄弟元素选择器

1、使用场景

同一父元素的子元素,元素之间无需紧靠在一起

2、表示方法

s1 ~ s2 s1与s2是同级关系,无需紧靠一起

示例:#food ~ div

3、扩展

many p.special ~ p

匹配到多个结果:与#many p.special元素同级的p元素

4、训练

lesson04/s1.html

http://www.w3school.com.cn/tiy/t.asp?f=csse_selector_adjacent_sibling_2

或者使用51job,网易云音乐的页面训练元素定位

八、属性选择器(重要)

1、使用场景

选择具有某个属性(值)的元素

2、表示方法

*[属性=”属性值”] *表示任意元素标签名,如p, div,li,button,等等

通常属性值没有空格或特殊字符,可以不加引号

示例:

*[style] #具有style属性的任意元素

p[spec=len2] #具有属性spec,且spec=len2的p元素

p[spec='len2 len3'] #属性spec='len2 len3'的p元素,len2 len3之间存在空格所以加引号

3、扩展

p[spec*='len2'] #属性spec包含len2的p元素

p[spec^='len2'] #属性spec以len2开头的p

p[spec$='len2'] #属性spec以len2结尾的p

p[class=special][name=p1] #属性class=special并且属性name=p1的p

与后代选择器结合 #many p[name=p1]

与兄弟选择器结合 #food>span+p[class=vegetable]

4、训练

lesson04/s1.html

http://www.w3school.com.cn/tiy/t.asp?f=csse_selector_attribute_value_3

或者使用51job,网易云音乐的页面训练元素定位

九、组选择器

1、使用场景

当一组选择器无法选择我们需要的元素,可以通过多组选择器来选择元素

2、表示方法

s1 , s2 s1与s2表示两组不同的css选择器

示例:

div,span,p 同时选择所有div,span,p元素

3、扩展

food > span ,p

表示选择 id为food的的所有span子元素 和 所有的p元素

food > span, #food > p

表示选择 id为food的所有span子元素 和 所有 id为food的p子元素

4、训练

lesson04/s1.html

http://www.w3school.com.cn/tiy/t.asp?f=csse_grouping

或者使用51job,网易云音乐的页面训练元素定位

九、伪类nth-child(n),nth-of-type(n)

1、使用场景

根据下标选择子元素,下标从1开始

2、表示方法

s1:nth-child(n)

选择其父元素下的第n个元素,且第n个元素为s1

s1:nth-of-type(n)

选择其父元素下的第n次出现的s1元素,对s1元素的位置没有要求

备注:s1表示一组选择器

示例:

p:nth-child(3)

选择其父元素下的第三个元素,元素类型必须是P

p:nth-of-type(3)

选择其父元素下的第三个p类型的元素,对于p元素位置没有要求

3、扩展

food > span:nth-child(2)

选择#food元素下第二个元素,该元素必须是span类型

food > p:nth-of-type(2)

选择#food元素下第二个p元素

4、训练

lesson04/s1.html

http://www.w3school.com.cn/tiy/t.asp?f=css_sel_nth-child

或者使用51job,网易云音乐的页面训练元素定位
lesson_8——编辑框操作

一、编辑框操作

1、清空输入框:input_ele.clear()

2、获取输入框已经输入的文本:input_ele.get_attribute('value')

Tips:input_ele是<input>对应的webelement对象

3、训练

lesson04/input1.html

或者使用51job,网易云音乐的页面训练编辑框操作

二、单选框操作

1、什么是单选框?

对应的HTML:

<input type="radio" name="gender" value="male"> 男

<input type="radio" name="gender" value="female"> 女

2、单选框有什么特点?

只能单选,不管原来该元素是否选中,直接去点击该元素即可,都可以确保该单选框被选中

3、如何操作?

只需调用click() 点击即可!

4、训练

lesson04/rb.html

或者使用51job,网易云音乐的页面训练单选框操作

三、勾选框操作

1、什么是勾选框?

对应的HTML:

<input type="checkbox" name="vehicle" value="bike" > 我有一辆自行车<input type="checkbox" name="vehicle" value="car" checked> 我有一辆汽车

2、勾选框有什么特点?

可以多选,点击被选中的元素则会取消选中状态,反之亦然

3、如何操作?

通过 is_selected() 查看元素是否处于选中状态

调用click() 进行选择

4、训练

lesson04/cb.html

或者使用51job,网易云音乐的页面训练勾选框操作

四、复选框操作

1、什么是复选框?

有两种,第一种是可以选择多个元素的多选下拉框

对应的HTML:

<select multiple>
<option value="benz">奔驰S300</option>
<option value="accord">雅阁</option>
</select>

第二种,只能选择一个元素的单选下拉框

对应的HTML:

<select>
<option value="male">男</option>
<option value="female" selected="selected">女</option>
</select>

2、都有什么特点?

相同:都是下拉框类型的元素

不同:第一种可以通过 ctrl + 点击选择多个元素

第二种只能选择一个元素,且必须选择一个元素

3、如何操作?

将元素用select类包装一下

模拟选择(两种下拉框都通用):调用select_by_visible_text(),参数是option元素的文本值

取消选择(仅限第一种选择框):deselect_by_visible_text()

取消所有选择(仅限第一种选择框):deselect_all()

4、训练

lesson04/ms.html

或者使用51job,网易云音乐的页面训练复选框操作

lesson_9——Xpath选择器

一、用途:

不仅可以用来在HTML文档中选择节点,还可以在XML文档中选择节点(手机自动化中会用到)

二、特点

语法非常像Linux系统中的路径,所以又叫做路径表达式

三、语法结构

1、绝对路径表示法

从根节点(html)开始,路径分割符是/(斜杠,类似于linux中路径分割符)

如:/html/body/div/span

表示对应路径下的span元素

2、相对路径表示法

以//开头后面加元素名称, 用法类似于css中的后代选择器,可以把//对应css中空格

如://span 表示html文档下所有的span元素

如://div//span 表示方法类似于CSS中的 div span

3、绝对路径与先对路径混合使用

如: //div/p/span p和span的位置确定的,分别属于div元素的子元素与孙元素

**四、通配符 ***

与css中一致,星号(*),表示匹配所有元素

用法://div/* 表示匹配div下面所有元素,等价于css中的 div>*

五、属性选择器

1、使用场景

选择具有某个属性(值)的元素

2、表示方法

//*[@属性] 表示选择具有某个属性的元素

//*[@属性=”属性值“]

表示选择具有某个属性值的元素,属性值必须加引号(单引号双引号都可以)

示例://*[@style] 选择所有具有style属性的元素

//p[@spec='len2'] 选择所有具有spec属性 值为 len2 的p元素

Tips:在xpath中没有表示id和class的特殊方法,id 、class 也是属性

如://div[@id="food"]

//div[@class="cheese"]

根据部分属性选择元素的方法有:

//*[contains(@属性,”value“)] 表示属性包含value

//*[starts-with(@属性,”value“)] 表示属性以value开头

六、子元素选择-单选

1、使用场景

选择属于其父元素的第n个某个类型的子元素

2、表示方法

//[n] 表示选择的父元素下面第n个*类型元素,

等价于 :nth-of-type(n)或//[position()=n]

示例://p[2] 选择p的父元素下的第2个p元素,等价于 p:nth-of-type(2)

七、倒数下标表示方法

1、使用场景:

选择属于其父元素的倒数第n个某个类型的子元素

2、表示方法:

//[last()-n] 表示选择的父元素下面倒数第n+1个*类型元素

等价于 :nth-last-of-type(n)或//[position()=last()-n]

3、示例:

//span[last()-1] 属于其父元素的倒数第二个span,等价于 span:nth-last-of-type(1)

//*[@id="food"]/span[last()] #food元素下倒数第1个span元素

//*[last()-1] 父元素下的倒数第二个元素(不限定类型)

八、子元素选择-多选

1、使用场景

选择属于其父元素的第m到n之间某个类型的子元素

2、表示方法

//[position()>1] 选择属于其父元素的第一个以后的元素

//[position()<last()-1] 选择属于其父元素的倒数第二之前的元素

示例:

//[@id="food"]/[position() > last()-3] 选择#food下倒数第四个到最后一个元素

九、组选择

1、使用场景

用于多组xpath表达式组合来选择元素的情况

2、表示方法

s1 | s2 s1和s2 是两组xpath选择器

示例:

//p | //button 选择所有的p元素, button元素,等价于 p, button

//p | //span | //div 选择所有的p元素, span元素和div元素,等价于 p, span,div

Tips: css和xpath的表达式不能混用

十、相邻兄弟选择

1、使用场景

根据同级元素选择其他的同级元素

2、表示方法

///following-sibling:: 选择*后面的兄弟元素 等价于 ~

///preceding-sibling:: 选择*前面的兄弟元素

示例:

//*[@id='food']/span/following-sibling::p 选择span元素后面的兄弟元素p

//*[@id='food']/p/preceding-sibling::span 选择p元素前面的兄弟元素span

3、扩展

//*[@id='food']/span/following-sibling::p[1] span元素后面的第一个兄弟元素p

//*[@id='food']/span/following-sibling::p[last()] span元素后面的最远一个兄弟元素P

//*[@id='food']/span/following-sibling::p[position()>1] span元素后面的第2到最后一个

兄弟元素p

//*[@id='food']/p/preceding-sibling::span[1] p元素前面的第一个兄弟元素span

//*[@id='food']/p/preceding-sibling::span[last()] p元素前面的最远的一个兄弟元素span

//*[@id='food']/p/preceding-sibling::span[position()>1] p元素前面的第2个到最前面的 一个兄弟元素span

十一、父元素选择

1、使用场景

根据子元素定位父元素

2、表示方法

///.. 选择的父元素,类似于linux中表示上层路径的方法

示例:

//p[@class="special"]/.. 选择//p[@class="special"]的父元素

//p[@class="special"]/../.. 选择//p[@class="special"]的父元素的父元素
lesson_10——webdriver属性及方法

一、获取当前窗口title

driver.title

二、获取当前窗口地址栏url

driver.current_url

窗口内容标题更新时,title和current_url也会随之而更新

页面更新时,可以通过查找更新页面的元素来判断页面加载完成,此时获取的title或url为新页面的title或url

三、截屏

截取整个页面:driver.get_screenshot_as_file(img_path)

截取单个元素:web_element.screenshot(img_path)

img_path是截屏图片保存路径,类型str

四、切换窗口

driver.switch_to.window(handle) 切换窗口

driver.window_handles 获取当前浏览器所有窗口的handle

driver.current_window_handle 保留当前窗口handle

driver.close() 用于关闭当前窗口

循环切换窗口,通过判断标题的方法来确定当前窗口是否为目标窗口

五、对话框处理

driver.switch_to.alert()

| |

点击ok

|

获取文本

|

点击cancel

|

输入内容

|
|

alert

|

accept()

|

text

|

N/A

|

N/A

|
|

confirm

|

accept()

|

text

|

dismiss()

|

N/A

|
|

prompt

|

accept()

|

text

|

dismiss()

|

send_keys()

|

注意浏览器alter和普通html弹出框的区别

六、上传文件

直接发送键盘消息给当前应用程序,

前提是浏览器必须是当前应用

此方法只在windows环境有用

pip install pypiwin32

import win32com.client

获取shell对象

shell = win32com.client.Dispatch("WScript.Shell")

有的系统要加 '\r'

有的系统要加 '\r\n'

使用shell对象的Sendkeys方法给应用程序发送字符串

shell.Sendkeys(r"d:\button.png" + '\n') # 回车符模拟确定键

可能响应慢,输入字符和按确定键可以分开发送,中间暂停一下

shell.Sendkeys(r"d:\button.png" )

time.sleep(2)

shell.Sendkeys("\n" )

输入法记得调成英文的,默认中文会导致某些字符输入不进去

注意:这个方法是发送字符串到你当前的焦点程序,所以自动化时不要做其他操作

七、刷新页面,前进,后退

driver.refresh()

driver.forward()

driver.back()

八、冻结窗口

setTimeout(function(){debugger},3000)

冻结当前窗口,有些隐藏窗口会自动消失,不好定位元素

lesson_11——浏览器获取CSS和Xpath

-- chrome 的 copy selector 和 copy xpath

我们在选择元素时,前面学过了两样大利器:用css 和xpath 进行选择

打开 百度 https://www.baidu.com/

如果我们要选择这个

image.png

image.png
  • 分别用 css和xpath

s_kw_wrap > span

//*[@id='s_kw_wrap']/span


有的同学可能看了网上的一些文章,发现可以通过浏览器开发工具帮助我们定位。在chrome浏览器里,按F12,打开开发工具窗口,点击element标签,然后在网页窗口里面点选我们要选择的元素,开发工具窗口会高亮显示该元素对应的html tag 代码。

这时,我们可以用鼠标右键点击该代码,在弹出的对话框中,依次选择 Copy -> Copy selector,如下图所示这样,该元素的CSS selector就被拷贝到剪贴板了


image.png

-- 同样可以选择xpath,操作一下


这种方法优先根据id,或者上层节点的id来定位的。

可以帮我们省一些时间,但,不是包治百病的。

它动不动就会使用很长的路径,比如

image.png

拷贝一下看看,发现是

s_xmancard_news > div > div.s-news-rank-wrapper.s-news-special-rank-wrapper > div > div > a

这样明显不合理,路径太长,很容易出现问题,其实只需根据 href 定位即可,因为它是唯一的
lesson_12——异常处理

我们经常会异常出错,这时候,由于不能执行到driver.quit,需要手动关闭浏览器。

其实还需要关闭chromedriver进程,否则进程不会自动退出,打开进程管理器看看

实际项目中,自动化case很多,失败也不少,这样会导致大量的 chromedriver进程。

多处进程没有退出导致内存占用,机器会变卡,建议写在try 里面,finall 后面需要driver.quit() , 不然会有很多的 chromedriver进程。

lesson_13——模拟鼠标悬停

通过 ActionChains 类模拟,ActionChains 类里面提供了一些特殊的动作,比如移动鼠标到某个元素,就是其中之一

ActionChains 类:action 动作,Chains 是链的意思,顾名思义就是支持一系列的

连续动作

acInstance = ActionChains(driver)

acInstance.action1().action2().actionN().perform()

acInstance 是ActionChains 类实例化对象,初始化参数就是 WebDriver对象,action1..n 是 一个个的动作,比如点击、输入字符、按下鼠标拖动等

注意,要以 .perform() 结尾

acInstance .move_to_element(ele)

参数是webelement对象,表示你要移动到这个元素对象上

演示代码段:

from selenium.webdriver.common.action_chains import ActionChains

ac = ActionChains(driver)

# 演示的时候,单步调试, 停在这里,再单步,可以看到效果 ac.move_to_element(driver.find_element_by_id('zxnav_1')).perform()ele= driver.find_element_by_css_selector('#zxnav_1 > div.category-panels >ul >li >a')

lesson_14——改变窗口大小

get_window_size() 获取当前窗口大小

set_window_size(800,600) 修改当前窗口大小,参数传递宽度和高度,单位是像素

比如,改变窗口宽度:

size = driver.get_window_size()

driver.set_window_size(1100,size['height'])

lesson_15——滚动屏幕

如果窗口太长,改变窗口大小都不够,因为屏幕只有那么大,需要滚动到元素的方案 ,可以使用最后一招,直接让浏览器执行javascript脚本,浏览器执行的语言是js, 如果我们能直接传入js让浏览器执行,就得到了最大的灵活性去控制浏览器,可以算是终极武器。

比如滚动屏幕,就可以使用 js语言window.scrollBy(250,0) 就是横向滚动250个像素,

让浏览器去执行selenium里面实用js代码。

window.scrollBy(x,y) 向右、向下滚动x,y为正,向左、向上滚动x,y为负

driver.execute_script('window.scrollBy(200,0)')

lesson_16——二次渲染

案例:

登录教管系统,http://localhost/mgr/login/login.html

实现一下添加2门课程,再删除2门课程都能正确显示

from selenium import webdriver import time driver = webdriver.Chrome()
driver.implicitly_wait(5)
driver.get('http://localhost/mgr/login/login.html')

driver.find_element_by_id('username').send_keys('auto')
driver.find_element_by_id('password').send_keys('sdfsdfsdf')
driver.find_element_by_tag_name('button').click()

def addCourse(driver,name,desc,idx): driver.find_element_by_css_selector("a[ui-sref='course']").click()
time.sleep(1)
driver.find_element_by_css_selector('button[ng-click^=showAddOne]').click()
ele = driver.find_element_by_css_selector("input[ng-model='addData.name']")
ele.clear()
ele.send_keys(name)

ele = driver.find_element_by_css_selector("textarea[ng-model='addData.desc']")
ele.clear()
ele.send_keys(desc)

ele = driver.find_element_by_css_selector("input[ng-model='addData.display_idx']")
ele.clear()
ele.send_keys(idx)

driver.find_element_by_css_selector('button[ng-click^=addOne]').click()

def DeleteAllTeacher(driver): delButtons = driver.find_elements_by_css_selector('[ng-click^=delOne]') for button in delButtons:* button.click()
driver.find_element_by_css_selector('.modal-footer .btn-primary').click() addCourse(driver,'数学','数学',1)

addCourse(driver,'语文','语文',2)

time.sleep(1) DeleteAllTeacher(driver) input('press any key to quit......')
driver.quit()

结果运行发现:selenium.common.exceptions.StaleElementReferenceException: Message: stale element reference: element is not attached to the page document

原来是现在的web应用和以前大不相同,以前的web应用大都是后端直接产生最终的html界面,而现在呢?很多是页面加载后(也加载javascript前端代码),由前端代码动态改变界面的内容,比如从后端获取一些数据后,再动态改变界面的内容。

尤其是很多采用了框架像 angular,react,vue这些都会这样做,这样就有一个问题,开始的时候获取的html只是一个模板一样的文档,里面的数据没有产生,而是需要等前端js代码动态的再次向后端查询数据后,才动态的向html模板中填入数据或者修改数据。


原因是:一下子获取了多个删除按钮元素,然后用循环点击每个删除按钮,但是当点击第一个按钮之后,页面有些部分被更新了,剩余的几个按钮,虽然看起来还是原来的样子,但是已经是新的界面元素了。

所以,你通过原来老的界面元素点击 ,就会出现这个错误。

那么怎么解决这个问题呢?

既然点击第一个课程的删除按钮后,页面部分被更新了,就只好重新获取界面元素。

def DeleteAllCourse(driver): driver.implicitly_wait(2) while 1: delButtons = driver.find_elements_by_css_selector('[ng-click^=delOne]') if len(delButtons) < 1: break delButtons[0].click()
driver.find_element_by_css_selector(
'.modal-footer .btn-primary').click() time.sleep(1*)

lesson_17——半自动化的用途

selenium 属于图形界面自动化的测试,图形界面自动化的难度是比较大的。

模拟难:

有些特殊的输入,比如12306 点击图片的某个部分

打开 https://kyfw.12306.cn/otn/login/init

检查难:

打开 https://www.vmall.com/

比如检查菜单有没有,我们经常是检查某些输出的字符,应该还有:界面的整体是否布局有错乱,图片显示logo是否正确

为什么会有这些难度,因为界面操作者是人 ,有很多操作需要人的智能,才方便输入,检查输出。

解决方式:比如难自动化的操作包括模拟输入,检查输入等,可以都提示(beep)让人去做。

打开浏览器代码 #系统提示,手动输入验证码 import time import winsound

winsound.Beep(1500,30000) #系统发出警报声 time.sleep(10) #暂停一会让用户手动输入 #自动化代码

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容