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都是一样的
原理参考图:
六、通过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
就说明了要使用的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啊。?
很多前端开发框架会自动生成一些元素,有动态生成的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看获取到的元素属性
为什么会造成这种结果?首先和我们获取元素的方式没有任何关系
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/
如果我们要选择这个
- 分别用 css和xpath
s_kw_wrap > span
//*[@id='s_kw_wrap']/span
有的同学可能看了网上的一些文章,发现可以通过浏览器开发工具帮助我们定位。在chrome浏览器里,按F12,打开开发工具窗口,点击element标签,然后在网页窗口里面点选我们要选择的元素,开发工具窗口会高亮显示该元素对应的html tag 代码。
这时,我们可以用鼠标右键点击该代码,在弹出的对话框中,依次选择 Copy -> Copy selector,如下图所示这样,该元素的CSS selector就被拷贝到剪贴板了
-- 同样可以选择xpath,操作一下
这种方法优先根据id,或者上层节点的id来定位的。
可以帮我们省一些时间,但,不是包治百病的。
它动不动就会使用很长的路径,比如
拷贝一下看看,发现是
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
检查难:
比如检查菜单有没有,我们经常是检查某些输出的字符,应该还有:界面的整体是否布局有错乱,图片显示logo是否正确
为什么会有这些难度,因为界面操作者是人 ,有很多操作需要人的智能,才方便输入,检查输出。
解决方式:比如难自动化的操作包括模拟输入,检查输入等,可以都提示(beep)让人去做。
打开浏览器代码 #系统提示,手动输入验证码 import time import winsound
winsound.Beep(1500,30000) #系统发出警报声 time.sleep(10) #暂停一会让用户手动输入 #自动化代码