Selenium3与Python3实战 Web自动化测试框架
一、环境搭建
1、selenium环境搭建
Client:
- pycharm
- python3.6
Driver:
- Chrome → ChromeDriver
- Firefox → FirefoxDriver
- IE → InternetExplorerDriver
Selenium
1.1、Selenium安装
pip install selenium # 安装
from selenium import webdriver # 导入
driver = webdriver.Chrome() # 启动谷歌浏览器
driver.get("http://www.baidu.com") # 打开百度网址
# 注意:启动谷歌浏览器前需要配置好谷歌浏览器中间件 ,从网上下载chromedriver.exe ,将其放置到python的安装目录下
1.2、使用脚本启动不同浏览器
启动浏览器前需配置好浏览器对应driver:
- Chrome --chromedriver.exe :谷歌浏览器调试驱动插件
- Firefox --geckodrive.exe : 火狐浏览器调试驱动插件
- IE --MicrosoftWebDriver.exe : IE浏览器调试驱动插件
将上面三个exe文件下载后放置到python目录下
1)启动谷歌浏览器
from selenium import webdriver driver = webdriver.Chrome() driver.get('http://www.baidu.com')
2)启动火狐浏览器:
from selenium import webdriver driver = webdriver.Firefox() driver.get('http://www.baidu.com')
3)启动IE浏览器
from selenium import webdriver driver = webdriver.Ie() # driver = webdriver.Edge() # win 10版本启动IE浏览器,使用此行代码 driver.get('http://www.baidu.com')
2、使用expected_condition下的 title_contains判断页面标题是否与我们想要的一致,如判断页面标题是否有‘注册’字眼:
from selenium import webdriver from selenium.webdriver.support import expected_conditions import time driver = webdriver.Chrome() # driver = webdriver.Edge() # win 10版本启动IE浏览器,使用此行代码 driver.get('http://www.5itest.cn/register') time.sleep(5) is_live = expected_conditions.title_contains('注册') # 判断页面的标题中是否有注册两字 print('is_live:',is_live)
返回结果:
is_live: <selenium.webdriver.support.expected_conditions.title_contains object at 0x000000000354DEF0> # 存在
3、使用不同方式进行定位
访问注册链接:http://www.5itest.cn/register ,进行测试
from selenium import webdriver driver = webdriver.Chrome() driver.get('http://www.5itest.cn/register') driver.find_element_by_id('register_email').send_keys("nan@163.com") # 填写邮箱 user_name_node = driver.find_elements_by_class_name('controls')[1] # 使用classname进行定义,需要细心处理 user_name_node.find_element_by_class_name('form-control').send_keys('Eric_nan') # 填写用户名 driver.find_element_by_name('password').send_keys('111111') # 填写密码 driver.find_element_by_xpath('//*[@id="captcha_code"]').send_keys('2222') # 填写验证码
脚本控制启动浏览器并访问注册页面,同时自动输入我们设定的值:
4、使用expected_conditions判断元素是否可见
from selenium import webdriver from selenium.webdriver.support import expected_conditions from selenium.webdriver.support.wait import WebDriverWait from selenium.webdriver.common.by import By driver = webdriver.Chrome() locator = (By.CLASS_NAME,'controls') # 通过classname的方式 找到 controls WebDriverWait(driver,1).until(expected_conditions.visibility_of_element_located(locator)) # WebDriverWait: 传入两个参数,一个是driver,另一个是超时时间(int类型) # visibility_of_element_located:只在可见的元素里找对应的元素。如有返回内存地址
5、如何解决验证码自动输入
1)将注册页面全屏截图保存(使用driver.save_screenhot方法),再将验证码部分区域截图保存下来
打开本地图片、截取部分区域需要用到PIL ,安装:pip install -i https://pypi.douban.com/simple Pillow
driver = webdriver.Chrome() base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # 项目首路径 image_path = os.path.join(base_dir,'Image','imooc.png') # 图片路径,用于保存全屏截图后的图片 code_path = os.path.join(base_dir,'Image','code.png') # 验证码图片保存路径 driver.get('http://www.5itest.cn/register') driver.save_screenshot(image_path) # 全屏截图 code_element = driver.find_element_by_id("getcode_num") # 定位到验证码所在的文字 # print(code_element.location) # 获取该元素(图片)左上角的(x,y)坐标 # print(code_element.size) # 获取该元素(图片)长度、宽度 left_x = code_element.location['x'] # 左上角x值 top_y = code_element.location['y'] # 左上角y值 right_x = left_x + code_element.size['width'] # 右下角x值 right_y = top_y + code_element.size['height'] # 右下角y值 im = Image.open(image_path) # 使用PIL下的Image打开下载的imooc.png图片 img = im.crop((left_x,top_y,right_x,right_y)) # 将指定的某部分裁剪出来 img.save(code_path) # 保存
2)使用 showapiRequest解决图片验证码识别
①、使用pytesseract识别图片中得问题
安装:pip install pytesseract
import pytesseract from PIL import Image image = Image.open("E:/imooc2.png") text = pytesseract.image_to_string(image) # 将图片文字转换成字符串 print(text) # 缺点:机械性读取,无法读取图片中不规则的字体,不适合于干扰性比较强的验证码图片文字读取
②、 使用 showapiRequest解决图片验证码识别(需收费,每测试识别一次都会收取费用,低至0.01)
进入万维易源网:https://www.showapi.com/api/view/184/4
选择:验证码识别英数_文件 ,找到请求示例,下载SDK:ShowapiRequest.py
将 ShowapiRequest.py文件放到项目中,新建read_code_img.py文件,用于读取图片中的验证码:
验证码:
from setting.ShowapiRequest import ShowapiRequest from setting import setting r = ShowapiRequest("http://route.showapi.com/184-4","62666","d61950be50dfgjnr9969f741b8e730f5" ) # ShowapiRequest 的第一个参数是万维易源网的url ,第二个参数是易源网上你个人的appId , 第三个参数是易源网上的密钥
r.addBodyPara("typeId", "35") #typeId:表示识别几位数的图片验证码 ;35:'3'表示英数结合的验证码,'5'表示5位数的验证码 ; 31:一位数的验证码 r.addBodyPara("convert_to_jpg", "0") r.addFilePara("image", setting.code_path) # 添加要识别验证码的图片 res = r.post() print(res.text) # {"showapi_res_error":"","showapi_res_id":"6f0e4cdb977141b293ea12178ad3d37e","showapi_res_code":0,"showapi_res_body":{"Id":"5bac83cc-5637-4e2d-bc91-25a78b527241","Result":"ANLZZ","ret_code":0}} text = res.json()['showapi_res_body']['Result']# 以json格式读取:showapi_res_body 下 Result 的值 print(text) # 返回信息:ANLZZ (识别正确)
注:这种方式识别准确率比较高
将注册相关代码封装起来-初次封装
from selenium import webdriver from setting.ShowapiRequest import ShowapiRequest from setting import setting from PIL import Image import time import random class Register_Operate(object): def __init__(self,file_name): # 浏览器初始化 self.driver = webdriver.Chrome() self.driver.get('http://www.5itest.cn/register') self.driver.maximize_window() # 窗口最大化 self.file_name = file_name def get_element(self,id): # 获取element信息 element = self.driver.find_element_by_id(id) return element def get_range_for_user(self): # 获取随机字符串,用于邮箱随机输入、用户名随机输入 user_info = ''.join(random.sample('1234567890abcdefghijklmn',9)) return user_info def get_code_image(self): # 获取验证码图片,并保存到file_name中 self.driver.save_screenshot(self.file_name) # 全屏截图,保存到file_name code_element = self.get_element("getcode_num") # 定位到验证码所在的文字 # print(code_element.location) # 获取该元素(图片)左上角的(x,y)坐标 # print(code_element.size) # 获取该元素(图片)长度、宽度 left_x = code_element.location['x'] # 左上角x值 top_y = code_element.location['y'] # 左上角y值 right_x = left_x + code_element.size['width'] # 右下角x值 right_y = top_y + code_element.size['height'] # 右下角y值 im = Image.open(self.file_name) # 使用PIL下的Image打开下载的imooc.png图片 img = im.crop((left_x, top_y, right_x, right_y)) # 将指定的某部分裁剪出来(验证码图片) img.save(self.file_name) # 保存到file_name中 def code_online(self): # 将file_name中的验证码图片进行识别,用于注册时验证码输入 r = ShowapiRequest("http://route.showapi.com/184-4", "62626", "d61950be50dc4dbd9969f741b8e730f5") r.addBodyPara("typeId", "35") # typeId:表示识别几位数的图片验证码 ;35:'3'表示英数结合的验证码,'5'表示5位数的验证码 ; 31:一位数的验证码 r.addBodyPara("convert_to_jpg", "0") r.addFilePara("image", self.file_name) # 添加要识别验证码的图片,image:图片格式,setting.code_path:图片位置 res = r.post() # print(res.text) # {"showapi_res_error":"","showapi_res_id":"6f0e4cdb977141b293ea12178ad3d37e","showapi_res_code":0,"showapi_res_body":{"Id":"5bac83cc-5637-4e2d-bc91-25a78b527241","Result":"ANLZZ","ret_code":0}} code_text = res.json()['showapi_res_body']['Result'] # 以json格式读取:showapi_res_body 下 Result 的值 # print(code_text) return code_text def run_main(self): # 主程序 user_name = self.get_range_for_user() # 用户名 user_email = user_name + '@163.com' # 邮箱 self.get_element("register_email").send_keys(user_email) # 定位邮箱,并自动输入随机获取的邮箱号 self.get_element("register_nickname").send_keys(user_name) # 自动输入用户名 self.get_element("register_password").send_keys("111111") # 自动输入密码 self.get_code_image() # 获取验证码图片,保存于服务器 code_text = self.code_online() # 识别验证码图片,获取验证码 print(code_text) self.get_element("captcha_code").send_keys(code_text) # 自动输入验证码 self.get_element("register-btn").click() # 注册按钮 self.driver.close() # 关闭浏览器 time.sleep(3) self.driver.close() if __name__ == "__main__": file_name = setting.code_path register_oper = Register_Operate(file_name) # 实例化 # time.sleep(1) register_oper.run_main() # 运行主程序
6、封装读取配置文件方法
新建int配置文件:
#localElement.ini文件 [RegisterElement] user_email=id>register_email user_email_error=id>register_email-error user_name=id>register_nickname user_name_error=id>register_nickname-error password=id>register_password password_error=id>register_password-error code_image=id>getcode_num code_text=id>captcha_code code_text_error=id>captcha_code-error register_button=id>register-btn
使用python3自带 configparser模块, 用于读取配置文件信息:
from setting.setting import config_ini_dir import configparser class Read_Ini(object): # 初始化 def __init__(self,node = None): if node: self.node = node else: self.node = 'RegisterElement' # 配置文件中的某个节点 self.cf = self.load_ini() def load_ini(self): # 加载文件 cf = configparser.ConfigParser() # 使用 configparser模块读取配置文件信息 cf.read(config_ini_dir) # 配置文件所在路径 return cf def get_value(self,key): # 获取配置文件中key的value值 data = self.cf.get(self.node,key) return data # if __name__ == '__main__': # read_init = Read_Ini() # print(read_init.get_value('user_name')) # 结果:id>register_nickname
7、封装定位元素类
# find_element.py from util.read_ini import Read_Ini class FindElement(object): def __init__(self,driver): self.driver = driver def get_element(self,key): read_ini = Read_Ini() data = read_ini.get_value(key) by,value = data.split('>') try: if by == 'id': return self.driver.find_element_by_id(value) elif by == 'name': return self.driver.find_element_by_name(value) elif by == 'className': return self.driver.find_element_by_class_name(value) elif by == 'xpath': return self.driver.find_element_by_xpath(value) else: return self.driver.find_element_by_css(value) except Exception as e: print("find_element错误信息:",e) return None
* 注册完整流程
1、配置文件
1)LocalElement.ini:存定位元素信息
[RegisterElement] user_email=id>register_email user_email_error=id>register_email-error user_name=id>register_nickname user_name_error=id>register_nickname-error password=id>register_password password_error=id>register_password-error code_image=id>getcode_num code_text=id>captcha_code code_text_error=id>captcha_code-error register_button=id>register-btn
2)setting.py:
import os base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # 项目首路径 codeerror_path = os.path.join(base_dir,'Image','codeerror.png') # 验证码错误图片路径 code_path = os.path.join(base_dir,'Image','code.png') # 验证码图片保存路径 config_ini_dir = os.path.join(base_dir,'setting','localElement.ini') # localElement.ini 配置文件路径
3)read_ini.py:读取配置文件LocalElement.py的配置信息
from setting.setting import config_ini_dir import configparser class Read_Ini(object): # 初始化 def __init__(self,node = None): if node: self.node = node else: self.node = 'RegisterElement' # 配置文件中的某个节点 self.cf = self.load_ini() def load_ini(self): # 加载文件 cf = configparser.ConfigParser() # 使用 configparser模块读取配置文件信息 cf.read(config_ini_dir) # 配置文件所在路径 return cf def get_value(self,key): # 获取配置文件中key的value值 data = self.cf.get(self.node,key) return data
4)find_element.py:获取元素定位信息
from util.read_ini import Read_Ini class FindElement(object): def __init__(self,driver): self.driver = driver def get_element(self,key): read_ini = Read_Ini() data = read_ini.get_value(key) by,value = data.split('>') try: if by == 'id': return self.driver.find_element_by_id(value) elif by == 'name': return self.driver.find_element_by_name(value) elif by == 'className': return self.driver.find_element_by_class_name(value) elif by == 'xpath': return self.driver.find_element_by_xpath(value) else: return self.driver.find_element_by_css(value) except Exception as e: # print("find_element错误信息:",e) return None
5)register_function.py:注册测试主程序
from selenium import webdriver from setting.ShowapiRequest import ShowapiRequest from setting import setting from PIL import Image from base.find_element import FindElement import time import random """用于注册测试,自动识别验证码,自动定位form表单位置,进行对应数据自动输入""" class RegisterFunction(object): def __init__(self,file_name,url,i,codeerror_name): # 浏览器初始化 self.i = i self.url = url self.file_name = file_name # 验证码图片保存路径 self.codeerror_name = codeerror_name # 验证码错误图片截图保存路径 self.driver = self.get_driver() def get_driver(self): # 启动浏览器类型 if self.i == 1: driver = webdriver.Chrome() elif self.i == 2: driver = webdriver.Firefox() else: driver = webdriver.Edge() driver.get(self.url) driver.maximize_window() return driver def get_user_element(self,key): # 定位元素位置,获取对应element find_element = FindElement(self.driver) user_element = find_element.get_element(key) # key为LocalElement 中的value值,如:id>register_email ; user_element:register_email return user_element def send_user_info(self, key, data): # 输入注册时所需用户信息 # get_user_element:定位到元素所在位置 ,send_keys:发送数据,让页面自动填写信息 self.get_user_element(key).send_keys(data) def get_range_for_user(self): # 获取随机字符串,用于邮箱随机输入、用户名随机输入 user_info = ''.join(random.sample('1234567890abcdefghijklmn',9)) return user_info def get_code_image(self): # 获取验证码图片,并保存到file_name中 self.driver.save_screenshot(self.file_name) # 全屏截图,保存到file_name code_element = self.get_user_element("code_image") # 定位到验证码图片所在的区域 left_x = code_element.location['x'] # 左上角x值 top_y = code_element.location['y'] # 左上角y值 right_x = left_x + code_element.size['width'] # 右下角x值 right_y = top_y + code_element.size['height'] # 右下角y值 im = Image.open(self.file_name) # 使用PIL下的Image打开下载的imooc.png图片 img = im.crop((left_x, top_y, right_x, right_y)) # 将指定的某部分裁剪出来(验证码图片) img.save(self.file_name) # 保存到file_name中 def code_online(self): # 将file_name中的验证码图片进行识别,用于注册时验证码输入 r = ShowapiRequest("http://route.showapi.com/184-4", "62626", "d61950be50dc4dbd9969f741b8e730f5") r.addBodyPara("typeId", "35") # typeId:表示识别几位数的图片验证码 ;35:'3'表示英数结合的验证码,'5'表示5位数的验证码 ; 31:一位数的验证码 r.addBodyPara("convert_to_jpg", "0") r.addFilePara("image", self.file_name) # 添加要识别验证码的图片,image:图片格式,setting.code_path:图片位置 res = r.post() # print(res.text) # {"showapi_res_error":"","showapi_res_id":"6f0e4cdb977141b293ea12178ad3d37e","showapi_res_code":0,"showapi_res_body":{"Id":"5bac83cc-5637-4e2d-bc91-25a78b527241","Result":"ANLZZ","ret_code":0}} code_text = res.json()['showapi_res_body']['Result'] # 以json格式读取:showapi_res_body 下 Result 的值 # print(code_text) return code_text def run_main(self): # 主程序 user_name = self.get_range_for_user() # 用户名 user_email = user_name + '@163.com' # 邮箱 self.send_user_info('user_email', user_email) # 定位邮箱,并自动输入随机获取的邮箱号 self.send_user_info('user_name', user_name) # 自动输入用户名 self.send_user_info('password', "111111") # 自动输入密码 self.get_code_image() # 获取验证码图片,保存于服务器 code_text = self.code_online() # 识别验证码图片,获取验证码 print(code_text) self.send_user_info("code_text",code_text) # 自动输入验证码 # self.send_user_info("code_text",11111) # 自动输入验证码 self.get_user_element("register_button").click() # 注册按钮 code_error = self.get_user_element("code_text_error") # 定位到验证码错误信息位置,如果返回None,表示定位失败,验证码没有错误 if code_error == None: print("注册成功") else: self.driver.save_screenshot(codeerror_name) time.sleep(3) self.driver.close() if __name__ == "__main__": file_name = setting.code_path codeerror_name = setting.codeerror_path url = 'http://www.5itest.cn/register' register_func = RegisterFunction(file_name,url,1,codeerror_name) # 实例化 register_func.run_main() # 运行主程序