Python+selenium 【第十章】封装底层页面操作类
前情提要
上一章节我们说到的是对是配置文件的处理,方便我们对数据源进行操作,还有就是针对驱动类进行单独封装更方便其他方法调用
本章内容
主要是针对页面操作类进行封装,并加入日志模块,方便我们进行监控代码操作,并且结合我们之前封装的element_excel_utils中数据进行操作
为什么要封装Base_page(底层页面)
原因之前已经说过了,方便我们在编写测试用例或者测试操作的时候更加方便,另一个更方面是结合当前的操作输出日志,能够直观的告诉你代码当前正在运行什么东西,另一个原因就是我们封装好base类之后就更加符合我们的关键字驱动,只需要调用一个方法,就可以直接帮你实现你要的操作…
优化前
# -*- coding: utf-8 -*-
# @Time : 2022/1/7 16:57
# @Author : Limusen
# @File : demo_base
import time
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
driver = webdriver.Chrome()
driver.get("http://www.baidu.com")
driver.implicitly_wait(10)
driver.find_element(By.XPATH, '//*[@id="kw"]').send_keys("测试一下")
time.sleep(2)
driver.find_element(By.XPATH, '//*[@id="su"]').click()
优化后
这里可以看到出来,我们封装之后的操作只需要调用这个click或者send_keys就行了,减少了多余代码的编写,更加的方便了
# -*- coding: utf-8 -*-
# @Time : 2022/1/7 16:57
# @Author : Limusen
# @File : demo_base
import time
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
driver = webdriver.Chrome()
driver.get("http://www.baidu.com")
driver.implicitly_wait(10)
# excel中取出来的数据格式
element = {'baidu_input': {'element_name': '百度输入框', 'locator_type': 'id', 'locator_value': 'kw', 'timeout': 5.0},
'query_button': {'element_name': '点击查询按钮', 'locator_type': 'id', 'locator_value': 'su', 'timeout': 5.0}}
input_text = element['baidu_input']
query_button = element['query_button']
# 由于我们从字典中取出来的数据是这样
# 所以我们封装base_page 代码
def find_element(element_info):
locator_type = element_info["locator_type"]
locator_value = element_info["locator_value"]
locator_timeout = element_info["timeout"]
if locator_type == "name":
locator_type = By.NAME
elif locator_type == "css":
locator_type = By.CSS_SELECTOR
elif locator_type == "xpath":
locator_type = By.XPATH
elif locator_type == "id":
locator_type = By.ID
elif locator_type == "class":
locator_type = By.CLASS_NAME
elif locator_type == "linktext":
locator_type = By.LINK_TEXT
elif locator_type == "partiallink":
locator_type = By.PARTIAL_LINK_TEXT
elif locator_type == "tag":
locator_type = By.TAG_NAME
element = WebDriverWait(driver, locator_timeout).until(
lambda x: x.find_element(locator_type, locator_value))
return element
def click(element):
element = find_element(element)
element.click()
def send_keys(element, text):
element = find_element(element)
element.send_keys(text)
send_keys(element['baidu_input'],"测试一下")
click(element['query_button'])
- 整体代码
# -*- coding: utf-8 -*-
# @Time : 2022/1/7 16:57
# @Author : Limusen
# @File : demo_base
import time
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
driver = webdriver.Chrome()
driver.get("http://www.baidu.com")
driver.implicitly_wait(10)
# driver.find_element(By.XPATH, '//*[@id="kw"]').send_keys("测试一下")
# time.sleep(2)
# driver.find_element(By.XPATH, '//*[@id="su"]').click()
# excel中取出来的数据格式
element = {'baidu_input': {'element_name': '百度输入框', 'locator_type': 'id', 'locator_value': 'kw', 'timeout': 5.0},
'query_button': {'element_name': '点击查询按钮', 'locator_type': 'id', 'locator_value': 'su', 'timeout': 5.0}}
input_text = element['baidu_input']
query_button = element['query_button']
# 由于我们从字典中取出来的数据是这样
# 所以我们封装base_page 代码
def find_element(element_info):
locator_type = element_info["locator_type"]
locator_value = element_info["locator_value"]
locator_timeout = element_info["timeout"]
if locator_type == "name":
locator_type = By.NAME
elif locator_type == "css":
locator_type = By.CSS_SELECTOR
elif locator_type == "xpath":
locator_type = By.XPATH
elif locator_type == "id":
locator_type = By.ID
elif locator_type == "class":
locator_type = By.CLASS_NAME
elif locator_type == "linktext":
locator_type = By.LINK_TEXT
elif locator_type == "partiallink":
locator_type = By.PARTIAL_LINK_TEXT
elif locator_type == "tag":
locator_type = By.TAG_NAME
element = WebDriverWait(driver, locator_timeout).until(
lambda x: x.find_element(locator_type, locator_value))
return element
def click(element):
element = find_element(element)
element.click()
def send_keys(element, text):
element = find_element(element)
element.send_keys(text)
send_keys(element['baidu_input'],"测试一下")
click(element['query_button'])
封装Base_page
封装Base_page之前先了解一下匿名函数
匿名函数
在此我们先了解一下匿名函数的用法,匿名函数有哪些优点?
不用取名称,因为给函数取名是比较头疼的一件事,特别是函数比较多的时候
可以直接在使用的地方定义,如果需要修改,直接找到修改即可,方便以后代码的维护工作 语法结构简单,不用使用def
函数名(参数名):这种方式定义,直接使用lambda 参数:返回值 定义即可
匿名函数
# -*- coding: utf-8 -*-
# @Time : 2022/1/5 13:16
# @Author : Limusen
# @File : demo_lambda_24
# 阶层
def x(y, z):
return y * z
print(x(3, 2))
# 用匿名函数写的话
xx = lambda x, y: x * y
print(xx(3, 3))
新建Base_page
- 在common文件夹下新建base_page.py 将写好的代码copy进去
# -*- coding: utf-8 -*-
# @Time : 2022/1/5 11:05
# @Author : Limusen
# @File : demo_base_page_23
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
class DemoBasePage:
def __init__(self, driver):
self.driver = driver
def open_url(self, url):
self.driver.get(url)
def find_element(self, element_info):
"""
通过分离处理的元素识别字典信息,返回一个元素
:param element_info: 元素信息,字典类型{}
:return: element对象
"""
try:
locator_type = element_info["locator_type"]
locator_value = element_info["locator_value"]
locator_timeout = element_info["timeout"]
if locator_type == "name":
locator_type = By.NAME
elif locator_type == "css":
locator_type = By.CSS_SELECTOR
elif locator_type == "xpath":
locator_type = By.XPATH
elif locator_type == "id":
locator_type = By.ID
elif locator_type == "class":
locator_type = By.CLASS_NAME
elif locator_type == "linktext":
locator_type = By.LINK_TEXT
elif locator_type == "partiallink":
locator_type = By.PARTIAL_LINK_TEXT
elif locator_type == "tag":
locator_type = By.TAG_NAME
# 采用匿名函数 将元素存在x变量当中,然后去查找页面是否存在当前元素
element = WebDriverWait(self.driver, locator_timeout).until(
lambda x: x.find_element(locator_type, locator_value))
except Exception:
raise
return element
def click(self, element_info):
# 优化
element = self.find_element(element_info)
element.click()
def send_keys(self, element_info, text):
# 优化
element = self.find_element(element_info)
element.send_keys(text)
if __name__ == '__main__':
driver = webdriver.Chrome()
db = DemoBasePage(driver)
db.open_url("http://www.baidu.com")
driver.implicitly_wait(10)
# db.send_keys((By.XPATH, '//*[@id="kw"]'), "测试一下")
# time.sleep(2)
# db.click((By.XPATH, '//*[@id="su"]'))
# 优化代码 读取excel中的数据
element_info = {
'input_text': {'element_name': '输入框', 'locator_type': 'xpath', 'locator_value': '//*[@id="kw"]',
'timeout': 5.0},
'click_button': {'element_name': '点击按钮', 'locator_type': 'xpath', 'locator_value': '//*[@id="su"]',
'timeout': 5.0}}
input_t = element_info['input_text']
click_b = element_info['click_button']
db.send_keys(input_t, "测试一下")
db.click(click_b)
其他方法封装
- 大家可以自己封装自己想要的方法,这里就不一一列举了
# -*- coding: utf-8 -*-
# @Time : 2022/1/5 13:50
# @Author : Limusen
# @File : base_page
import time
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
from common.log_utils import logger
from common.config_utils import local_config
class BasePage:
def __init__(self, driver):
self.driver = driver # driver
def open_url(self, url):
try:
self.driver.get(url)
logger.info("打开url:%s" % url)
except Exception as e:
logger.error("不能打开制定网站,原因是: %s" % e.__str__())
def close_browser(self):
self.driver.close()
logger.info("关闭当前tab页签")
def exit_driver(self):
self.driver.quit()
logger.info("退出浏览器")
def set_window_max(self):
self.driver.maximize_window()
logger.info("浏览器最大化")
def page_refresh(self):
self.driver.refresh()
logger.info("浏览器刷新")
def get_title(self):
value = self.driver.title
logger.info("获取标题:%s" % value)
return value
def get_url(self):
value = self.driver.current_url
logger.info("获取url:%s" % value)
return value
def get_page_source(self):
self.wait(1)
source = self.driver.page_source
logger.info("获取页面源码,用来检查是否包含某个元素:%s" % source)
return source
def back_up(self):
self.driver.back()
logger.info("返回上一页")
def forward(self):
self.driver.forward()
logger.info("前进一页")
def clear_input(self, element_info):
element = self.find_element(element_info)
element.clear()
logger.info("清除内容输入框内容: %s" % element_info["locator_value"])
# 封装时间
def wait(self, seconds=local_config.time_out):
"""
固定等待--加入默认值,如果没有设置超时时间,则默认等待五秒钟
:param seconds: 如果没有传入值则默认等待5秒钟
"""
time.sleep(seconds)
logger.info("休息一会儿 %s 秒钟~" % seconds)
def implicitly_wait(self, seconds=local_config.time_out):
"""
隐式等待--加入默认值,如果没有设置超时时间,则默认等待五秒钟
:param seconds: 如果没有传入值则默认等待5秒钟
"""
self.driver.implicitly_wait(seconds)
logger.info("隐式等待个 %s 秒" % seconds)
def find_element(self, element_info):
"""
通过分离处理的元素识别字典信息,返回一个元素
:param element_info: 元素信息,字典类型{}
:return: element对象
"""
try:
locator_type = element_info["locator_type"]
locator_value = element_info["locator_value"]
locator_timeout = element_info["timeout"]
if locator_type == "name":
locator_type = By.NAME
elif locator_type == "css":
locator_type = By.CSS_SELECTOR
elif locator_type == "xpath":
locator_type = By.XPATH
elif locator_type == "id":
locator_type = By.ID
elif locator_type == "class":
locator_type = By.CLASS_NAME
elif locator_type == "linktext":
locator_type = By.LINK_TEXT
elif locator_type == "partiallink":
locator_type = By.PARTIAL_LINK_TEXT
elif locator_type == "tag":
locator_type = By.TAG_NAME
element = WebDriverWait(self.driver, locator_timeout).until(
lambda x: x.find_element(locator_type, locator_value))
logger.info('[%s]元素识别成功' % element_info['element_name'])
except Exception as e:
logger.error("[%s]元素不能识别,原因是: %s" % (element_info['element_name'], e.__str__()))
return element
def get_text(self, element_info):
element = self.find_element(element_info)
try:
text = element.text
logger.info("获取文本信息:%s" % text)
return text
except Exception as e:
logger.error("[%s]元素不能识别,原因是: %s" % (element_info['element_name'], e.__str__()))
def input(self, element_info, inputs):
"""
:param element_info: 元素信息,字典类型{}
:param inputs: 输入参数
"""
element = self.find_element(element_info)
try:
element.send_keys(inputs)
logger.info("输入框输入内容:%s , 识别输入框:%s" % (inputs, element_info["locator_value"]))
except Exception as e:
logger.error("[%s]元素不能识别,原因是: %s" % (element_info['element_name'], e.__str__()))
def click(self, element_info):
"""
:param element_info: 元素信息,字典类型{}
"""
element = self.find_element(element_info)
try:
element.click()
logger.info("识别元素进行点击操作:%s" % element_info["locator_value"])
except Exception as e:
logger.error("[%s]元素不能识别,原因是: %s" % (element_info['element_name'], e.__str__()))
if __name__ == '__main__':
driver = webdriver.Chrome()
db = BasePage(driver)
db.open_url("http://www.baidu.com")
driver.implicitly_wait(10)
# 优化代码 读取excel中的数据
element_info = {
'input_text': {'element_name': '输入框', 'locator_type': 'xpath', 'locator_value': '//*[@id="kw"]',
'timeout': 5.0},
'click_button': {'element_name': '点击按钮', 'locator_type': 'xpath', 'locator_value': '//*[@id="su"]',
'timeout': 5.0}}
input_t = element_info['input_text']
click_b = element_info['click_button']
db.input(input_t, "测试一下")
db.click(click_b)
日志模块
日志模块能够帮助我们快速定位到代码的错误地方,所以很有必要在代码中添加日志
新建log_demo进行学习
代码示例
# -*- coding: utf-8 -*-
# @Time : 2022/1/5 14:14
# @Author : Limusen
# @File : demo_log_24
# log日志demo
import os
import logging
import time
current_path = os.path.abspath(os.path.dirname(os.path.dirname(os.path.dirname(__file__))))
logs_path = os.path.join(current_path, 'logs')
# logger输入的地址
login_name = os.path.join(logs_path, 'Test_%s.log' % time.strftime("%Y_%m_%d"))
# 创建logger对象
logger = logging.getLogger("logger")
# logger的等级 info
logger.setLevel(20)
fh = logging.FileHandler(login_name, 'a', encoding="utf-8") # 输出日志到文件
fh.setLevel(20)
ch = logging.StreamHandler() # 输出日志到控制台
ch.setLevel(20)
logger.addHandler(fh)
logger.addHandler(ch)
fh.close() # 关闭以免重复打印
ch.close()
logger.info("测试一下")
代码图示
封装log_utils类
# -*- coding: utf-8 -*-
# @Time : 2022/1/5 14:13
# @Author : Limusen
# @File : log_utils
import os
import time
import logging
from common.config_utils import local_config
current_path = os.path.dirname(os.path.abspath(__file__))
log_path = os.path.join(current_path, '..','logs')
class LogUtils:
def __init__(self, logger=None):
self.log_name = os.path.join(log_path, 'Test_%s.log' % time.strftime('%Y_%m_%d'))
self.logger = logging.getLogger(logger) # 日志对象
self.logger.setLevel(local_config.log_level) # 日志级别
self.fh = logging.FileHandler(self.log_name, 'a', encoding='utf-8') # 输出到文件
self.fh.setLevel(local_config.log_level)
self.ch = logging.StreamHandler() # 输出到控制台
self.ch.setLevel(local_config.log_level)
formatter = logging.Formatter(
'[%(asctime)s] %(filename)s->%(funcName)s line:%(lineno)d [%(levelname)s] : %(message)s')
self.fh.setFormatter(formatter)
self.ch.setFormatter(formatter)
self.logger.addHandler(self.fh)
self.logger.addHandler(self.ch)
self.fh.close()
self.ch.close()
def get_log(self):
return self.logger
logger = LogUtils().get_log()
if __name__ == '__main__':
logger.info('测试一下日志文件')
其他类引入新建的日志类
base_page.py
# -*- coding: utf-8 -*-
# @Time : 2022/1/5 13:50
# @Author : Limusen
# @File : base_page
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
from common.log_utils import logger
class BasePage:
def __init__(self, driver):
self.driver = driver
def open_url(self, url):
self.driver.get(url)
logger.info("当前正在打开网址: [%s]" % url)
def find_element(self, element_info):
"""
通过分离处理的元素识别字典信息,返回一个元素
:param element_info: 元素信息,字典类型{}
:return: element对象
"""
try:
locator_type = element_info["locator_type"]
locator_value = element_info["locator_value"]
locator_timeout = element_info["timeout"]
if locator_type == "name":
locator_type = By.NAME
elif locator_type == "css":
locator_type = By.CSS_SELECTOR
elif locator_type == "xpath":
locator_type = By.XPATH
elif locator_type == "id":
locator_type = By.ID
elif locator_type == "class":
locator_type = By.CLASS_NAME
elif locator_type == "linktext":
locator_type = By.LINK_TEXT
elif locator_type == "partiallink":
locator_type = By.PARTIAL_LINK_TEXT
elif locator_type == "tag":
locator_type = By.TAG_NAME
# 采用匿名函数 将元素存在x变量当中,然后去查找页面是否存在当前元素
element = WebDriverWait(self.driver, locator_timeout).until(
lambda x: x.find_element(locator_type, locator_value))
logger.info("当前进行元素识别操作,元素名称为: [%s] " % (element_info["element_name"]))
except Exception as e:
logger.error("[%s]元素不能识别,原因是: %s" % (element_info['element_name'], e.__str__()))
raise
return element
def click(self, element_info):
# 优化
try:
element = self.find_element(element_info)
logger.info("当前进行点击操作,点击元素名称为: [%s] " % (element_info["element_name"]))
except Exception as e:
logger.error("当前元素不能点击,原因是: [%s]" % e.__str__())
raise
element.click()
def send_keys(self, element_info, inputs):
# 优化
try:
element = self.find_element(element_info)
logger.info("输入框输入内容:%s ,识别输入元素:[%s]" % (inputs, element_info["locator_value"]))
except Exception as e:
logger.error("[%s]元素不能识别,原因是: %s" % (element_info['element_name'], e.__str__()))
raise
element.send_keys(inputs)
if __name__ == '__main__':
driver = webdriver.Chrome()
db = BasePage(driver)
db.open_url("http://www.baidu.com")
driver.implicitly_wait(10)
# 优化代码 读取excel中的数据
element_info = {
'input_text': {'element_name': '输入框', 'locator_type': 'xpath', 'locator_value': '//*[@id="kw"]',
'timeout': 5.0},
'click_button': {'element_name': '点击按钮', 'locator_type': 'xpath', 'locator_value': '//*[@id="su"]',
'timeout': 5.0}}
input_t = element_info['input_text']
click_b = element_info['click_button']
db.send_keys(input_t, "测试一下")
db.click(click_b)
browser_utils.py
# -*- coding: utf-8 -*-
# @Time : 2022/1/4 19:44
# @Author : Limusen
# @File : browser_utils
# 封装驱动类
import os
import sys
import warnings
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from common.config_utils import local_config
from common.log_utils import logger
current_path = os.path.dirname(os.path.abspath(__file__))
system_driver = sys.platform
class BrowserUtils:
def __init__(self):
# 去除控制台警告
warnings.filterwarnings("ignore", category=DeprecationWarning)
self.driver_name = local_config.driver_name
def get_driver(self):
if self.driver_name.lower() == 'chrome':
logger.info("当前正在打开:%s" % self.driver_name)
return self.__get_chrome_driver()
elif self.driver_name.lower() == 'firefox':
logger.info("当前正在打开:%s" % self.driver_name)
return self.__get_firefox_driver()
elif self.driver_name.lower() == 'edge':
logger.info("当前正在打开:%s" % self.driver_name)
return self.__get_edge_driver()
def __get_chrome_driver(self):
# 先封装简易代码
# 加入系统环境判断
chrome_options = Options()
chrome_options.add_argument('--disable-gpu') # 谷歌文档提到需要加上这个属性来规避bug
chrome_options.add_argument('lang=zh_CN.UTF-8') # 设置默认编码为utf-8
chrome_options.add_experimental_option('useAutomationExtension', False) # 取消chrome受自动控制提示
chrome_options.add_experimental_option("excludeSwitches", ['enable-automation']) # 取消chrome受自动控制提示
if system_driver.lower() == "darwin":
"""如果是mac系统执行这个驱动"""
chrome_path = os.path.join(current_path, '..', 'webdriver', 'chrome', 'chromedriver.exe')
driver = webdriver.Chrome(executable_path=chrome_path, options=chrome_options)
logger.info('初始化Google浏览器并启动')
return driver
else:
chrome_path = os.path.join(current_path, '..', 'webdriver', 'chrome', 'chromedriver93.exe')
driver = webdriver.Chrome(executable_path=chrome_path, options=chrome_options)
logger.info('初始化Google浏览器并启动')
return driver
def __get_firefox_driver(self):
if system_driver.lower() == "darwin":
firefox_path = os.path.join(current_path, '..', 'webdriver', 'firefox', 'geckodriver')
driver = webdriver.Firefox(executable_path=firefox_path)
logger.info('初始化Firefox浏览器并启动')
return driver
else:
firefox_path = os.path.join(current_path, '..', 'webdriver', 'firefox', 'geckodriver.exe')
driver = webdriver.Firefox(executable_path=firefox_path)
logger.info('初始化Firefox浏览器并启动')
return driver
def __get_edge_driver(self):
"""
驱动下载地址:https://developer.microsoft.com/zh-cn/microsoft-edge/tools/webdriver/
:return:
"""
edge_path = os.path.join(current_path, '..', 'webdriver', 'edge', 'msedgedriver.exe')
driver = webdriver.Edge(executable_path=edge_path)
logger.info('初始化Edge浏览器并启动')
return driver
if __name__ == '__main__':
driver = BrowserUtils().get_driver()
driver.get("https://www.baidu.com")
总结
本章节主要是讲述的是封装底层模块方便其他模块调用,封装日志模块,能够更好的帮助测试人员定位代码报错的位置,能够快速定位到问题的所在
代码
地址 : https://gitee.com/todayisgoodday/PythonSelenium
博客园地址
https://www.cnblogs.com/yushengaqingzhijiao/category/2000515.html