同學,你為什麼定位不到元素?
在UI自動化中,一般先要找到需要操作的元素對象,然後進行操作。
定位元素成功與否,決定了你的用例的成敗。所以定位元素很重要。
很多同學在用Selenium,Appium等做自動化的時候,有的時候卻總能碰到這個熟悉的錯誤:
NoSuchElementException)
排查了很久,也找不到原因。一下子就懵了,剛才還好好的,這是怎麼了?
UI 自動化,先天不足的就是不夠穩定。很多因素導致定位不到元素。
可能網速導致還還沒載入完全,你卻已經操作了。可能頁面渲染慢,資源還沒載入完全,特別是弱網情況下明顯。
可能有廣告等彈出框。可能你等待時間不夠,目標還沒出現,你卻先下手了。種種因素,讓你獲取不到元素,從而報錯。
下面我們來分析一下,找不到元素的原因有哪些,並找到解決方案。
1.Frame/Iframe原因定位不到元素:
這個是最常見的原因,首先要理解下frame的實質,frame中實際上是嵌入了另一個頁面,而webdriver每次只能在一個頁面識別,因此需要先定位到相應的frame,對那個頁面里的元素進行定位。解決方案:如果iframe有name或id的話,直接使用switch_to_frame(「name值」)或switch_to_frame(「id值」)。如下:driver=webdriver.Firefox()driver.get(rhttp://www.126.com/)driver.switch_to_frame(x-URS-iframe) #需先跳轉到iframe框架username=driver.find_element_by_name(email)username.clear()#driver.switch_to.frame() python3#driver.switch_to_frame() python2
操作完frame裡面的元素後,要跳出來,接著操作其它的元素。
driver.switch_to.default_content()
2.Xpath描述錯誤原因:
由於Xpath層級太複雜,容易犯錯。但是該定位方式能夠有效定位絕大部分的元素,建議掌握。 我們定位元素的原則是:越簡單越好。如果有id,name,class,css,link等,這是最簡單不過了的。如果實在不好定位,我們可以用xpath,xpath建議不要用絕對路徑,也不宜過長,一般用模糊匹配就可以了。如:find_element_by_xpath(「//標籤名[@屬性=』屬性值』]」)find_element_by_xpath("//*[@id=snake)]")
這個屬性可以是id,name,class等任意一種
也可以通過內容來匹配:如:find_element_by_xpath("//*[contains(text(),安蜀黍)]")
也可以通過組合匹配:
如:find_element_by_xpath("//*[contains(text(),安蜀黍) and @id=『snake]")
建議定位完了以後,用我教的那種辦法,在瀏覽器控制台檢驗一下。
3.頁面還沒有載入出來,就對頁面上的元素進行的操作:
這種情況一般說來,可以設置等待,等待頁面顯示之後再操作,這與人手工操作的原理一樣。設置一下顯式等待時間。import timetime.sleep(3)
設置等待時間可以解決這個問題,缺點是需要設置較長的等待時間,案例多了測試就很慢,而且你不太清楚要等待多久,等待時間長了,浪費時間,等待時間短了,沒有作用。
推薦大家用智能等待,在某個時間範圍內,如果出現,就直接執行,如果沒有出現,就拋出timeout異常,如下所示:
from selenium import webdriverfrom selenium.webdriver.common.by import Byfrom selenium.webdriver.support.ui import WebDriverWaitfrom selenium.webdriver.support import expected_conditions as ECdriver = webdriver.Chrome()driver.get("https://www.csdn.net/")try: element= WebDriverWait(driver,10).until(EC.presence_of_element_located((By.CSS_SELECTOR,iv.J_close.layer_close)))finally: driver.quit()
4. 不可見元素定位
有些元素,是需要hover在另外一個元素上,才顯示。是invisiable,disable的,如下拉列表等。所以我們先要將滑鼠移到其父節點上,顯示以後才對其定位。移動滑鼠可以這樣寫:from selenium import webdriverfrom selenium.webdriver.common.action_chains import ActionChainsdriver = webdriver.Chrome()ActionChains(driver).move_to_element(driver.find_element_by_id(父節點)).perform()element = driver.find_element_by_id("子節點")
5. 廣告頁面
見到廣告頁,不要怕,有些是彈框的,有些是浮動的頁面。基本都是能定位得到的。比如這種:driver.get("https://www.csdn.net/")time.sleep(5)driver.find_element_by_css_selector(div.J_close.layer_close).click()
又如這種:
driver.get("https://www.1688.com/")time.sleep(5)driver.find_element_by_css_selector(i.identity-icon.identity-close-icon).click()
都能定位得到,直接操作一下就可以了,也可以寫個公共的方法,來處理這些廣告或者彈框。
6. 彈出框
有的時候,會有彈出框來讓你confirm,你必須去點擊一下,否則頁面失去焦點,導致你無法操作Alert 彈出框:driver.switch_to.alert.accept() #okdriver.switch_to.alert.dismiss() #cancel
7. 窗體
有的時候,我們操作的時候,會打開另外的窗體,或者瀏覽器的其它tab頁。句柄已經切過去了,但是焦點還沒切過去,所以需要switch_to.window(),把焦點頁切過去,才能對當前頁進行操作。思路是: 獲取所有句柄,返回一個list,而要切的對象都是最後一個,所有可以用[-1]直接切過去。如:
driver.switch_to.window(driver.window_handles[-1])
在實踐中,可能會遇到各種問題,只有通過不斷積累,才能應付自如。
作者簡介:
Snake, 人稱安蜀黍,專職軟體測試10幾年,測試界的老司機。更多精彩,請關注微信公眾號:python愛好部落推薦閱讀:
※在寫Python的時候,你最喜歡用哪一款IDE?
※黃哥推薦學習Python 10本好書。
※Day 4-6, 列印、文件、函數
※怎樣寫出Pythonic的代碼
※Github上同學總結的機器學習和deeplearning方面的很全的資料