在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(r'http://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 time
time.sleep(3)
設定等待時間可以解決這個問題,缺點是需要設定較長的等待時間,案例多了測試就很慢,而且你不太清楚要等待多久,等待時間長了,浪費時間,等待時間短了,沒有作用。
推薦大家用智能等待,在某個時間範圍内,如果出現,就直接執行,如果沒有出現,就抛出timeout異常,如下所示:
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
driver = 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 webdriver
from selenium.webdriver.common.action_chains import ActionChains
driver = 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() #ok
driver.switch_to.alert.dismiss() #cancel
7. 窗體
有的時候,我們操作的時候,會打開另外的窗體,或者浏覽器的其它tab頁。
句柄已經切過去了,但是焦點還沒切過去,是以需要switch_to.window(),把焦點頁切過去,才能對目前頁進行操作。
思路是: 擷取所有句柄,傳回一個list,而要切的對象都是最後一個,所有可以用[-1]直接切過去。
如:
driver.switch_to.window(driver.window_handles[-1])