《Python实现Web UI自动化测试实战:Selenium 3/4+unittest/pytest+gitlab+jenkins》读书笔记
导包:
from selenium.webdriver.support.ui import Select
from selenium.webdriver.support.select import Select
Select(driver.find_element())select_by_index(index)select_by_value(value) :通过value值选项下拉选项select_by_visible_text(text): 通过可见text选择下拉选项deselect_by_index(index)deselect_by_value(value)deselect_by_visible_text(text)deselect_all()optioins : 返回所有选项first_selected_option: 返回第一个选中项all_selected_options : 返回所有选中项is_multiple1 = Select(driver.find_element_by_id('s1Id')) # 实例化Select
sleep(2)
s1.select_by_index(1) # 通过index选择第二个选项:o1
sleep(2)
s1.select_by_value("o2") # 通过value值选择value="o2"的选项
sleep(2)
s1.select_by_visible_text("o3") # 通过可见text选择text="o3"的值,即在打开下拉列表时我们可以看到的文本
from selenium import webdriver
from selenium.webdriver.support.ui import Select
from time import sleep
import os
driver = webdriver.Chrome()
# driver = webdriver.Firefox()
html_file = 'File:///' + os.getcwd() + os.sep + 'myhtml6_3.html'
driver.get(html_file)
s1 = Select(driver.find_element_by_id('s1Id')) # 实例化Select
sleep(2)
all_options = s1.options
for i in range(0,len(all_options)): # 通过len方法获得选项数量,通过range方法将其变为一个整数列表
s1.select_by_index(i)
sleep(2)
driver.quit()
$ 当我们用select_by_visible_text选择时需要注意以下3点。
使用键盘模拟操作
driver.find_element_by_id('select').send_keys('b')
sleep(3)
driver.find_element_by_id('select').send_keys(Keys.ARROW_DOWN)
sleep(3)
driver.find_element_by_id('select').send_keys(Keys.ENTER)
cell_text = driver.find_element(By.ID, "CellWithId").text
print(cell_text)
# 输出表中的所有内容
tbody = driver.find_element(By.XPATH, "/html/body/table/tbody")
# 找出表格下有多少个tr
tr_list = tbody.find_elements(By.TAG_NAME, "tr")
print(len(tr_list), tr_list)
# 输出表格中的内容
for tr in range(0, len(tr_list)):
td_list = tr_list[tr].find_elements(By.TAG_NAME, "td")
for td in range(0, len(td_list)):
print(td_list[td].text)
sleep(3)
driver.quit()
通过id切换driver.switch_to.frame("ifrma1")
通过name(也是唯一)切换driver.switch_to.frame("name1")
通过index切换driver.switch_to.frame(0)
通过定位元素切换driver.switch_to.frame(iframe_element)
切回上一级driver.switch_to.parent_frame()
直接切回主页面driver.switch_to.default_content()
操作Alert弹窗
driver.switch_to.alert.text # 输出Alert弹窗文字
driver.switch_to.alert.accept() # 单击Alert弹窗中的 确定 按钮
操作Confirm弹窗
driver.switch_to.alert.text # 输出Confirm弹窗文字
driver.switch_to.alert.accept() # 单击Confirm弹窗中的 确定 按钮
driver.switch_to.alert.dismiss() # 单击Confirm弹窗中的 取消 按钮
操作Prompt弹窗
driver.switch_to.alert.text # 输出Prompt弹窗文字
driver.switch_to.alert.accept() # 单击Prompt弹窗中的 确定 按钮
driver.switch_to.alert.dismiss() # 单击Prompt弹窗中的 取消 按钮
driver.switch_to.alert.send_keys(xx) # Prompt弹窗中输入文字
默认情况下,浏览器下载的文件会在chrome浏览器设置的路径中,可以进行修改
指定浏览器的下载路径参数
Chrome下载文件
from selenium import webdriver
from time import sleep
import os
chromeOptions = webdriver.ChromeOptions() # 定义变量,存储Chrome浏览器的设置项
prefs = {"download.default_directory": "D:\\A\\"} # 指定默认下载路径
chromeOptions.add_experimental_option("prefs", prefs) # 将prefs定义的下载路径应用于浏览器设置
driver = webdriver.Chrome(chrome_options=chromeOptions) # 以自定义的设置项启动浏览器
html_file = 'File:///' + os.getcwd() + os.sep + 'myhtml6_13.html'
driver.get(html_file)
sleep(2)
driver.find_element_by_tag_name('a').click()
sleep(5)
driver.quit()
FireFox下载文件
from selenium import webdriver
from time import sleep
'''
browser.download.dir:指定下载路径
browser.download.folderList:设置成2表示使用自定义下载路径,设置成0表示下载到桌面,设置成1表示下载到默认路径
browser.download.manager.showWhenStarting:在开始下载时是否显示下载管理器
browser.helperApps.neverAsk.saveToDisk:对所给出的文件类型不再出现弹窗进行询问
'''
profile = webdriver.FirefoxProfile()
profile.set_preference('browser.download.dir', 'd:\\')
profile.set_preference('browser.download.folderList', 2)
profile.set_preference('browser.download.manager.showWhenStarting', False)
profile.set_preference('browser.helperApps.neverAsk.saveToDisk', 'application/zip')
driver = webdriver.Firefox(firefox_profile=profile)
driver.get('http://sahitest.com/demo/saveAs.htm')
driver.find_element_by_xpath('//a[text()="testsaveas.zip"]').click()
sleep(3)
driver.quit()
判断下载的文件和目标文件是否一致 -> 使用md5
这种情况只适用于,文件不变的情况
from selenium import webdriver
from time import sleep
import os
import hashlib
def get_md5(file):
m = hashlib.md5()
with open(file, 'rb') as f:
for line in f:
m.update(line)
md5code = m.hexdigest()
return md5code
if os.path.exists("D:\\A\\storm.rar"): # 先判断文件是否存在
os.remove("D:\\A\\storm.rar") # 如果存在则删除
chromeOptions = webdriver.ChromeOptions() # 定义变量,存储Chrome浏览器的设置项
prefs = {"download.default_directory": "D:\\A\\"} # 指定默认下载路径
chromeOptions.add_experimental_option("prefs", prefs) # 将prefs定义的下载路径应用于浏览器设置
driver = webdriver.Chrome(chrome_options=chromeOptions) # 以自定义的设置项启动浏览器
html_file = 'File:///' + os.getcwd() + os.sep + 'myhtml6_13.html'
driver.get(html_file)
sleep(2)
driver.find_element_by_tag_name('a').click()
sleep(5) # 等待下载完成,然后再去判断文件是否存在
if os.path.exists("D:\\A\\storm.rar"): # 先判断文件是否存在
file_md5 = get_md5("D:\\A\\storm.rar")
if file_md5=="6c17852b255374e8d9dc7c7c6a8c2b0d":
print('下载文件的md5值正确')
driver.quit()
input标签的文件上传
from selenium import webdriver
from time import sleep
import os
driver = webdriver.Chrome()
html_file = 'File:///' + os.getcwd() + os.sep + 'myhtml6_14.html'
driver.get(html_file)
sleep(2)
driver.find_element_by_id('file').send_keys("D:\\A\\storm.rar") # 直接传递一个文件
sleep(3)
driver.quit()
非input文件上传
●AutoIt,借助外力,我们去调用其生成的“.au3”或“.exe”文件。
●Python pywin32库,识别弹窗句柄,进而处理弹窗。
●SendKeys库。
一般富文本编辑器都是嵌套再iframe中
直接切换到ifram
from selenium import webdriver
from time import sleep
driver = webdriver.Chrome()
driver.get('http://mail.163.com/')
driver.maximize_window()
driver.implicitly_wait(20)
driver.find_element_by_id('switchAccountLogin').click()
driver.switch_to.frame(0) #切换到iframe
driver.find_element_by_name('email').send_keys('apitest100@163.com')
driver.find_element_by_name('password').send_keys('XXXXX')
driver.find_element_by_id('dologin').click()
sleep(3)
# 单击"写信"按钮
driver.find_elements_by_class_name('oz0')[1].click()
sleep(3)
# 富文本编辑器在iframe中
driver.switch_to.frame(3)
ele = driver.find_element_by_tag_name('body') # 富文本编辑器就是body
ele.clear()
ele.send_keys('Storm')
sleep(5)
driver.quit()
定位到富文本编辑器相邻的元素,使用tab键,切换到富文本编辑器
from selenium import webdriver
from time import sleep
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.action_chains import ActionChains
'''
切换到iframe,然后按"Tab"键定位到富文本编辑器,输入文字
'''
driver = webdriver.Chrome()
driver.get('http://mail.163.com/')
driver.maximize_window()
driver.implicitly_wait(20)
driver.find_element_by_id('switchAccountLogin').click()
driver.switch_to.frame(0) #切换到iframe
driver.find_element_by_name('email').send_keys('apitest333@163.com')
driver.find_element_by_name('password').send_keys('XXXX')
driver.find_element_by_id('dologin').click()
sleep(13)
# 单击"写信"按钮
driver.find_elements_by_class_name('oz0')[1].click()
sleep(3)
# 第一个"坑":定位“收件人”文本框的时候,要定位到<input>标签,否则不能使用send_keys
driver.find_element_by_class_name('nui-editableAddr-ipt').send_keys('apitest666@163.com')
# 第二个"坑":需要组元素定位,通过下标获取具体元素
ele = driver.find_elements_by_class_name('nui-ipt-input')[2]
ele.send_keys('邮件主题-Storm')
ele.send_keys(Keys.CONTROL, 'a')
ele.send_keys(Keys.CONTROL, 'c')
ele.send_keys(Keys.TAB)
sleep(3)
# 第三个"坑":不要使用ele.send_keys()
ActionChains(driver).send_keys('Hello Storm').perform()
sleep(3)
driver.quit()
使用JavaScript向富文本编辑器中输入文字
from selenium import webdriver
from time import sleep
driver = webdriver.Chrome()
driver.get('http://mail.163.com/')
driver.maximize_window()
driver.implicitly_wait(20)
driver.find_element_by_id('switchAccountLogin').click()
driver.switch_to.frame(0) #切换到iframe
driver.find_element_by_name('email').send_keys('apitest333@163.com')
driver.find_element_by_name('password').send_keys('XXXX')
driver.find_element_by_id('dologin').click()
sleep(13)
# 单击"写信"按钮
driver.find_elements_by_class_name('oz0')[1].click()
sleep(3)
# 富文本编辑器在iframe中
driver.switch_to.frame(3)
# 向编辑器中输入文字"document.getElementsByTagName('body')[0].innerHTML='<b>正文<b>;'"
js = "document.getElementsByTagName('body')[0].innerHTML='中国'"
driver.execute_script(js)
sleep(5)
driver.quit()
操作思路

