2w元教学课程,免费分享,教你搞定selenium自动化框架封装!

2w元教学课程,免费分享,教你搞定selenium自动化框架封装!

首先,大家在做selenium自动化的时候,通常都是调用官网提供的元素定位方法,直接调用,可能初期做自动化的时候,不会有什么问题,但是随着我们项目功能越来越多,业务也越来越复杂,有些定位功能,需要单独定制,如果是直接调用的话,我们需要修改所有调用元素定位方法的代码,这样我们维护代码需要耗费很多时间,下面我们通过将元素定位单独封装,来解决这个问题,话不多说,直接贴代码。

(注意:这里执行的地方,需要依赖driver驱动,这里我用的是Chrome浏览器,所以安装的是Chromedriver,大家可以直接去下载搭建环境)

log.py

# -*- coding: utf-8 -*-
# @Time    : 2019/2/15 9:23 AM
# @Author  : 余少琪
# @FileName: log.py
# @email   : 1603453211@qq.com
"""
这里封装了打印日志,之后做自动化的过程中,可以调用直接LogHandler方法,
将元素定位的信息打印出来,方便我们查看及定位问题。
"""
import logging
from logging import handlers
import colorlog
from common.setting import DevConfig
class LogHandler(object):
# 日志级别关系映射
level_relations = {

'debug': logging.DEBUG,
'info': logging.INFO,
'warning': logging.WARNING,
'error': logging.ERROR,
'crit': logging.CRITICAL
}
def __init__(self, filename, level='info', when='D', backCount=3, fmt='%(asctime)s - %(filename)s[line:%('
'lineno)d] - %(levelname)s: %(message)s'):
self.logger = logging.getLogger(filename)
self.log_colors_config = {

'DEBUG': 'cyan',
'INFO': 'white',
'WARNING': 'yellow',
'ERROR': 'red',
'CRITICAL': 'red',
}
formatter = colorlog.ColoredFormatter(
'%(log_color)s[%(asctime)s] [%(name)s] [%(levelname)s]: %(message)s',
log_colors=self.log_colors_config)
# 设置日志格式
format_str = logging.Formatter(fmt)
# 设置日志级别
self.logger.setLevel(self.level_relations.get(level))
# 往屏幕上输出
sh = logging.StreamHandler()
# 设置屏幕上显示的格式
sh.setFormatter(formatter)
# 往文件里写入#指定间隔时间自动生成文件的处理器
th = handlers.TimedRotatingFileHandler(filename=filename, when=when, backupCount=backCount, encoding='utf-8')
"""
#实例化TimedRotatingFileHandler
#interval是时间间隔,backupCount是备份文件的个数,如果超过这个个数,就会自动删除,when是间隔的时间单位,单位有以下几种:
# S 秒
# M 分
# H 小时、
# D 天、
# W 每星期(interval==0时代表星期一)
# midnight 每天凌晨    
"""
# 设置文件里写入的格式
th.setFormatter(format_str)
# 把对象加到logger里
self.logger.addHandler(sh)
self.logger.addHandler(th)
log_path = DevConfig().log_path
Log = LogHandler(log_path + '/all.log', level='debug')
# get_info_log = LogHandler(log_path + '/info.log', level='info')
# get_error_log = LogHandler(log_path + '/error.log', level='error')
if __name__ == '__main__':
msg = '111'
# log = LogHandler('all.log', level='debug')
Log.logger.debug('debug')
# log.logger.info(msg)
# log.logger.warning('警告')
# log.logger.error('报错')
# log.logger.critical('严重')
# LogHandler('error.log', level='error').logger.error('error')
# is_open = ReadIni(node='log').get_value("run")
# get_info_log.logger.info("111")

依赖库

