简介
条件
软件需求变更不频繁(稳定)
项目周期比较长
自动化的脚本能够重复利用
自动化测试切入点
系统测试
自动化项目的实施过程
可行性分析、框架的选择(selenium、RF),需求分析、计划、测试用例设计、无人值守、提交报告、脚本维护
一、web自动化环境搭建
安装selenium
pip install selenium//安装selenium
使用selenium
from selenium import webdriver
driver = webdriver.chrome()#启动浏览器
driver.get("https://baidu.com")#控制浏览器,访问百度
driver.quit()#关闭浏览器
安装“浏览器驱动”
手动安装
查询浏览器版本
下载对应版本浏览器驱动
将浏览器驱动,放至Path路径下
【浏览器自动更新,以上操作,重新来过】
自动化安装浏览器驱动
二、对浏览器的控制
selenium通过面向对象思路,让我们完成对浏览器的控制:
属性:获取数据
方法:操作数据
常用的属性和方法:
driver.get("https://baidu.com")
driver.get_screenshot_as_file("a_百度.png")
driver.maximixze_window()
三、八大元素定位
1 面试题:如果元素定位不到,你是怎么取分析?
元素没有加载完成
Frame中
元素不可用,不可读,不可见
动态属性,动态的DIV层
前提:需要定位的元素或属性必须要唯一
selenium提供了8个定位策略:
【问题集锦】
问题1:selenium启动浏览器后会自动关闭浏览器
原因:selenium4版本自带运行程序结束后,自动清除缓存,关闭浏览器
处理方法:设置休眠时间来延缓闪退
问题2:find_element 方法抛出 selenium.common.exceptions.NoSuchElementException 异常
原因:根据 传入的ID,找不到这样的元素
问题3:find_element 和 find_elements 的区别
使用 find_elements 选择的是符合条件的 所有 元素, 如果没有符合条件的元素, 返回空列表
使用 find_element 选择的是符合条件的 第一个 元素, 如果没有符合条件的元素, 抛出 NoSuchElementException 异常在这里插入代码片
from selenium import webdriver
from selenium.webdriver.common.by import By
#打开浏览器
driver = webdriver.Chrome()#Chrome大写C
#加载网页
driver.get("https://baidu.com")
# id元素定位
driver.find_element(By.ID, "kw").send_keys("csdn")
# name元素定位
driver.find_element(By.NAME, "wd").send_keys("csdn")
# link text元素定位
driver.find_element(By.LINK_TEXT, "新闻").click()
# Partial link text元素定位(部分匹配是确保唯一性)
driver.find_element(By.PARTIAL_LINK_TEXT, "图").click()
2 ID属性定位
3 Class属性定位
通过指定 参数为 By. CLASS_NAME,选择所有的class属性的值
from selenium import webdriver
from selenium.webdriver.common.by import By
# 创建 WebDriver 实例对象,指明使用chrome浏览器驱动
wd = webdriver.Chrome()
# WebDriver 实例对象的get方法 可以让浏览器打开指定网址
wd.get('https://cdn2.byhy.net/files/selenium/sample1.html')
# 根据 class name 选择元素,返回的是 一个列表
# 里面 都是class 属性值为 animal的元素对应的 WebElement对象
elements = wd.find_elements(By.CLASS_NAME, 'animal')
# 取出列表中的每个 WebElement对象,打印出其text属性的值
# text属性就是该 WebElement对象对应的元素在网页中的文本内容
for element in elements:
print(element.text)
4 tag 名 选择元素<标签>
通过指定 参数为 By.TAG_NAME ,选择所有的tag名为 div的元素
通过标签名的定位方式,要慎用,如果能够不适用还是尽量不用,因为一个页面有大量重复的标签名,容易造成混乱,从而使Selenium无法找到正确的元素
from selenium import webdriver
from selenium.webdriver.common.by import By
wd = webdriver.Chrome()
wd.get('https://cdn2.byhy.net/files/selenium/sample1.html')
# 根据 tag name 选择元素,返回的是 一个列表
# 里面 都是 tag 名为 div 的元素对应的 WebElement对象
elements = wd.find_elements(By.TAG_NAME, 'div')
# 取出列表中的每个 WebElement对象,打印出其text属性的值
# text属性就是该 WebElement对象对应的元素在网页中的文本内容
for element in elements:
print(element.text)
5 Xpath定位
xpath 语法中,整个HTML文档根节点用’/‘表示,如果我们想选择的是根节点下面的html节点,则可以在搜索框输入
/html。
注意: / 有点像 CSS中的 > , 表示直接子节点关系。
5.1 绝对路径选择:
从根节点开始的,到某个节点,每层都依次写下来,每层之间用 / 分隔的表达式,就是某元素的 绝对路径。
/开头,如:/html/body/script[1]
自动化程序要使用Xpath来选择web元素,应该调用 WebDriver对象的方法 find_element_by_xpath 或者 find_elements_by_xpath,像这样:
elements = driver.find_elements(By.XPATH, “/html/body/div”)
5.2 相对路径选择:
xpath需要前面加 // , 表示从当前节点往下寻找所有的后代元素,不管它在什么位置。
//开头,如//input
‘//’ 符号也可以继续加在后面,比如,要选择 所有的 div 元素里面的 所有的 p 元素 ,不管div 在什么位置,也不管p元素在div下面的什么位置,则可以这样写 //div//p
要选择 所有的 div 元素里面的 直接子节点 p,xpath,就应该这样写了 //div/p
5.3 通配符
- 是一个通配符,对应任意节点名的元素
要选择所有div节点的所有直接子节点,可以使用表达式 //div/*
5.4 根据属性选择
Xpath 可以根据属性来选择元素.
根据属性来选择元素 是通过 这种格式来的 [@属性名=‘属性值’]
注意:
属性名注意前面有个@
属性值一定要用引号, 可以是单引号,也可以是双引号
根据id属性选择
选择 id 为 west 的元素,可以这样 //[@id=‘west’]
根据class属性选择
选择所有 select 元素中 class为 single_choice 的元素,可以这样 //select[@class=‘single_choice’]
根据其他属性
选择 具有multiple属性的所有页面元素 ,可以这样 //[@multiple]
属性值包含字符串【xpath 2.0 的语法 ,目前浏览器都不支持】
要选择 style属性值 包含 color 字符串的 页面元素 ,可以这样 //[contains(@style,‘color’)]
要选择 style属性值 以 color 字符串 开头 的 页面元素 ,可以这样 //[starts-with(@style,‘color’)]
要选择 style属性值 以 某个 字符串 结尾 的 页面元素 ,大家可以推测是 //[ends-with(@style,‘color’)],
5.5 按次序选择
某类型 第几个 子元素
要选择 p类型第2个的子元素,就是
//p[2]
要选取父元素为div 中的 p类型 第2个 子元素
//div/p[2]
第几个子元素
选择父元素为div的第2个子元素,不管是什么类型 //div/[2]
某类型 倒数第几个 子元素
选取p类型倒数第1个子元素
//p[last()]
选取p类型倒数第2个子元素
//p[last()-1]
选择父元素为div中p类型倒数第3个子元素
//div/p[last()-2]
范围选择:xpath还可以选择子元素的次序范围
选取option类型第1到2个子元素
//option[position()<=2]或者//option[position()❤️]
选择class属性为multi_choice的前3个子元素//[@class=‘multi_choice’]/[position()<=3]
选择class属性为multi_choice的后3个子元素
//[@class=‘multi_choice’]/[position()>=last()-2]
5.6 组选择、父节点、兄弟节点
组选择
xpath也有组选择, 是用 竖线 隔开多个表达式
比如,要选所有的option元素 和所有的 h4 元素,可以使用
//option | //h4
要选所有的 class 为 single_choice 和 class 为 multi_choice 的元素,可以使用//[@class=‘single_choice’] | //[@class=‘multi_choice’]
选择父节点【xpath可以选择父节点, 这是css做不到的】
某个元素的父节点用 /… 表示
比如,要选择 id 为 china 的节点的父节点,可以这样写 //[@id=‘china’]/…
还可以继续找上层父节点,比如 //[@id=‘china’]/…/…/…
场景:当某个元素没有特征可以直接选择,但是它有子节点有特征, 就可以采用这种方法,先选择子节点,再指定父节点。
兄弟节点选择
xpath也可以选择 后续 兄弟节点,用这样的语法 following-sibling::
比如,要选择 class 为 single_choice 的元素的所有后续兄弟节点 //[@class=‘single_choice’]/following-sibling::
要选择后续节点中的div节点, 就应该这样写 //[@class=‘single_choice’]/following-sibling::div
xpath还可以选择 前面的 兄弟节点,用这样的语法 preceding-sibling::
要选择 class 为 single_choice 的元素的 所有 前面的兄弟节点,这样写//[@class=‘single_choice’]/preceding-sibling:😗
要选择 class 为 single_choice 的元素的前面最靠近的兄弟节点 , 这样写//[@class=‘single_choice’]/preceding-sibling::[1]
要选择 class 为 single_choice 的元素的前面第2靠近的兄弟节点 , 这样写//[@class=‘single_choice’]/preceding-sibling::[2]
【其余结合场景例子】
Xpath-相对路径定位结合方式有:【前提:确定目标元素的唯一性】
相对路径+索引定位://from/span[1]/input
相对路径+属性定位://input[@属性=‘属性值’]
相对路径+通配符定位*:
//[@属性=‘属性值’]
//[@=‘属性值’]
复制xpath经常会出错,不是万能的
相对路径+部分属性值定位:
以开头://[starts-with(@属性,‘部分属性值’)]
以结尾://[substring(@属性,部分属性值长度)=‘部分属性值’]
包含://[contains(@属性,‘部分属性值’)]
相对路径+文本定位://span[text()=‘属性值’]
6 CSS Selector定位
适用场景:要选择的 元素 没有id、class 属性,或者有些我们不想选择的元素 也有相同的 id、class属性值
选择单个元素的方法:find_element(By.CSS_SELECTOR, CSS Selector参数)
选择所有元素的方法:find_elements(By.CSS_SELECTOR, CSS Selector参数)
校验css选择器的定位语法是否正确,可采用点击 Elements 标签后, 同时按 Ctrl 键 和 F 键,如下图:
绝对路径:基本不用
6.1 通过ID和class定位
'''
注明:下方find_element和find_elements取决于返回的数据是一条还是多条
'''
#根据 tag名 选择元素的 CSS Selector 语法非常简单,直接写上tag名即可
elements = wd.find_elements(By.CSS_SELECTOR, 'div')
#根据id属性 选择元素的语法是在id号前面加上一个井号: #id值
wd.find_element(By.CSS_SELECTOR, '#searchtext').send_keys("csdn")
#根据class属性 选择元素的语法是在 class 值 前面加上一个点:.class值
elements = wd.find_elements(By.CSS_SELECTOR, '.animal')
6.2 通过属性定位
通过任何属性来选择元素,语法是:[属性=‘属性值’]
通过加标签名限制,属性值选择元素,语法是:标签名[属性=‘属性值’]
from selenium import webdriver
from selenium.webdriver.common.by import By
# 打开浏览器
driver = webdriver.Chrome()
# 打开网址
driver.get("https://cdn2.byhy.net/files/selenium/sample1.html")
#选择href属性值为http://www.miitbeian.gov.cn的元素
element = driver.find_element(By.CSS_SELECTOR,'[href="http://www.miitbeian.gov.cn"]')
#选择所有标签名为a,且href属性值为http://www.miitbeian.gov.cn的元素
element = driver.find_element(By.CSS_SELECTOR,'a[href="http://www.miitbeian.gov.cn"]')
print(element.get_attribute('outerHTML') )
6.3 通过部分属性定位
选择 属性值 包含 某个字符串 的元素
方法:标签名[属性*=“字符串”]
如:a[href*=“miitbeian”]
选择 属性值 以某个字符串 开头 的元素
方法:标签名[属性^=“字符串”]
如:a[href^=“http”]
选择 属性值 以某个字符串 结尾 的元素
方法:标签名[属性
=
"
字符串
"
]
如:
a
[
h
r
e
f
="字符串"] 如:a[href
="字符串"]如:a[href=“gov.cn”]
选择的元素要 同时具有多个属性的限制
方法:标签名[属性=“字符串”][属性=“字符串”]
如:div[class=misc][ctype=gun]
6.4 选择 子元素 和 后代元素
如果 元素2 是 元素1 的 直接子元素, CSS Selector 选择子元素的语法,如:
元素1> 元素2
元素1>元素2>元素3>元素4(最终选择的元素是 元素4)
“#container > #layer1 > #inner11 >span”
如果 元素2 是 元素1 的 后代元素, CSS Selector 选择后代元素的语法:,如
元素1 元素2(中间是一个或者多个空格隔开)
元素1 元素2 元素3 元素4(最终选择的元素是 元素4)
“#container #inner11 > span”
7 Css表达式–组合使用
7.1 选择语法联合使用
#方法1:选择 一个class 属性值为 copyright 的 span 节点, 并且要求其 必须是 class 属性值为 footer1 的 div节点 的子节点
div.footer1 > span.copyright
#方法2:选择 一个class 属性值为copyright 的节点(不限类型),并且要求其必须是 class 属性值为 footer1 的节点的子节点
.footer1 > .copyright
#方法3:子元素同时也是后代元素
.footer1 .copyright
7.2 组选择
css选择器可以 使用 逗号 ,称之为 组选择
#eg1:选择所有tag名为div的元素 和 id为BYHY的元素
div,#BYHY
#eg2:选择所有 id 为 t1 里面的 span 和 p 元素
#t1 span,#t1 p
或
#t1 > span,#t1 > p
7.3 按次序选择子节点
父元素的第n个子节点
选择的元素 是父元素的第几个子节点
方法:使用 nth-child
#选择的是 第2个子元素,并且是span类型
span:nth-child(2)
#选择所有位置为第2个的所有元素,不管是什么类型
:nth-child(2)
父元素的倒数第n个子节点
选择的是父元素的 倒数第几个子节点
方法:使用 nth-last-child
#选择第倒数第1个子元素,并且是p元素
p:nth-last-child(1)
#选择第倒数第1个子元素,不管是什么类型
:nth-last-child(1)
父元素的第几个某类型的子节点
选择的元素 是父元素的第几个 某类型的 子节点
方法:使用 nth-of-type
#选择的是 第1个span类型 的子元素
span:nth-of-type(1)
父元素的倒数第几个某类型的子节点
选择父元素的 倒数第几个某类型 的子节点
方法:使用 nth-last-of-type
#选择倒数第1个p类型的子元素
p:nth-last-of-style(1)
奇数节点和偶数节点
选择的是父元素的 偶数节点,使用 nth-child(even)
选择的是父元素的 奇数节点,使用 nth-child(odd)
#选择的是父元素的 p类型偶数节点
p:nth-child(even)
#选择的是父元素的 p类型奇数节点
p:nth-child(odd)
7.4 兄弟节点选择
相邻兄弟节点选择,
表示元素 紧跟关系的 是 加号( “ + ” 号)
#选择 h3 后面紧跟着的兄弟节点 span(同一层级)
h3 + span
后续所有兄弟节点选择
方法:使用 “ ~ ” 号
#选择是 选择 h3 后面所有的兄弟节点 span
h3 ~ span
四、操控元素的基本方法
1 操控元素通常包括
1.1 点击元素
就是调用元素WebElement对象的 click方法
```python
from selenium import webdriver
from selenium.webdriver.common.by import By
# 打开浏览器
driver = webdriver.Chrome()
# 打开网址
driver.get("https://www.baidu.com")
driver.find_element(By.ID, "kw").send_keys("csdn")
driver.find_element(By.ID, "su").click()
1.2 在元素中输入字符串,通常是对输入框这样的元素
就是调用元素WebElement对象的send_keys方法
from selenium import webdriver
from selenium.webdriver.common.by import By
# 打开浏览器
driver = webdriver.Chrome()
# 打开网址
driver.get("https://cdn2.byhy.net/files/selenium/test3.html")
driver.find_element(By.ID, "input1").clear()
driver.find_element(By.ID, "input1").send_keys("白月黑羽")
1.3 获取元素包含的信息,比如文本内容,元素的属性
获取元素的文本内容:
通过WebElement对象的 text 属性,可以获取元素 展示在界面上的 文本内容
元素的文本内容没有展示在界面上,或者没有完全完全展示在界面上
可以尝试使用 element.get_attribute(‘innerText’) ,或者 element.get_attribute(‘textContent’)
获取元素属性
通过WebElement对象的 get_attribute 方法来获取元素的属性值
如:要获取元素属性class的值,就可以使用 element.get_attribute(‘class’)
获取整个元素对应的HTML
要获取整个元素对应的HTML文本内容,可以使用 element.get_attribute(‘outerHTML’)
获取某个元素 内部 的HTML文本内容,可以使用 element.get_attribute(‘innerHTML’)
获取输入框里面的文字
对于input输入框的元素,要获取里面的输入文本,用text属性是不行的,这时可以使用 element.get_attribute(‘value’)
#获取文本内容1
element = wd.find_element(By.ID, 'animal')
print(element.text)
#获取内容2
element = wd.find_element(By.ID, 'input_name')
print(element.get_attribute('class'))
五、Frame切换/窗口切换
1 切换frame
被嵌入的 html 文档 中的元素, 就必须 切换操作范围 到 被嵌入的文档中
方法:使用 WebDriver 对象的 switch_to 属性wd.switch_to.frame(frame_reference)
frame_reference 可以是 frame 元素的属性 name 或者 ID 或 所对应的 WebElement 对象
#填写 iframe元素的id ‘frame1’
wd.switch_to.frame('frame1')
#填写 name属性值 ‘innerFrame’
wd.switch_to.frame('innerFrame')
#根据frame的元素位置或者属性特性,使用find系列的方法,选择到该元素,得到对应的WebElement对象
wd.switch_to.frame(wd.find_element(By.TAG_NAME, "iframe"))
#例1:
from selenium import webdriver
from selenium.webdriver.common.by import By
# 打开浏览器
driver = webdriver.Chrome()
# 打开网址
driver.get("https://cdn2.byhy.net/files/selenium/sample2.html")
#切换至内部嵌套的html页面操作
driver.switch_to.frame('frame1')
elements = driver.find_elements(By.CSS_SELECTOR, ".plant")
for element in elements:
print(element.text)
#切换至默认html页面
driver.switch_to.default_content()
driver.find_element(By.CSS_SELECTOR,'#outerbutton').click()
2 切换到新的窗口
在新窗口里面 打开一个新网址, 并且去自动化操作新窗口里面的元素
方法:使用Webdriver对象的switch_to属性的 window方法:
wd.switch_to.window(handle)
#例1
from selenium import webdriver
from selenium.webdriver.common.by import By
# 打开浏览器
driver = webdriver.Chrome()
# 打开网址
driver.get("https://cdn2.byhy.net/files/selenium/sample3.html")
element = driver.find_element(By.CSS_SELECTOR, 'body>a')
element.click()
#切换为跳转后的窗口
for handle in driver.window_handles:
# 先切换到该窗口
driver.switch_to.window(handle)
# 得到该窗口的标题栏字符串,判断是不是我们要操作的那个窗口
if 'cn.bing.com' in driver.title:
# 如果是,那么这时候WebDriver对象就是对应的该该窗口,正好,跳出循环,
break
#打印当前窗口的标题
print(driver.title)
#切换回跳转前的窗口
for handle in driver.window_handles:
# 先切换到该窗口
driver.switch_to.window(handle)
# 得到该窗口的标题栏字符串,判断是不是我们要操作的那个窗口
if '白月黑羽测试网页3' in driver.title:
# 如果是,那么这时候WebDriver对象就是对应的该该窗口,正好,跳出循环,
break
#打印当前窗口的标题
print(driver.title)
#例2:
```python
from selenium import webdriver
from selenium.webdriver.common.by import By
# 打开浏览器
driver = webdriver.Chrome()
# 打开网址
driver.get("https://cdn2.byhy.net/files/selenium/sample3.html")
element = driver.find_element(By.CSS_SELECTOR, 'body>a')
element.click()
# mainWindow变量保存当前窗口的句柄
mainwindow = driver.current_window_handle
for handle in driver.window_handles:
# 先切换到该窗口
driver.switch_to.window(handle)
# 得到该窗口的标题栏字符串,判断是不是我们要操作的那个窗口
if 'cn.bing.com' in driver.title:
# 如果是,那么这时候WebDriver对象就是对应的该该窗口,正好,跳出循环,
break
print(driver.title)
#通过前面保存的老窗口的句柄,自己切换到老窗口
driver.switch_to.window(mainwindow)
print(driver.title)
六、选择框
1 radio选择框
radio框选择选项,直接用WebElement的click方法,模拟用户点击就可以了
from selenium import webdriver
from selenium.webdriver.common.by import By
driver = webdriver.Chrome()
driver.get("https://cdn2.byhy.net/files/selenium/test2.html")
# 获取当前选中的元素
element = driver.find_element(By.CSS_SELECTOR,'#s_radio [checked="checked"]')
print(element.get_attribute('value'))
# 点选 小雷老师
driver.find_element(By.CSS_SELECTOR,'[value="小雷老师"]').click()
2 checkbox选择框
对checkbox进行选择,也是直接用 WebElement 的 click 方法,模拟用户点击选择
要选中checkbox的一个选项,必须 先获取当前该复选框的状态 ,如果该选项已经勾选了,就不能再点击。否则反而会取消选择。
from selenium import webdriver
from selenium.webdriver.common.by import By
driver = webdriver.Chrome()
driver.get("https://cdn2.byhy.net/files/selenium/test2.html")
time.sleep(2)#增加延迟时间,看页面效果
#先把 已经选中的选项全部点击一下
elements = driver.find_elements(By.CSS_SELECTOR,'#s_checkbox [checked="checked"]')
for i in elements:
i.click()
time.sleep(2)#增加延迟时间,看页面效果
#再选择所有选项
elements = driver.find_elements(By.CSS_SELECTOR,'#s_checkbox input')
for i in elements:
i.click()
3 select选择框
select框 则是一个新的select标签, Selenium 专门提供了一个 Select类 进行操作,具体如下:
select_by_value
eg:s.select_by_value(‘foo’) foo为value属性值
select_by_index
根据选项的 次序 (从1开始),选择元素
select_by_visible_text
根据选项的 可见文本 ,选择元素
eg:s.select_by_visible_text(‘Bar’)
deselect_by_value
根据选项的value属性值, 去除 选中元素
deselect_by_index
根据选项的次序,去除 选中元素
deselect_by_visible_text
根据选项的可见文本,去除 选中元素
deselect_all
去除 选中所有元素
Select单选框
from selenium import webdriver
from selenium.webdriver.common.by import By
# 导入Select类
from selenium.webdriver.support.ui import Select
driver = webdriver.Chrome()
driver.get("https://cdn2.byhy.net/files/selenium/test2.html")
# 创建Select对象
select = Select(driver.find_element(By.CSS_SELECTOR,'#ss_single'))
# 通过 Select 对象选中小雷老师
select.select_by_value('小雷老师')
Select多选框
from selenium import webdriver
from selenium.webdriver.common.by import By
#导入Select类
from selenium.webdriver.support.ui import Select
driver = webdriver.Chrome()
driver.get("https://cdn2.byhy.net/files/selenium/test2.html")
#创建Select对象
select = Select(driver.find_element(By.CSS_SELECTOR,'#ss_multi'))
# 选择小雷老师 和 小凯老师
select.select_by_value('小雷老师')
select.select_by_visible_text('小江老师')
time.sleep(2)
# 清除所有 已经选中 的选项
select.deselect_all()