import importlib import time from selenium.common.exceptions import StaleElementReferenceException, ElementClickInterceptedException from selenium.webdriver.remote.webelement import WebElement from selenium.webdriver.support.wait import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.remote.webdriver import WebDriver SimpleActions = ['clear()', 'send_keys()', 'click()', 'submit()', 'size', 'text', 'is_displayed()', 'get_attribute()'] complexActions = ['iframe()', 'select()', 'option()'] # 默认超时时间10秒 DEFAULT_TIMEOUT = 10 # 默认重试次数 DEFAULT_RETRY = 30 class BasePage: retry_number = 0 # 初始化方法 def __init__(self, driver: WebDriver): """构造方法,传入webdriver""" self.driver = driver # def _get_page_elem(self, elem): # """获取定位元素的by,以及操作action""" # for each in self.elements: # if each['name'] == elem: # self.loc = each['loc'] # if each['action'] is not None: # self.action = each['action'] # else: # self.action = None # if 'optionsLoc' in each: # self.optionsLoc = each['optionsLoc'] # else: # self.optionsLoc = None # if 'wait' in each: # self.wait = each['wait'] # else: # self.wait = None # # def oper_elem(self, elem, args=None): # self._get_page_elem(elem) # cmd = self._selenium_cmd('find_element', args) # return eval(cmd) # # def oper_elems(self, elem, args=None): # self._get_page_elem(elem) # cmd = self._selenium_cmd('find_elements', args) # return eval(cmd) # # def _selenium_cmd(self, find_type='find_element', args=None): # """拼接selenium查找命令,查找单个元素时find为'find_element',多个元素时为'find_elements'""" # cmd = 'self.driver.' + find_type + '(*self.loc)' # if self.action: # cmd = 'self.' + self.action # if args: # cmd = cmd[:-1] + 'args' + ')' # return cmd # # def iframe(self): # self.driver.switch_to.frame(self.driver.find_element(*self.loc)) # # def click(self): # if self.wait: # wait = WebDriverWait(self.driver, self.wait, 0.5) # wait.until(EC.presence_of_element_located(self.loc)).click() # else: # self.driver.find_element(*self.loc).click() # # # 使用js语句点击 # def click_js(self): # item = self.driver.find_element(*self.loc) # self.driver.execute_script("arguments[0].click();", item) # # def send_keys(self, text): # wait = WebDriverWait(self.driver, 10, 0.5) # wait.until(EC.presence_of_element_located(self.loc)).send_keys(text) # # def text(self): # wait = WebDriverWait(self.driver, 10, 0.5) # return wait.until(EC.presence_of_element_located(self.loc)).text # def select(self, select_loc, options_loc, item): """ 选择传入的选项 :param select_loc: 选择框定位 :param options_loc: 选项定位 :param item: 选项 :return: """ # 点击选择框对象 self.click(select_loc, timeout=10) # 获取所有选项 options = self.get_eles(options_loc, timeout=10) for option in options: if option.text == item: option.click() break # # def value_js(self): # """ # 使用js语句获取value值 # :return: # """ # # 等待对象 # wait = WebDriverWait(self.driver, 10, 0.5) # input_box = wait.until(EC.presence_of_element_located(self.loc)) # input_value = self.driver.execute_script("return arguments[0].value", input_box) # return input_value # # def option(self, text): # """ # 点击传入的选项 # :param text: # :return: # """ # wait = WebDriverWait(self.driver, 10, 0.5) # wait.until(EC.presence_of_all_elements_located(self.loc)) # options = self.driver.find_elements(*self.loc) # for option in options: # if option.text == text: # option.click() # 元素定位 def goto(self, url): """访问url""" self.driver.get(url) def get_ele(self, loc, timeout=None) -> WebElement: """ 获取元素 :param loc: 元素定位 :param timeout: 超时时间 :return: """ if timeout: return self.wait_visible(loc, timeout) else: return self.driver.find_element(*loc) def get_eles(self, loc, timeout=None): """ 获取多个元素 :param loc: 元素定位 :param timeout: 超时时间 :return: """ if timeout: return self.wait_visible(loc, timeout=timeout, find_type="elements") else: return self.driver.find_elements(*loc) def clear(self, loc, timeout=None): """ 清除文本框内容 :param loc: :param timeout: :return: """ ele = self.get_ele(loc, timeout=timeout) ele.clear() def fill(self, loc, text, timeout=None): """页面输入""" ele = self.get_ele(loc, timeout=timeout) # 先清除文本框内容 ele.clear() # 填写内容 ele.send_keys(text) def wait_visible(self, loc, timeout=DEFAULT_TIMEOUT, find_type="element") -> WebElement: """ 等待元素可见 :param loc: 元素定位 :param timeout: 等待时间 :param find_type: 等待元素的类型 :return: """ wait = WebDriverWait(self.driver, timeout=timeout) element = None if find_type == "element": element = wait.until(EC.visibility_of_element_located(loc)) elif find_type == "elements": element = wait.until(EC.visibility_of_all_elements_located(loc)) return element def click(self, loc, timeout=None): """ 点击元素 :param loc: 元素定位 :param timeout: 超时时间 :return: """ try: if timeout: ele = self.wait_clickable(loc, timeout=timeout) ele.click() else: ele = self.driver.find_element(*loc) ele.click() self.retry_number = 0 except (StaleElementReferenceException, ElementClickInterceptedException): if self.retry_number >= DEFAULT_RETRY: return time.sleep(1) self.retry_number += 1 self.click(loc, timeout=timeout) def click_js(self, loc, timeout=None): """ JavaScript点击元素 :param loc: :param timeout: :return: """ item = self.get_ele(loc, timeout=timeout) self.driver.execute_script("arguments[0].click();", item) def wait_clickable(self, loc, timeout=DEFAULT_TIMEOUT) -> WebElement: """ 等待元素可点击 :param loc: 元素定位 :param timeout: 超时时间 :return: """ wait = WebDriverWait(self.driver, timeout=timeout) element = wait.until(EC.element_to_be_clickable(loc)) return element def equals(self, loc, text): """ 判断元素的value或者text是否与text相等 :param loc: :param text: :return: """ # 先获取value ele_value = self.get_ele(loc, timeout=10).get_attribute("value") # 如果为None则通过value_js获取value值 if not ele_value: ele_value = self.get_value_js(loc, timeout=10) # 如果还为空则获取text if not ele_value: ele_value = self.get_ele(loc, timeout=10).text return ele_value == text def contains(self, loc, text): """ 判断元素的value或者text包含text :param loc: :param text: :return: """ # 先获取value ele_value = self.get_ele(loc).get_attribute("value") # 如果为None则通过value_js获取value值 if not ele_value: ele_value = self.get_value_js(loc) # 如果还为空则获取text if not ele_value: ele_value = self.get_ele(loc).text return text in ele_value # 多个元素定位 def get_elements_wait(self, locator): wait = WebDriverWait(self.driver, 10, 0.5) wait.until(EC.presence_of_element_located(locator)) return self.driver.find_elements(*locator) # 在指定元素中定位元素 def get_element_in(self, element, locator): return element.find_element(*locator) # 在指定元素中定位多个元素 def get_elements_in(self, element, locator): return element.find_elements(*locator) # 元素定位 def get_element_wait(self, locator): wait = WebDriverWait(self.driver, 10, 0.5) wait.until(EC.presence_of_element_located(locator)) return self.driver.find_element(*locator) def click_js_wait(self, *locator): item = self.get_element_wait(*locator) self.driver.execute_script("arguments[0].click();", item) def click_element_js(self, element): """ 使用js点击元素 :param element: 要点击的元素 :return: """ self.driver.execute_script("arguments[0].click();", element) # # 点击 # def click(self, locator): # """ # 点击元素 # :param locator: 元素定位 # :return: # """ # self.get_element(locator).click() def click_wait(self, *locator): self.get_element_wait(*locator).click() # # 输入 # def fill(self, text, locator): # """ # 输入内容 # :param text: 内容 # :param locator: 元素定位 # :return: # """ # self.get_element(locator).send_keys(text) def send_text_wait(self, text, *locator): self.get_element_wait(*locator).send_keys(text) def get_value_js(self, loc, timeout=None): """ 执行JavaScript获取value值 :param timeout: :param loc: :return: """ ele = self.get_ele(loc, timeout=timeout) value = self.driver.execute_script("return arguments[0].value", ele) return value def get_input_value_js_wait(self, *locator): input_box = self.get_element_wait(*locator) input_value = self.driver.execute_script("return arguments[0].value", input_box) return input_value # 清除 def clear_text(self, *locator): self.get_element(*locator).clear() def clear_text_wait(self, *locator): self.get_element_wait(*locator).clear() # 表单切换 def switch_iframe(self, loc): """ 切换表单 :param loc: 表单定位 :return: """ # 获取到iframe元素 iframe = self.get_ele(loc, timeout=10) self.driver.switch_to.frame(iframe) def switch_parent_iframe(self): """ 切换到上一层的iframe :return: """ self.driver.switch_to.parent_frame() def switch_iframe_wait(self, locator): self.driver.switch_to.frame(self.get_element_wait(locator)) # 窗口切换 def switch_window(self, n): self.driver.switch_to.window(self.driver.window_handles[n]) # 检查元素是否可见可点击 def check_clickable(self, *locator): wait = WebDriverWait(self.driver, 10, 0.5) try: e = wait.until(EC.element_to_be_clickable(locator)) if e is not None: return True except: pass return False # 等待元素出现 def wait_appear(self, *locator): wait = WebDriverWait(self.driver, 10, 0.5) try: e = wait.until(EC.presence_of_element_located(locator)) if e is not None: return True except: pass return False # 滑动页面 def scroll_by(self, num): self.driver.execute_script(f"window.scrollBy(0, {num})") def scroll_to_top(self): self.driver.execute_script("window.scrollTo(0, 0);") # 滑动到底部 def scroll_to_bottom(self): self.driver.execute_script("window.scrollBy(0,document.body.scrollHeight);") # 滚动到对应元素上 def scroll_to_element(self, ele, timeout=None): # 获取元素的坐标 element_top = self.driver.execute_script("return arguments[0].getBoundingClientRect().top;", ele) # 获取视口的高度 viewport_height = self.driver.execute_script("return window.innerHeight;") # 计算滚动距离 scroll_distance = element_top + viewport_height - ele.size['height'] # 执行滚动操作 self.driver.execute_script(f"window.scrollTo(0, {scroll_distance});") WebDriverWait(self.driver, 10).until(EC.visibility_of(ele)) # 截取当前窗口保存为图片 def get_png(self): """截取当前窗口保存为图片""" return self.driver.get_screenshot_as_png() def goto_new_table(self, url): """ 打开一个新的标签页,并跳转到指定的url :return: """ # 打开新标签页 self.driver.execute_script("window.open()") # 切换到新的标签页 self.switch_window(-1) # 在新标签页中加载指定url self.driver.get(url) def elements_is_visibility(self, locator): """ 判断是否至少有一个元素在页面中可见 :param locator: :return: """ wait = WebDriverWait(self.driver, 10, 0.5) return wait.until(EC.visibility_of_any_elements_located(locator)) def add_elements(self, ele): """ 在elements中新增元素 :param ele: :return: """ self.elements.append(ele) def get_page_elements(page): """ 动态加载页面定义文件,获取文件中定义的元素列表elements :param page: :return: """ elements = None if page: try: m = importlib.import_module(page) elements = m.elements except Exception as e: pass return elements