drag_and_drop_by_offset(ele, x, y) : 拖动到某个坐标然后松开(平行移动x的长度)from selenium import webdriver
from time import sleep
from selenium.webdriver.common.action_chains import ActionChains
driver = webdriver.Chrome()
driver.get('https://passport.ctrip.com/user/reg/home')
driver.find_element_by_xpath('//*[@id="agr_pop"]/div[3]/a[2]').click()
sleep(2)
# 获取滑块
slider = driver.find_element_by_xpath('//*[@id="slideCode"]/div[1]/div[2]')
# 获取整个滑块框
ele = driver.find_element_by_id('slideCode')
# 需要使用到Actions的方法来进行拖动
ActionChains(driver).drag_and_drop_by_offset(slider,ele.size['width'], ele.size ['height']).perform()
# 这样也行,向右拖动一定的距离,长度是滑块框的宽度
# ActionChains(driver).drag_and_drop_by_offset(slider,ele.size['width'], 0).perform()
sleep(2)
driver.quit()
可以根据xpath匹配的方式
contains
starts-with
ends-with
from selenium import webdriver
from time import sleep
driver = webdriver.Chrome()
driver.get('https://www.126.com/')
sleep(2)
driver.switch_to.frame(0)
driver.find_element_by_xpath('//input[starts-with(@id,"auto-id-")]').send_keys('storm')
# driver.find_element_by_xpath('//input[contains(@id,"auto-id-")]').send_keys('storm')
sleep(2)
driver.quit()
cookie:存储在浏览器本地客户端,当我们发送请求携带cookie的时候可以实现登录操作
seesion:存放在服务器
token:应用于应用程序
get_cookies()
get_cookie("name")
delete_cookie('name')
delete_all_cookies()
add_cookie({"":""})
from selenium import webdriver
from time import sleep
from selenium.webdriver.common.by import By
import json
url = "http://127.0.0.1:8666/#/login"
driver = webdriver.Chrome()
driver.get(url)
sleep(2)
def login():
driver.find_element(By.NAME, "username").send_keys("admin")
driver.find_elements(By.TAG_NAME, "input")[1].send_keys("123456")
driver.find_element(By.TAG_NAME, "button").click()
def get_cookie():
"""获取cookie"""
sleep(2)
cur_cookies = driver.get_cookies()
print(type(cur_cookies))
print(type(cur_cookies[0]))
print(len(cur_cookies))
print(cur_cookies)
jsoncookies = json.dumps(cur_cookies)
with open("mycookies.json", "w") as f:
f.write(jsoncookies)
def read_cookie(file):
with open(file, "r") as f:
cookies_str = f.readline()
cookies_dict = json.loads(cookies_str)
driver.delete_all_cookies()
for cookie in cookies_dict:
for k in cookie.keys():
if k == "expiry":
cookie[k] = int(cookie[k])
driver.add_cookie(cookie)
# login()
# get_cookie()
read_cookie("mycookies.json")
driver.refresh()
sleep(2)
driver.quit()
👆: 添加cookie的时候,需要将expiry转换成整型(int),否则会报错InvalidArgumentException: Message: invalid argument: invalid 'expiry'。
封装一下
def get_url_with_cookies(driver, target_url, file):
cookies_file_path = file
cookies_file = open(cookies_file_path, "r")
cookies_str = cookies_file.readline()
cookies_dict = json.loads(cookies_str)
time.sleep(2)
driver.get(target_url)
driver.delete_all_cookies()
for cookie in cookies_dict:
for k in cookie.keys():
if k == "expiry":
cookie[k] = int(cookie[k])
driver.add_cookie(cookie)
time.sleep(2)
driver.refresh()
if __name__ == '__main__':
from selenium import webdriver
import time
import json
from time import sleep
driver = webdriver.Chrome()
get_url_with_cookies(driver, 'http://mail.163.com/', 'mycookie.json')
sleep(5)
driver.quit()
.save_screenshot("image.png"): 截图生成文件
.get_screenshot_as_file("image_png"): 截图生成文件
.get_screenshot_as_png(): 返回截图的二进制数据
.get_screenshot_as_base64(): 返回base64的字符串
from selenium import webdriver
import os
import time
script_name = os.path.basename(__file__).split('.')[0] # 获取当前脚本的名称,不包含扩展名
file_name = script_name + '_' + str(time.time()) + '.png' #组合成图片名
# print(file_name)
driver = webdriver.Chrome()
driver.get('https://www.baidu.com/')
driver.save_screenshot(file_name) # 截取当前页面,保存成".png"图片
driver.quit()
计算两张图片的相似程度
from selenium import webdriver
import unittest,time
from PIL import Image
'''
某些情况下,我们需要对某个功能执行两次并分别截图,通过比较截图来验证功能是否没问题
首先安装Python的pillow包,然后from PIL import Image
'''
class ImageCompare(object):
'''
本例实现的功能是对两张图片通过像素对比的算法,获取文件的像素个数大小
然后通过循环的方式对两张图片的所有项目进行一一对比 并计算对比结果的相似度的百分比
''' def make_regalur_image(self,img,size = (256,256)):
#将图片尺寸强制重置为指定的大小,然后再将其转换成RGB值
return img.resize(size).convert('RGB')
def split_image(self,img,part_size = (64,64)):
#将图片按给定大小切分
w,h = img.size
pw,ph = part_size
assert w % pw ==h % ph == 0
return [img.crop((i,j,i + pw,j + ph)).copy()
for i in range(0,w,pw) for j in range(0,h,ph)]
def hist_similar(self,lh,rh):
#统计切分后每部分图片的相似度频率曲线
assert len(lh) == len(rh)
return sum(1 - (0 if l == r else float(abs(1 - r)) / max(1,r))
for l,r in zip(lh,rh)) / len(lh)
def calc_similar(self,li,ri):
#计算两张图片的相似度
return sum(self.hist_similar(l.histogram(),r.histogram())
for l,r in zip(self.split_image(li),self.split_image(ri)))/16.0
def calc_similar_by_path(self,lf,rf):
li,ri = self.make_regalur_image(Image.open(lf)),\
self.make_regalur_image(Image.open(rf))
return self.calc_similar(li,ri)
class TestDemo(unittest.TestCase):
def setUp(self):
self.IC = ImageCompare()
self.driver = webdriver.Chrome()
def test_ImageComparison(self):
self.driver.get('https://www.baidu.com/')
self.driver.save_screenshot('a.png')
self.driver.get('https://www.baidu.com/')
self.driver.save_screenshot('b.png')
print(self.IC.calc_similar_by_path('a.png','b.png'))
def tearDown(self):
self.driver.quit()
if __name__ == '__main__':
unittest.main()
from selenium import webdriver
driver = webdriver.Chrome()
driver.get('http://www.baidu.com/')
driver.find_element_by_id('su').screenshot('d:\\A\\button.png') # 定位元素,然后截图
driver.quit()
当浏览器访问某个页面时,页面中会有默认的焦点元素。例如,我们访问百度首页时,默认的焦点元素是搜索框,即打开百度首页后,光标自动定位在搜索框。这时候我们可以使用“driver.switch_to.active_element”来获取搜索框元素。
from selenium import webdriver
driver = webdriver.Chrome()
driver.get("https://www.baidu.com")
# 获取当前焦点所在元素的attribute信息
id = driver.switch_to.active_element.get_attribute('id')
print(id)
driver.quit()
导包:
from selenium.webdriver.support.color import Color
创建颜色对象
HEX_COLOUR = Color.from_string('#2F7ED8')
RGB_COLOUR = Color.from_string('rgb(255, 255, 255)')
RGB_COLOUR = Color.from_string('rgb(40%, 20%, 40%)')
RGBA_COLOUR = Color.from_string('rgba(255, 255, 255, 0.5)')
RGBA_COLOUR = Color.from_string('rgba(40%, 20%, 40%, 0.5)')
HSL_COLOUR = Color.from_string('hsl(100, 0%, 50%)')
HSLA_COLOUR = Color.from_string('hsla(100, 0%, 50%, 0.5)')
BLACK = Color.from_string('black')
CHOCOLATE = Color.from_string('chocolate')
HOTPINK = Color.from_string('hotpink')
TRANSPARENT = Color.from_string('transparent') # 透明颜色
# 获取颜色
color = Color.from_string(button_ele.value_of_css_property("color"))
print(color)
assert color == Color.from_string('rgba(242, 245, 248, 1)')
格式:
Color.from_string('rgba(242, 245, 248, 1)')
=>
Color: rgba(242, 245, 248, 1)
验证:
assert login_button_background_colour.hex == '#ff69b4'
assert login_button_background_colour.rgba == 'rgba(255, 105, 180, 1)'
assert login_button_background_colour.rgb == 'rgb(255, 105, 180)'
driver.execute_script()
from selenium import webdriver
from time import sleep
driver = webdriver.Chrome()
driver.get('https://www.baidu.com/')
ele1JS = "document.getElementById('kw').value='storm'"
ele2JS = "document.getElementById('su').click()"
driver.execute_script(ele1JS)
sleep(3)
driver.execute_script(ele2JS)
sleep(3)
driver.quit()
删除readonly属性
from selenium import webdriver
from time import sleep
import os
driver = webdriver.Chrome()
html_file = 'File:///' + os.getcwd() + os.sep + 'myhtml7_2.html'
driver.get(html_file)
sleep(2)
js2 = "document.getElementById('id1').removeAttribute('readonly')"
driver.execute_script(js2)
driver.find_element_by_tag_name('input').send_keys('002020/06/06')
sleep(5)
driver.quit()
js = "document.getElementById('c-date1').removeAttribute('readonly')" # 原生js,移除属性
js = "$('input[id=c-date1]').removeAttr('readonly')" # jQuery,移除属性
js = "$('input[id=c-date1]').attr('readonly',False)" # jQuery,设置为False
js = "$('input[id=c-date1]').attr('readonly','')" # jQuery,设置为空
使用JavaScript执行单击操作
ele = driver.find_element_by_id('reg_butt')
js1 = "arguments[0].click()"
driver.execute_script(js1,ele)
纵向滚动条
js1 = "window.scrollTo(0, document.body.scrollHeight)"# 滑动滚动条到底部
js2 = "window.scrollTo(0,0)"# 滑动到顶端
js3 = "window.scrollTo(0,200)"# 向下滑动200像素
js4 = "arguments[0].scrollIntoView();" # 滑动到指定元素
横向滚动条
js5 = "window.scrollTo(document.body.scrollWidth,0)"
js6 = "window.scrollTo(0,0)"
js7 = "window.scrollTo(200,0)"
获取当前窗口的宽度 document.body.scrollWidth
获取当前窗口的高度 document.body.scrollHeight
滑动到指定元素
arguments[0].scrollIntoView(), arguments[0]是指第一个传参
js4 = "arguments[0].scrollIntoView();"
ele = driver.find_element_by_id('con-ar') #定位一个元素
driver.execute_script(js4,ele) #滑动到上面定位的元素的地方
def highLightElement(driver,element):
'''
#封装高亮显示页面元素的方法:使用js代码将页面元素对象的背景颜色设置为绿色,边框设置为红色
:param driver:
:param element:
:return:
'''
driver.execute_script("arguments[0].setAttribute('style', arguments[1]);", element, "background: green; border: 2px solid red;")
if __name__ == '__main__':
from selenium import webdriver
from time import sleep
driver = webdriver.Chrome()
driver.get('https://www.baidu.com/')
ele = driver.find_element_by_id('kw')
highLightElement(driver, ele)
sleep(3)
driver.quit()
options.add_argument:添加启动参数
options.add_experimental_option:添加实验选项
options.page_load_strategy:页面加载策略
options = webdriver.ChromeOptions()
options.add_argument("--start-maximized") # 最大化参数
options.add_argument('lang=zh_CN.UTF-8') # 指定编码格式
driver = webdriver.Chrome(chrome_options=options)
指定浏览器Driver地址启动
driver = webdriver.Chrome(executable_path='C:\\Python\\Python36\\chromedriver.exe')
禁止图片加载
options = webdriver.ChromeOptions()
prefs = {
'profile.default_content_setting_values' : {
'images' : 2
}
}
options.add_experimental_option('prefs',prefs)
driver = webdriver.Chrome(chrome_options = options)
无界面模式运行
options = webdriver.ChromeOptions()
options.add_argument('headless')
driver = webdriver.Chrome(chrome_options = options)
添加代理服务器
from selenium import webdriversaesqwdesdqxdzxfarddxdcfdfcchjhujyhuhjuhuygjhsssasasaddddddddddddddsdf
PROXY = "proxy_host:proxy:port"
options = webdriver.ChromeOptions()
desired_capabilities = options.to_capabilities()
desired_capabilities['proxy'] = {
"httpProxy":PROXY,
"ftpProxy":PROXY,
"sslProxy":PROXY,
"noProxy":None,
"proxyType":"MANUAL",
"class":"org.openqa.selenium.Proxy",
"autodetect":False
}
driver = webdriver.Chrome(desired_capabilities = desired_capabilities)