2023-07-31|閱讀時間 ‧ 約 10 分鐘

【筆記】Selenium的三種等待方式

為了更好的讓程式運行,或多或少會需要使用等待方式,順利的讓driver取得元素後順利運行,本篇會提到Selenium的三種等待方式,以及常用的操作語法。

等待方式有三種,分別是強制等待、隱性等待、顯性等待:

強制等待

from time import sleep ​
#強制等待10秒​
sleep(10)

強制等待在不管任何情況下,等待設定的時間,簡單易用,等待期間會完全暫停程式的執行,可用於單純的等待場景。

缺點:因為是無條件的固定等待時間,在一些比較複雜的情況下無法設定自己想要的情境,如果使用強制等待的目的是讓頁面某個元素出現,即便元素出現了,也是要繼續等待。


隱性等待

#隱性等待10秒​
driver.implicitly_wait(10)

隱性等待不用導入任何套件,是一個全局設定,整個WebDriver都適用,當等待元素出現在頁面時,就會繼續執行後面的程式,或是等待設定的秒數。

可以跟顯性等待混用,會取時間長的那個。

缺點:等待時間不夠精確,每個場景所需要的等待時間不一定一樣,沒辦法個別針對場景進行設定等待時間,會造成資源不必要的浪費,另外也沒有辦法特定等待條件:比如點一個按鈕,才會出現提示框,這種隱性等待就沒有辦法處理。


顯性等待

#顯性等待​
from selenium.webdriver.support.ui import WebDriverWait
#預期條件函數,網頁元素在瀏覽器中的的出現、可見、可點擊
from selenium.webdriver.support import expected_conditions
#等待超時異常處理
from selenium.common.exceptions import TimeoutException

#創造一個顯性等待,等待時間20秒,每1秒檢查一次、忽略找不到元素的錯誤​
driver_wait = WebDriverWait(driver, timeout=20, poll_frequency=1, ignored_exceptions=[NoSuchElementException])

顯性等待可以設定許多條件,來達到完全我們需要的場景,明確等待某個特定條件,等出現後才會去執行:


timeout,等待時間,以秒為單位,強制等待跟隱性等待的等待時間也是以秒為單位。

poll_frequency,指定等待條件檢查的頻率,以秒為單位,預設值是0.5秒,可以不設定,如果不設定的情況下,那WebDriver會按照預設值每0.5秒檢查一次元素是否出現,有設定則按照預設值。

ignored_exceptions,在等待期間希望忽略的例外錯誤,有些錯誤會導致程式的中斷,它可以很好的讓程式順利運行,常見的忽略類型如下:

  • NoSuchElementException:找不到元素,就是你的元素定位定錯了,可能多字或少字,或是方法錯了,比如NAME你用ID去搜。


  • TimeoutException:在設定的等待時間內仍找不到元素,有可能未加載完全或是其他原因導致。


  • StaleElementReferenceException:訪問已不存在的元素,原先存在的元素,因為進行了某些操作,該元素不見或是刷新頁面導致。


  • ElementNotVisibleException:當元素存在但不可見時,比如頁面把元素藏起來了,display: none 或是visibility: hidden,或是在頁面以外,需要往下滑動才會看到。


  • ElementNotSelectableException:當元素存在但不可點擊,比如登入按鈕需要帳號密碼都輸入才能點登入,如果帳號密碼沒有輸入時,就會出現此情況。

顯性等待語法我們可以簡化成:

#去除掉​參數文字,簡化的情況下,順序一定要是 時間、頻率、忽略例外錯誤
driver_wait = WebDriverWait(driver, 20, 0.5, [NoSuchElementException])

如果想同時忽略多個例外錯誤,直接後面繼續加就可以了:

#同時忽略多個錯誤
driver_wait = WebDriverWait(driver, 20, 1, [NoSuchElementException, ElementNotVisibleException, StaleElementReferenceException])


顯性等待實際使用

#這裡我們拿expected_conditions的字首e跟c出來取別名叫做EC,不然整串程式碼太長了
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
from selenium.common.exceptions import TimeoutException

​driver.get("https://www.google.com/")

#等待時間20秒,搜尋頻率1秒一次​
driver_wait = WebDriverWait(driver,20,1)

#顯性等待抓取元素​
search_box = driver_wait.until(EC.presence_of_element_located((By.NAME,"q")))

#隱性等待抓取元素​(對照組)
search_box = driver.find_element(By.NAME,"q")

說明:

1.創建WebDriverWait的物件時,需要有兩個參數是必要的,分別是瀏覽器的控制跟等待時間,這裡我們瀏覽器的控制是"driver",後面必填的是等待時間(timeout),至於頻率跟忽略例外錯誤是選配,可加可不加。

2.需要三層( )的原因是:

driver_wait.until( ) 第一層,用來指示要使用顯性等待。

EC.presence_of_element_located( )第二層,表示要使用的方法,像這裡是使用"元素出現"這個等待條件。

(By.NAME,"q")第三層,定位元素本身作為一種參數,外面需要一層套用在第二層上。

以下是 expected_conditions,或是說顯性等待常見的幾種等待條件:

presence_of_element_located:元素出現,元素存在DOM中並可以使用元素定位方法取得,字尾"located"指的是Locator(元素定位方法),像是(By.NAME,"皮卡丘")。

#​presence_of_element_located
search_box = driver_wait.until(EC.presence_of_element_located((By.NAME,"q")))


presence_of_all_elements_located:所有元素出現,元素存在DOM,並透過元素定位方法,把指定的元素都找出來,並形成一個陣列。

#​presence_of_all_elements_located
search_results = driver_wait.until(EC.presence_of_all_elements_located((By.CSS_SELECTOR, "div.g")))


visibility_of_element_located:元素可見,元素存在瀏覽器畫面上,即元素沒有被隱藏(display:none、visibility:hidden),並且高寬都大於0,可用Locator定位。

#​visibility_of_element_located
search_box = driver_wait.until(EC.visibility_of_element_located((By.NAME,"q")))


element_to_be_clickable:元素可點擊,元素存在瀏覽器畫面,沒有被隱藏,並且可點擊,可用Locator定位。

#​element_to_be_clickable
search_box = driver_wait.until(EC.element_to_be_clickable((By.NAME,"q")))
search_box.click()


text_to_be_present_in_element:文本出現,等待網頁DOM可見,並且指定的元素出現特定的文本。

#​text_to_be_present_in_element
search_box = driver_wait.until(EC.text_to_be_present_in_element((By.ID, "pikachu"), "皮卡丘"))


alert_is_present:出現彈出窗口,當瀏覽器畫面出現彈窗時,做相應的處理。

#​alert_is_present,出現彈窗,印出提示,並接受
alert = driver_wait.until(EC.alert_is_present())
alert_text = alert.text
print("彈窗內容顯示:", alert_text)
alert.accept()


註:DOM,文件物件模型(Document Object Model),簡單來說就是瀏覽器開發者模式中,元素分頁那頁的內容。


至於顯性等待的缺點:它有點複雜



分享至
成為作者繼續創作的動力吧!
© 2024 vocus All rights reserved.