上面4个小节就是基本UI自动化框架了
后续小节围绕框架做细节分析
UI自动化最重要的一点就是定位元素,所以第一个分析的是selenium封装类,也就是上文中提到的webdriver_base.py。
元素定位方法参考 https://www.cnblogs.com/eastonliu/p/9088301.html
接下来根据selenium源码来看下定位元素实现原理
一、selenium定位元素源码
主要讲下面5种常见的定位方法
1、id定位: find_element_by_id()
2、name定位: find_element_by_name()
3、class定位:find_element_by_class_name()
4、xpath定位:find_element_by_xpath()
5、CSS定位:find_element_by_css_selector()
首先大家可以在点击进去看看他们调用的会是同一个方法(下图展示了id和xpath)
接着点击find_element方法看看具体实现(实现代码见下图)
当使用id、name、class定位时,实际上selenium只是对value做了处理,还是通过css来定位(所以实际上selenium页面元素定位分xpath和css定位两块)
最后看看我们封装类具体实现元素定位
(1)、封装类find_element方法是调用selenium的find_element方法,并且在调用基础上多了一些验证
lambda driver: driver.find_element(*loc).is_displayed() 页面存在一些隐藏属性,可以通过该条语句获取
WebDriverWait(self.driver, 10).until 页面隐形等待10s,10s内查找不到则抛元素查找超时异常
(2)、定位完后主要的操作是输入文本和点击
输入文本:封装类send_keys方法是调用selenium的send_keys方法,并且在调用基础上多了输入框文本情况和异常捕获并截图
点击:封装类click方法是调用selenium的click方法,并且在调用基础上多了异常捕获并截图
(3)、为了方便元素定位,封装类定位元素设置统一入口loc_method方法,只需要调用loc_method,上面的元素定位方法都可以间接调用到
该方法4个参数
param eleLoc: 定位的元素路径 也就是id,xpath,css定位元素对应的路径
param action: 页面动作(输入文本,点击等等,可以自己扩展)
param method: 定位方式 目前支持CSS、XPATH、ID、NAME、CLASS(可以自己扩展),默认为CSS
param text: 如果是需要文本信息输入校验,才需要用到
举例:
百度输入框原先 driver.find_element_by_id("kw").send_keys("懒勺")
封装类后 loc_method("kw", "send_keys", method='id', text="懒勺")
百度点击搜索原先 driver.find_element_by_id("su").click()
封装类后 loc_method("su", "click", method='id')
def loc_method(self, eleLoc, action, method='CSS', text=None): """ 通用元素定位方法主入口 :param eleLoc: 定位的元素路径 :param action: 页面动作(输入文本,点击等等) :param method: 定位方式(css, path)提示:id、name、class属性都可以用css定位到,默认为CSS :param text: 如果是需要文本信息输入校验,才需要用到 :return: """ #loc放到selenium的driver.find_element方法就会自动识别元素 if str(method).upper() == 'CSS': loc = (By.CSS_SELECTOR, eleLoc) elif str(method).upper() == 'XPATH': loc = (By.XPATH, eleLoc) elif str(method).upper() == 'ID': loc = (By.ID, eleLoc) elif str(method).upper() == 'NAME': loc = (By.NAME, eleLoc) elif str(method).upper() == 'CLASS': loc = (By.CLASS_NAME, eleLoc) else: loc = None try: if loc != None: if action == 'click': self.click(loc) elif action == 'send_keys': self.send_keys(text, loc) elif action == 'select_by_text': self.select_by_text(text, loc) elif action == 'select_by_index': self.select_by_index(text, loc) elif action == 'select_by_value': self.select_by_value(text, loc) elif action == 'get_element_text': return self.get_element_text(loc) elif action == 'get_element_attribute': return self.get_element_attribute(text, loc) elif action == 'text_in_element': return self.text_in_element(text, loc) elif action == 'value_in_element': return self.value_in_element(text, loc) else: logger.error("action错误:请确认action值:%s" % action) else: logger.error("method错误:请确认method值:%s" % method) except Exception as e: logger.error(e)
二、封装类初始化方法:
1、判断获取是否已经打开浏览器驱动,已经存在则不在创建新浏览器驱动,防止打开多个浏览器界面
2、获取驱动目前只写了谷歌,可在else里面扩展火狐,IE
def __init__(self): global driver # 如果driver不为空,直接使用原来的driver if driver != None: self.driver = driver return # 获取驱动 chromeDriverPath = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))), 'driver', 'chromedriver.exe') option = webdriver.ChromeOptions() option.add_argument("disable-infobars") # 获取配置文件 sysConfig = YamlUtil('sysconfig.yaml').read_yaml() # 找浏览器的名字 browserName = sysConfig['browser']['browserName'] if str(browserName).lower() == 'chrome': # 获取谷歌的驱动 driver = webdriver.Chrome(executable_path=chromeDriverPath, chrome_options=option) self.driver = driver else: logger.error("暂不支持谷歌以外的驱动") raise Exception("暂不支持谷歌以外的驱动") if self.driver == None: logger.error("打开浏览器驱动失败") raise Exception("打开浏览器驱动失败") self.maximize_window()
三、封装类其他页面操作方法
主要列几个常用的(其他方法也都以注释)
1、下拉框操作 select_by_index、select_by_value
2、切换窗口 switch_to_next_window、switch_to_next_frame
3、执行js脚本 execute_script
4、退出浏览器 quit_browser
def select_by_index(self, index, *loc): # 通过index 下标取select ele = self.find_element(*loc) Select(ele).select_by_index(index) sleep(1) def select_by_value(self, value, *loc): # 通过value值取select ele = self.find_element(*loc) Select(ele).select_by_value(value) sleep(1) def switch_to_next_window(self, currentHandle): # 当打开的窗口不是当前窗口,就切换 allHandles = self.driver.window_handles for handle in allHandles: if handle != currentHandle: self.driver.switch_to.window(handle) break def switch_to_next_frame(self, iframe): # 表单切换到iframe,其中iframe是id self.driver.switch_to.frame(iframe) def execute_script(self, js): #执行js命令 self.driver.execute_script(js) def quit_browser(self): # 退出浏览器,关闭所有窗口 self.driver.quit()