> pip install PyUserInput 	 	
> pip intsall pyperclip
# -*- coding: utf-8 -*-
# @Time    : 2019/2/15 8:54 AM
# @Author  : 余少琪
# @FileName: basepage.py
# @email   : 1603453211@qq.com
from selenium.webdriver.remote.webdriver import WebDriver
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
# DevConfig 是我自己存放项目文件地址的,你们可以结合自己的业务单独创建
from common.setting import DevConfig
import datetime
from Outputs.logs.log import Log
from selenium.webdriver.support.select import Select
from time import time, sleep
from pykeyboard import PyKeyboard
import pyperclip
from pymouse import PyMouse
import os
import platform
class BasePage:
def __init__(self, driver: WebDriver):
self.driver = driver
# 等待元素可见
def wait_ele_visible(self, loc, img_name, timeout=20, poll_fre=0.5):
"""
:param loc: 元素
:param timeout:
:param poll_fre:
:return: 等待元素
"""
start_time = time()
try:
WebDriverWait(self.driver, timeout, poll_frequency=poll_fre).until(EC.visibility_of_element_located(loc))
Log.logger.info("等待{0}元素可见, 用时{1:.2f}秒.".format(loc, time()-start_time))
except:
self.save_page_shots(img_name)
Log.logger.error("等待{0}元素可见失败, 用时{1:.2f}秒.".format(loc, time()-start_time))
raise
def send_pictures(self, loc, img_name, file):
"""
上传图片
:param loc:
:param img_name:
:param file: 图片路径
:return:
"""
start_time = time()
platform_system = platform.system()
if platform_system  == 'Windows':
try:
self.get_element(loc, img_name).send_keys(file)
Log.logger.info("开始上传文件,文件路径{0}, 用时{1:.2f}秒.".format(file, time() - start_time))
except:
self.save_page_shots(img_name)
Log.logger.error("上传图片失败!图片路径{0}".format(file))
raise
elif platform_system == 'Linux' or platform_system == "Darwin":
def _is_China(file):
# 判断文件名称中是否包含中文
for ch in file:
if u'\u4e00' <= ch <= u'\u9fff':
return True
return False
try:
if _is_China(file) is True:
Log.logger.error("文件路径中不允许包含中文字符!请修改文件命名。文件路径:{0}".format(file))
if _is_China(file) is False:
Log.logger.info("开始上传图片, 图片路径:{0}".format(file))
self.click_element(loc, img_name)
k = PyKeyboard()
# k.press_keys(['Command', 'Shift', 'E'])
m = PyMouse()
filepath = '/'
# 模拟键盘点击 Command + Shift + G
k.press_keys(['Command', 'Shift', 'G'])
# 获取当前屏幕尺寸
x_dim, y_dim = m.screen_size()
m.click(x_dim // 2, y_dim // 2, 1)
# 复制文件路径开头的斜杠/
pyperclip.copy(filepath)
# 粘贴斜杠/
k.press_keys(['Command', 'V'])
# 输入文件全路径进去
k.type_string(file)
sleep(2)
k.press_key('Return')
sleep(2)
k.press_key('Return')
sleep(2)
except:
self.save_page_shots(img_name)
Log.logger.error("上传图片失败!图片路径{0}".format(file))
raise
else:
Log.logger.error("{0}操作系统不支持上传文件功能!".format(get_current_system()))
# 精准 link text 定位
def accurate_link_text(self, text, img_name):
start_time = time()
Log.logger.info("开始通过 link text 进行定位, 定位内容:{0},用时{1:.2f}秒.".format(text, time()-start_time))
try:
self.driver.find_element_by_link_text(str(text)).click()
except:
self.save_page_shots(img_name)
Log.logger.error("精准 link text 定位失败!,用时{0:.2f}秒.".format(time()-start_time))
# 等待元素可点击
def wait_ele_clickable(self, loc, img_name, timeout=20, poll_fre=0.5):
"""
:param loc: 元素
:param timeout:
:param poll_fre:
:return: 等待元素
"""
start_time = time()
Log.logger.info("{0} 等待 {1} 元素可点击, 用时{2:.2f}秒.".format(img_name, loc, time()-start_time))
try:
WebDriverWait(self.driver, timeout, poll_frequency=poll_fre).until(EC.element_to_be_clickable(loc))
except:
self.save_page_shots(img_name)
Log.logger.error("等待元素可点击失败:{0}, 用时{1:.2f}秒.".format(loc, time()-start_time))
raise
# 元素存在
def wait_page_contain_element(self):
pass
# 查看元素
def get_element(self, loc, img_name):
start_time = time()
Log.logger.info("在 {0} 查找元素:{1}, 用时{2:.2f}秒.".format(img_name, loc, time()-start_time))
try:
ele = self.driver.find_element(*loc)
except:
self.save_page_shots(img_name)
Log.logger.error("查找元素{0}失败!用时{1:.2f}秒.".format(loc, time()-start_time))
raise
else:
return ele
# 查找所有元素
def get_elements(self, loc, img_name):
start_time = time()
Log.logger.info("在 {0} 查找元素:{1}, 用时{2:.2f}秒.".format(img_name, loc, time()-start_time))
try:
ele = self.driver.find_elements(*loc)
except:
self.save_page_shots(img_name)
Log.logger.error("查找元素{0}失败!用时{1:.2f}秒.".format(loc, time()-start_time))
raise
else:
return ele
# 点击元素
def click_element(self, loc, img_name, timeout=20, poll_fre=0.5):
start_time = time()
self.wait_ele_visible(loc, img_name, timeout, poll_fre)
ele = self.get_element(loc, img_name)
Log.logger.info("对 {0} 点击元素:{1},用时{2:.2f}秒. ".format(img_name, loc, time()-start_time))
try:
ele.click()
except:
self.save_page_shots(img_name)
Log.logger.error("点击元素失败, 元素内容:{0}".format(loc))
raise
# 元素的输入属性
def input_text(self, loc, value, img_name, timeout=20, poll_fre=0.5):
start_time = time()
self.wait_ele_visible(loc, img_name, timeout, poll_fre)
ele = self.get_element(loc, img_name)
Log.logger.info("对 {0} 将元素 {1} 输入文本值:{2}, 用时{3:.2f}秒.".format(img_name, loc, value, time()-start_time))
try:
ele.send_keys(value)
except:
self.save_page_shots(img_name)
Log.logger.error("元素输入文本失败!内容: {0}, 用时{1:.2f}秒. ".format(value, time()-start_time))
raise
# 获取元素属性
def get_ele_attribute(self, loc, attr_name, img_name,  timeout=20, poll_fre=0.5):
start_time = time()
self.wait_ele_visible(loc, img_name, timeout, poll_fre)
ele = self.get_element(loc, img_name)
Log.logger.info("在 {0} 获取元素 {1} 的 {2} 属性, 用时{3:.2f}秒".format(img_name, loc, attr_name, time()-start_time))
try:
value = ele.get_attribute(attr_name)
except:
self.save_page_shots(img_name)
Log.logger.error("获取元素属性{0}失败!用时{1:.2f}秒".format(loc, time()-start_time))
else:
Log.logger.info("属性值为:{}".format(value))
return value
# 获取属性的文本内容
def get_ele_text(self, loc, img_name,  timeout=20, poll_fre=0.5):
start_time = time()
self.wait_ele_visible(loc, img_name, timeout, poll_fre)
ele = self.get_element(loc, img_name)
Log.logger.info("在 {0} 获取元素 {1} 的文本值, 用时{2:.2f}秒 ".format(img_name, loc, time()-start_time))
try:
text = ele.text
except:
self.save_page_shots(img_name)
Log.logger.error("获取元素文本值失败!文本值内容:{0}, 用时{1:.2f}秒".format(loc, time()-start_time))
else:
Log.logger.info("属性值为:{0}, 用时{1:.2f}秒".format(text, time()-start_time))
return text
# 截图
def save_page_shots(self, img_name):
# 将图片存储在 OutPuts 的 screenshot 的文件中,唯一不同的是图片的命名
file_name = "{}_{}.png".format(img_name, datetime.datetime.now())
# 判断文件如果不存在,则创建存放一个文件夹
# DevConfig.screenshots_path是我自己创建的文件夹路径,你们可以自己创建一个
if not os.path.exists(DevConfig.screenshots_path):
os.mkdir(DevConfig.screenshots_path)
self.driver.save_screenshot(DevConfig.screenshots_path + "/" + file_name)
Log.logger.info("页面图片保存在:{}".format(DevConfig.screenshots_path + "/" + file_name))
# 切换至iframe页面
def switch_to_ifaram(self, loc, img_name):
Log.logger.info("切换ifram页面:{}".format(loc))
try:
WebDriverWait(self.driver, 20).until(EC.frame_to_be_available_and_switch_to_it(loc))
except:
self.save_page_shots(img_name)
Log.logger.error("切换至iframe页面失败!")
# 纵向滚动条操作
def vertical_scroll_bar(self, img_name, *postion, type=None):
"""
:param img_name:
:param postion: 滚动条的坐标,为 postion 为 0,则表示滑动到顶部,为 1000 时则表示滑动到底部
横向滑动时,需要同时传 x ,y 轴的坐标
:param type: 纵向 :portrait; 横向 :transverse
:return:
"""
Log.logger.info("开始滑动滚动条,滚动位置为{0}".format(postion))
try:
global js
# 判断滚动类型为纵向
if type == 'portrait' or type is None:
js = 'var action=document.documentElement.scrollTop=' + ",".join(map(str, postion))
# 判断滚动类型为横向
elif type == 'transverse':
js = "window.scrollTo" + str(postion) + ";"
self.driver.execute_script(js)
except:
self.save_page_shots(img_name)
Log.logger.error("滚条条滑动失败!")
# 富文本框输入
def rishtext(self, content, loc, img_name, loc_type="Id"):
"""
:param content: 富文本输入内容
:param loc: 元素名称
:param img_name:
:param loc_type: Id , ClassName, Name,TagName
:return:
"""
try:
Log.logger.info("开始输入富文本内容:{0}".format(content))
js = 'document.getElementBy' + str(loc_type) + "(" + str(
loc) + ")" + 'contentWindow.document.body.innerHTML="%s"' % content
self.driver.execute_script(js)
except:
self.save_page_shots(img_name)
Log.logger.error("富文本框输入失败!")
# 下拉框定位
def drop_down_menu_positioning(self, loc, img_name, type, value):
"""
:param loc:  loc = driver.find_element_by_id("kw")
:param img_name:
:param type: 下拉框定位类型,index 为坐标元素定位,value 为值定位,text则为文字定位
:param value:
:return:
"""
Log.logger.info("开始进行下拉框定位,定位类型:{0}, 定位内容:{1}".format(type, value))
try:
select = Select(loc)
if type == "index":
select.select_by_index(value)
elif type == 'value':
select.select_by_value(value)
elif type == 'text':
select.select_by_visible_text(value)
except:
self.save_page_shots(img_name)
Log.logger.error("下拉框定位失败!")
if __name__ == '__main__':
pass

元素定位我们已经封装好了,那么我们来看看具体的运行情况,下面我们以打开百度地址为例,然后在百度输入框中,输入“selenium”进行查询

    from  selenium import webdriver
from selenium.webdriver.common.by import By
driver = webdriver.Chrome()
# 打开百度地址
driver.get("http://www.baidu.com")
# 实例化BasePage,然后传入driver对象
basepage = BasePage(driver)`在这里插入代码片`
# 因为是输入内容,所以我们这里调用封装好的input_text()方法进行调用
basepage.input_text((By.NAME, "wd"), 'selenium', '再输入框中输入内容')
basepage.click_element((By.ID, 'su'), '点击搜索')

可以看到我们已经搜索成功了,下面我们再来看看日志的情况
在这里插入图片描述
查看日志信息
在这里插入图片描述
以上这些就是元素定位封装的方法,basepage中我只封装了一些常用的定位方法,selenium中元素定位的方式有很多,如果还有其他需要的,可以自己单独在进行封装。关于元素封装我也是基于自己对于自动化的学习和理解整理出来的,如果大家有什么更好的方式,欢迎随时讨论~

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/100660.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • 数据库第一范式 第二范式 第三范式 BC 范式

    数据库第一范式 第二范式 第三范式 BC 范式国内绝大多数院校用的王珊的《数据库系统概论》这本教材,某些方面并没有给出很详细很明确的解释,与实际应用联系不那么紧密,你有这样的疑问也是挺正常的。我教《数据库原理》这门课有几年了,有很多学生提出了和你一样的问题,试着给你解释一下吧。(基本来自于我上课的内容,某些地方为了不过于啰嗦,放弃了一定的严谨,主要是在“关系”和“表”上)首先要明白”范式(NF)”是什么意思。按照教材中的定义,范式是“

    2022年5月20日
  • 朋友圈集赞小程序 最新版_朋友圈虚拟点赞软件

    朋友圈集赞小程序 最新版_朋友圈虚拟点赞软件大家好这是一款朋友圈积攒截图小程序里面内涵三款样式生成,一款图文,一款分享,一款查看的样式也就是我们微信朋友圈所用到的样式就包含了里面的流量主那些可以用户自由的添加哈!赞的数量那些可以用户自定义的哈另外所需的内容也是用户自定义的安装方法的话和往常一样!直接微信开发者工具打开源码然后设置一个合法域名上传审核就可以了合法域名在压缩包里面,搭建解压了就可以看到了小程序源码下载地址:…

    2022年9月5日
  • 三角不等式_三角函数基本不等式公式

    三角不等式_三角函数基本不等式公式1.关于三角形边的不等式关于三角形有一个常用的不等式,以下面的三角形为例:$$a+b>c\\a+c>b\\b+c>a$$上面的三个不等式很容易理解

    2022年8月1日
  • java九九乘法表代码加解释_java九九乘法表编程代码是什么?

    java九九乘法表代码加解释_java九九乘法表编程代码是什么?展开全部packagech02;publicclassTEST{publicstaticvoidmain(String[]args){for(inti=1;i<=9;i++){for(intj=1;j<=i;j++){System.out.print(j+”*”+i+”=”+(i*j)+””);}System.out.println(…

    2022年7月15日
  • labview噪声发生器_labview示波器显示两个波形

    labview噪声发生器_labview示波器显示两个波形当今的电子元器件与过去相比,开关切换速度更快,斜率(slewrate)更大、每个封装包含的有源针脚数量更多,信号摆动更小。因此,设计者更加关注从手机到服务器等新数字设计中的电源噪声。通常我们使用示波器测量电源噪声。本应用指南举例说明了使用示波器分析电源噪声的各种技术,并讨论了如何选择和评测电源噪声测量工具。现在面临的精准测量的问题随着开关切换速度和信号斜率的升高以及器件上有源针脚数目的…

    2022年10月10日
  • mysql的longtext

    mysql的longtextvarchar为变长字节,所占空间为字符串实际长度加1,最长为65535个字节而longtext也是变长字符存储,只保存字符数据,最长为4294967295字节,比较适合存储大内容…

    2022年5月14日

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号