加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
base_page.py 15.98 KB
一键复制 编辑 原始数据 按行查看 历史
unknown 提交于 2022-09-16 16:29 . fix
#!/usr/bin/python3.9
# -*- coding: utf-8 -*-
# @Time : 2021/4/20 10:06 上午
# @Author : 姜晖
# @Email : jianghui@tianyancha.com
# @File : base_page.py
import platform
from contextlib import contextmanager
import allure
import xlrd
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.common.by import By
from selenium.webdriver.remote.webdriver import WebDriver
from selenium.webdriver.remote.webelement import WebElement
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.expected_conditions import staleness_of
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.keys import Keys
import os
import platform
class BasePage(object):
"""
实现通用的Page方法,对常用自动化行为做封装
减少每个Page对Appium,selenium等库的太多依赖
"""
# 此处是黑名单机制,任何广告弹窗,tips等等都可以定义在这,形式如下:
# [(By.ID, "image_cancel"),(By.ID, "tips") ]
_black_list = [(By.CLASS_NAME, "close-btn")]
def __init__(self, driver: WebDriver = None):
self.driver = driver
def find_element(self, locator, isPresence=False):
try:
if isPresence:
WebDriverWait(self.driver, 20).until(EC.presence_of_element_located(locator))
return self.driver.find_element(*locator)
else:
WebDriverWait(self.driver, 20).until(EC.visibility_of_element_located(locator))
return self.driver.find_element(*locator)
except:
self.handle_exception()
# 按理说应该这块是递归调用,但是这块要慎重处理,处理不好的话会出现死循环
# self.find_element(locator)
return self.driver.find_element(*locator)
def find_elements(self, locator, isPresence=False):
try:
if isPresence:
WebDriverWait(self.driver, 10).until(EC.presence_of_all_elements_located(locator))
return self.driver.find_elements(*locator)
else:
WebDriverWait(self.driver, 10).until(EC.visibility_of_all_elements_located(locator))
return self.driver.find_elements(*locator)
except:
self.handle_exception()
return self.driver.find_elements(*locator)
def action_chains(self, locator, index=0, no_click=False):
ele = self.find_elements(locator)[index]
if no_click:
ActionChains(self.driver).move_to_element(ele).perform()
else:
ActionChains(self.driver).move_to_element(ele).click(ele).perform()
# 此方法的好处是不仅仅在找元素的时候,处理异常,同时在点击的时候遇到任何问题,也会去看看是不是有什么干扰项。
def find_element_and_click(self, locator, index=0):
try:
self.find_elements(locator)[index].click()
except:
self.handle_exception()
self.find_elements(locator)[index].click()
def find_element_and_click_by_js(self, locator, index=None):
"""
通过执行javascript脚本达到定位元素并且点击的目的,主要是用来处理一些正常通过selenium定位并点击处理不了的场景,
比如目前弹窗div中的checkbox控件的选中,目前此方法暂不做处理异常操作。
:param locator: 定位符,元祖形式
:param index:
:return:
"""
by_way = locator[0]
by_locator = locator[1]
if not index:
if by_way == 'id':
js_locator = 'getElementById({0})'.format(by_locator)
elif by_way == 'css selector':
js_locator = 'querySelector({0})'.format(by_locator)
else:
raise Exception('The locator you selected can not matched to js way, please change it')
js_code = 'return document.{0}'.format(js_locator)
element = self.driver.execute_script(js_code)
self.driver.execute_script('arguments[0].click()', element)
else:
if by_way == 'class name':
js_locator = 'getElementsByClassName("{0}")'.format(by_locator)
elif by_way == 'name':
js_locator = 'getElementsByName({0})'.format(by_locator)
elif by_way == 'css selector':
js_locator = 'querySelector({0})'.format(by_locator)
else:
raise Exception('The locator you selected can not matched to js way, please change it')
js_code = 'return document.{0}'.format(js_locator)
element = self.driver.execute_script(js_code)
self.driver.execute_script('arguments[0].click()', element[index])
def find_elements_and_click(self, locator, index=0):
try:
self.find_elements(locator)[index].click()
except:
self.handle_exception()
self.find_elements(locator)[index].click()
def find_elements_by_selenium_and_click_by_js(self, locator, index=None):
by_way = locator[0]
by_locator = locator[1]
if index is not None:
if by_way == 'xpath':
js_locator = self.driver.find_elements_by_xpath(by_locator)[index]
else:
raise Exception('The locator you selected can not matched to js way, please change it')
self.driver.execute_script('arguments[0].click()', js_locator)
else:
if by_way == 'xpath':
js_locator = self.driver.find_element_by_xpath(by_locator)
else:
raise Exception('The locator you selected can not matched to js way, please change it')
self.driver.execute_script('arguments[0].click()', js_locator)
def find_element_and_input(self, locator, keyword, index=0):
try:
self.find_elements(locator)[index].clear()
self.find_elements(locator)[index].send_keys(keyword)
except:
self.handle_exception()
self.find_elements(locator)[index].clear()
self.find_elements(locator)[index].send_keys(keyword)
def get_current_url(self) -> str:
"""
get current url of opening page
"""
return self.driver.current_url
@contextmanager
def wait_for_page_load(self, element: WebElement = None):
"""
Wait until page loaded, if element assigned, wait specific element loaded and otherwise wait full page
:param element:
:return:
"""
old_page = self.driver.find_element_by_tag_name('html') if not element else element
yield
WebDriverWait(self.driver, 60).until(
staleness_of(old_page),
'The page {0} is not refreshed'.format(self.get_current_url())
)
def get_all_window_handles(self):
return self.driver.window_handles
def switch_to_window(self, window_name):
self.driver.switch_to_window(window_name)
def switch_to_div_alert(self):
"""
This is made to handle those div kind of alert dialog
"""
self.driver.switch_to.default_content()
def handle_exception(self):
for locator in self._black_list:
elements = self.driver.find_elements(*locator)
if len(elements) >= 1:
elements[0].click()
else:
print("%s not found" % str(locator))
# find_elements是重隐式等待的,如果黑名单的locator有的话会点击,但是如果没有的话,也会等待隐式等待设置的时间,所以可以先判断黑名单的项是否在page_source中
# page_source = self._driver.page_source
# if "image_cancel" in page_source:
# self._driver.find_element(*locator).click()
# elif "tips" in page_source:
# pass
def get_page_source(self):
return self.driver.page_source
def switch_to_new_window(self):
"""
切换到新打开的窗口,此处添加等待是防止新窗口还未打开的时候,就做了切换处理而导致无法达到预期。
:return:
"""
handles = self.driver.window_handles
try:
WebDriverWait(self.driver, 5).until(EC.new_window_is_opened(handles))
self.driver.switch_to.window(self.driver.window_handles[-1])
except:
self.driver.switch_to.window(self.driver.window_handles[-1])
def switch_to_first_window(self):
handles = self.driver.window_handles
try:
WebDriverWait(self.driver, 5).until(EC.new_window_is_opened(handles))
self.driver.switch_to.window(self.driver.window_handles[0])
except:
self.driver.switch_to.window(self.driver.window_handles[0])
def back_page(self):
self.driver.back()
def get_element_attribute(self, locator, attr, isvalueChange=False, value=""):
element = self.find_element(locator)
if isvalueChange:
return WebDriverWait(self.driver, 20).until(lambda d : value == element.get_attribute(attr))
else:
return element.get_attribute(attr)
def get_element_text(self, locator, index=0):
element = self.find_elements(locator)[index]
return element.text
def get_element_all_text(self, locator, isset=False):
if isset:
return {element.text for element in self.find_elements(locator)}
else:
return [element.text for element in self.find_elements(locator)]
def get_elements_attribute(self, locator, attr, index=0, presence=False):
if presence:
return self.find_element(locator, isPresence=True).get_attribute(attr)
else:
element = self.find_elements(locator)[index]
return element.get_attribute(attr)
def capture_screenshot_to_allure(self):
screenshot = self.driver.get_screenshot_as_png()
allure.attach(screenshot, '截图', allure.attachment_type.PNG)
def get_local_storage(self, key):
return self.driver.execute_script("return localStorage.getItem(arguments[0])", key)
def set_local_storage(self, key, value):
self.driver.execute_script("localStorage.setItem(arguments[0], arguments[1]);", key, value)
def slide_page(self, locator, index=0):
"""等待页面滚动到对应元素可见"""
target = self.find_elements(locator, isPresence=True)
return self.driver.execute_script("arguments[0].scrollIntoView();", target[index])
@contextmanager
def switch_to_iframe(self, locator):
"""切换iframe"""
self.driver.switch_to.frame(self.find_element(locator))
yield
self.driver.switch_to.default_content()
# 此方法专门针对元素被定位后,内部的text属性还会加载变化的情况,如商家-设置-店铺信息-基本信息上方的三种状态
# 页面初始化时元素就可定位,但是缺省text为"-",需要等待一会才刷成对应的"已审核"等状态
# occur参数表示终止条件是目标文本显示还是不显示,用find_elements方法兼容单个元素和元素列表的情况
def wait_for_text(self, text, locator, occur=True, index=0):
# 这里的find_elements调用的是selenium原生的,而不是BasePage封装的,所以必须解包传参
if occur:
WebDriverWait(self.driver, 5, 0.5)\
.until(lambda d: text in d.find_elements(*locator)[index].text)
else:
WebDriverWait(self.driver, 5, 0.5)\
.until_not(lambda d: text in d.find_elements(*locator)[index].text)
# 与上面方法类似,此方法专门针对定位到元素后,元素内部的属性值会发生变化的情况
# 具体可见 商家端-设置-店铺信息-签约信息-签约有效期中的时间控件,页面刚加载时此处显示的是当前时间
# 加载完成后,才变成入驻时填写的签约时间,导致需要等待后才能进行字段校验
def wait_for_attr(self, attrAndValue:'(attr, value)', locator, occur=True, index=0):
if occur:
WebDriverWait(self.driver, 5, 0.5)\
.until(lambda d: attrAndValue[1] in d.find_elements(*locator)[index].get_attribute(attrAndValue[0]))
else:
WebDriverWait(self.driver, 5, 0.5) \
.until_not(lambda d: attrAndValue[1] in d.find_elements(*locator)[index].get_attribute(attrAndValue[0]))
def wait_for_disappear(self, locator):
WebDriverWait(self.driver, 10).until(EC.staleness_of(self.find_element(locator)))
# 元素是否存在
def isElementExist(self, elements):
driver = self.driver
try:
driver.find_elements_by_xpath(elements)
return True
except:
return False
def wait_html_change(self, attr, locator, index=0):
WebDriverWait(self.driver, 20, 0.5).until(lambda d: attr != d.find_elements(*locator)[index].get_attribute("outerHTML"))
def key_event(self, key, locator, index=0, time=1):
for i in range(time):
self.find_elements(locator)[index].send_keys(key)
def keyboard_delete(self, locator, index=0, string=None):
"""
清空输入框操作,全选之后再删除
"""
ele = self.find_elements(locator)[index]
if string: # 适用于得先有内容,删除后才会出错误提示的输入框的验证
ele.send_keys(string)
ele.send_keys(Keys.COMMAND if platform.system() == "Darwin" else Keys.CONTROL, "a")
return ele.send_keys(Keys.DELETE)
# 等待元素消失
def is_not_visible(self, locator, timeout=40):
WebDriverWait(self.driver, timeout).until_not(EC.visibility_of_element_located(locator))
# 判断元素是否存在
def is_element_exist(self, locator):
try:
self.find_element(locator)
return True
except:
return False
# 读取文件内容
def get_file_content(self, locator, sheet_name):
# 读取表格内容
table_open = xlrd.open_workbook(locator)
# 获取sheet页的行列数
table = table_open.sheet_by_name(sheet_name)
return table.row_values(0)
def refresh_page(self):
self.driver.refresh()
def element_text(self, locator):
# 获取元素标签之间的文本
return self.driver.find_element_by_xpath(locator).text
def delete_n_times(self, locator, index=0, times=5, string=None):
# 全选-删除的替代方法,因为前者有些场景不好使
ele = self.find_elements(locator)[index]
if string: # 适用于得先有内容,删除后才会出错误提示的输入框的验证
ele.send_keys(string)
for i in range(times):
ele.send_keys(Keys.BACK_SPACE)
def move_im_page(self, locator):
web_element = self.find_element(locator)
ActionChains(self.driver).move_to_element(web_element).perform()
def upload_file(self, locator, file_path, index=0, label="input"):
"""上传文件,如果是input,直接sendkeys"""
if label == "input":
return self.driver.find_element(*locator).send_keys(file_path)
else:
""""""
# pyautogui.write(file_path)
# pyautogui.press('enter', presses=2)
pass
def wait_for_display(self, locator, is_show=True):
"""
:param locator:
:param is_show: True-locator显示 False-locator在DOM中存在
:return:
"""
try:
if is_show:
WebDriverWait(self.driver, 20).until(EC.visibility_of_element_located(locator))
else:
WebDriverWait(self.driver, 20).until(EC.presence_of_element_located(locator))
except:
raise Exception("元素%s未找到" % locator)
def wait_for_text_appear(self, locator, index=0):
WebDriverWait(self.driver, 20).until(lambda d: d.find_elements(*locator)[index].text != '')
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化