Selenium無法定位元素的九種解決方案
一、frame/iframe表單嵌套
WebDriver只能在一個頁面上對元素識別與定位,對於frame/iframe表單內嵌的頁面元素無法直接定位。
解決方法:driver.switch_to.frame(
id/name/obj
)
。
switch_to.frame()默認可以直接取表單的id或name屬性。如果沒有可用的id和name屬性,可以先定位到frame/iframe,再將定位對象傳給switch_to.frame(對象)方法。
xf = driver.find_element_by_xpath('//*[@class="if"]')
driver.switch_to.frame(xf)
...
driver.switch_to.parent_frame()
切到父frame。影響性能,可以提給開發,讓其改進。driver.switch_to.default_content()
跳回最外層的頁面
二、頁面跳轉到新的標簽頁,或者彈出的警告框等
在頁面操作過程中有時候點擊某個鏈接會彈出新窗口,這時就需要切換焦點到新窗口上進行操作。
解決方法1:driver.switch_to.window(
window_handle
)
切換到新窗口。
首先獲取當前窗口的句柄driver.current_window_handle
,接着打開彈出新窗口,獲得當前打開的所有窗口的句柄driver.window_handles
。通過for循環遍歷handle,如果不等於第一次打開窗口的句柄,那么一定是新窗口的句柄,因為執行過程只打開了兩個窗口;改變條件,如果等於第一次打開窗口的句柄,那么可以切換回第一次打開的窗口。
解決方法2:對於JavaScript生成的alert、confirm以及prompt,無法使用前端工具對彈出窗口進行定位的,使用driver.switch_to.alert
方法定位彈出框。alert的方法有:
.accept() '等同於點擊“確認”或“OK”'
.dismiss() '等同於點擊“取消”或“Cancel”'
.text '獲取alert文本內容,對有信息顯示的alert框'
.send_keys(text) '發送文本,對有提交需求的prompt框'
.authenticate(username,password) '驗證,針對需要身份驗證的alert'
三、頁面元素失去焦點導致腳本運行不穩定
解決方法:driver.switch_to.active_element
遇到腳本不穩定,有時會失去焦點導致測試失敗的情況下,可以先切到焦點元素再進行操作。注意.active_element后面不帶括號()。
下面是一個參考案例。
'最初的 “右擊鼠標 → 新建文件夾 → 輸入文件夾名稱” 的代碼'
l = driver.find_element_by_id('pm_treeRoom_1_span')
ActionChains(driver).context_click(l).perform()
driver.find_element_by_class_name('fnew').click()
time.sleep(2)
driver.find_element_by_xpath('//*[@id="pm_treeRoom_1_ul"]/li[...]').send_keys('filename')
time.sleep(2)
結果這種操作總會導致輸入框失去焦點,直接消失,更不能send_keys進去了,直接報錯。
'修改后的代碼如下'
driver.find_element_by_class_name('fnew').click()
time.sleep(2)
driver.switch_to.active_element.send_keys('filename')
time.sleep(2)
四、使用Xpath或CSS定位
find_element_by_xpath("//標簽[屬性='值']")
使用Xpath/CSS方法,非常適合定位屬性值動態生成、不容易定位的元素。如果不想指定標簽,則可以使用“*”代替,使用xpath不局限於id、name和class這三個屬性,元素的任意屬性值都可以使用,只要它能唯一的標識一個元素。
解決方法1:如果一個元素沒有唯一屬性,那么我們可以一級一級向上查找,直到找到可以唯一定位元素的屬性,再向下查找其子元素。find_element_by_xpath("//form[@id='form']/span[2]/input")
首先通過唯一標識屬性id=form定位最外層元素,接着找到最外層元素下的第2個span標簽的元素為父元素,最后向下查找定位到父元素下標簽為input的子元素。
解決方法2:如果一個屬性不能唯一地區分一個元素,那么使用多個屬性來唯一地定位一個元素。find_element_by_xpath("//input[@id='kw' and @class='su']/span/input")
首先找到標簽為input,id=kw且class=su的元素,接着找到其下標簽為span的子元素,繼續向下查找找到標簽為input的子元素。
解決方法3:檢查Xpath描述是否有誤,導致無法定位到元素。
五、頁面還沒有加載出來,就對頁面上的元素進行的操作
因為加載元素延時造成的腳本失敗,我們可以通過設置等待時間來提升自動化腳本的穩定性。
解決方法1:WebDriverWait()
顯示等待。等待單個的元素加載,通常配合until()
、until_not()
方法使用。
WebDriverWait(driver,timeout,poll_frequency=0.5,ignored_exceptions=None) - driver - 傳入WebDriver實例,必填 - timeout - 最長等待時間,必填 - poll_frequency - 調用`until`/`until_not`方法的時間間隔,默認為0.5秒,可省。 - ignored_exceptions - 忽略異常,默認僅包含NoSuchElementException,可省。
WebDriverWait(driver,10).until(method,message='') '等待目標出現' WebDriverWait(driver,5,1).until_not(method,