上面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()