Selenium廣泛應用于自動化測試和自動化業務開發,同時在網絡爬蟲中也有較多的應用,使用Selenium有兩個核心的問題:第一個是如何在爬蟲領域不被識别出來,另一個是在自動化領域如何解決逾時加載的問題。
今天來總結一下處理Selenium在自動化業務中的逾時加載,讓程式不在奔潰,同時能準确的擷取資訊。
首先需要區分兩種逾時情況,一種是頁面加載出現的逾時,一種是擷取頁面元素的逾時。
對于頁面加載出現的逾時,Selenium提供了兩個設定:
driver.set_page_load_timeout() # 設定頁面加載逾時
driver.set_script_timeout() # 設定頁面異步js執行逾時
set_page_load_timeout是用于設定頁面加載逾時,如下圖在指定時間内未加載出頁面則會報錯。
set_script_timeout,用于execute_async_script()執行的異步js逾時報錯。
注意:使用set_page_load_timeout時候,當頁面未加載出任何東西的時候(往往是html源碼未加載),因為逾時而停止,會導緻driver失效,後面的driver都不能操作,是以逾時設定應該至少保證頁面内容加載出來一部分,設定逾時不宜過短,如下圖在頁面此種狀态下停止加載後driver失效。
頁面加載逾時在打開新頁面、頁面重新整理、跳轉等方法執行中會起作用,對于頁面異步加載逾時問題可以配合使用js停止,該js文法如下:
window.stop()
該方法類似在浏覽器上點選停止載入按鈕,如果頁面在載入圖檔或架構(iframe)時間過長,我門可以使用該方法來停止載入。
第二種是擷取頁面元素的逾時,又分為隐式等待(implicit) 和 顯示等待(explicit)。
隐式等待(implicit)
隐式等待是設定全局的查找頁面元素的等待時間,在這個時間内沒找到指定元素則抛出異常,隻需設定一次,文法如下:
driver.implicitly_wait(time)
顯示等待(explicit)
顯式等待是使用頻率最高的擷取頁面元素逾時設定,其原理是通過設定一個最大時間和一個周期時間,按照周期時間來檢測是否出現等待元素,直到達到了最大等待時間。
顯示等待的基本文法如下:
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.common.by import By
from selenium import webdriver
driver = webdriver.Chrome()
WebDriverWait(driver, 3).until(EC.presence_of_element_located((By.ID, 'wrapper')))
WebDriverWait(driver, 3).until_not(EC.presence_of_element_located((By.ID, 'wrapper1')))
其中WebDriverWait用來給指定driver設定逾時時間,until、until_not有兩個參數method、message,method是EC即expected_conditions類提供的預先判斷條件,message是在逾時發生時候的提示資訊。
until用來檢測指定元素是否出現,如果在逾時時間内出現則傳回選擇器資訊,否則報出TimeoutException異常。
until_not用于檢測指定元素是否消失,如果在逾時時間内消失則傳回True,否則會報出TimeoutException異常。
method是EC即expected_conditions類提供的預先判斷條件如下:
WebDriverWait(driver,10).until(EC.title_is(u"百度一下,你就知道"))
# 判斷title,傳回布爾值
WebDriverWait(driver,10).until(EC.title_contains(u"百度一下"))
# 判斷title,傳回布爾值
WebDriverWait(driver,10).until(EC.presence_of_element_located((By.ID,'kw')))
# 判斷某個元素是否被加到了dom樹裡,并不代表該元素一定可見,如果定位到就傳回WebElement
WebDriverWait(driver,10).until(EC.visibility_of_element_located((By.ID,'su')))
# 判斷某個元素是否被添加到了dom裡并且可見,可見代表元素可顯示且寬和高都大于0
WebDriverWait(driver,10).until(EC.visibility_of(driver.find_element(by=By.ID,value='kw')))
# 判斷元素是否可見,如果可見就傳回這個元素
WebDriverWait(driver,10).until(EC.presence_of_all_elements_located((By.CSS_SELECTOR,'.mnav')))
# 判斷是否至少有1個元素存在于dom樹中,如果定位到就傳回清單
WebDriverWait(driver,10).until(EC.visibility_of_any_elements_located((By.CSS_SELECTOR,'.mnav')))
# 判斷是否至少有一個元素在頁面中可見,如果定位到就傳回清單
WebDriverWait(driver,10).until(EC.text_to_be_present_in_element((By.XPATH,"//*[@id='u1']/a[8]"),u'設定'))
# 判斷指定的元素中是否包含了預期的字元串,傳回布爾值
WebDriverWait(driver,10).until(EC.text_to_be_present_in_element_value((By.CSS_SELECTOR,'#su'),u'百度一下'))
# 判斷指定元素的屬性值中是否包含了預期的字元串,傳回布爾值
#WebDriverWait(driver,10).until(EC.frame_to_be_available_and_switch_to_it(locator))
# 判斷該frame是否可以switch進去,如果可以的話,傳回True并且switch進去,否則傳回False注意這裡并沒有一個frame可以切換進去
WebDriverWait(driver,10).until(EC.invisibility_of_element_located((By.CSS_SELECTOR,'#swfEveryCookieWrap')))
# 判斷某個元素在是否存在于dom或不可見,如果可見傳回False,不可見傳回這個元素注意#swfEveryCookieWrap在此頁面中是一個隐藏的元素
WebDriverWait(driver,10).until(EC.element_to_be_clickable((By.XPATH,"//*[@id='u1']/a[8]"))).click()
# 判斷某個元素中是否可見并且是enable的,代表可點選
driver.find_element_by_xpath("//*[@id='wrapper']/div[6]/a[1]").click()
WebDriverWait(driver,10).until(EC.element_to_be_clickable((By.XPATH,"//*[@id='wrapper']/div[6]/a[1]"))).click()
WebDriverWait(driver,10).until(EC.staleness_of(driver.find_element(By.ID,'su')))
# 等待某個元素從dom樹中移除
WebDriverWait(driver,10).until(EC.element_to_be_selected(driver.find_element(By.XPATH,"//*[@id='nr']/option[1]")))
# 判斷某個元素是否被選中了,一般用在下拉清單
WebDriverWait(driver,10).until(EC.element_selection_state_to_be(driver.find_element(By.XPATH,"//*[@id='nr']/option[1]"),True))
# 判斷某個元素的選中狀态是否符合預期
WebDriverWait(driver,10).until(EC.element_located_selection_state_to_be((By.XPATH,"//*[@id='nr']/option[1]"),True))
# 判斷某個元素的選中狀态是否符合預期
driver.find_element_by_xpath(".//*[@id='gxszButton']/a[1]").click()
instance = WebDriverWait(driver,10).until(EC.alert_is_present())
# 判斷頁面上是否存在alert,如果有就切換到alert并傳回alert的内容
instance.accept()
# 關閉彈窗
部配置設定置來源參考:https://www.cnblogs.com/wxcx/p/8948280.html
注意:顯示等待和隐式等待都存在的,按照其中逾時時間設定最大的方式來執行。