三種等待方式
簡介
在實際工作中等待機制可以保證程式碼的穩定性,保證程式碼不會受網速、電腦效能等條件的約束。
等待就是當執行程式碼時,如果頁面的渲染速度跟不上程式碼的執行速度,就需要人為的去限制程式碼執行的速度。
在做 Web 自動化時,一般要等待頁面元素載入完成後,才能執行操作,否則會報找不到元素等各種錯誤,這樣就要求在有些場景下加上等待。
最常見的有三種等待方式:隱式等待、顯式等待、強制等待,下面介紹以下這三種等待方式。
隱式等待
隱式等待的機制是:設定一個等待時間,輪詢查詢(預設 0.5 秒)元素是否出現,如果沒出現就丟擲異常。這也是最常見的等待方法。
隱式等待的作用是全域性的,是作用於整個 session 的生命週期,也就是說只要設定一次隱式等待,後面就不需要設定。如果再次設定隱式等待,那麼後一次的會覆蓋前一次的效果。
當在 DOM 結構中查詢元素,且元素處於不能立即互動的狀態時,將會觸發隱式等待。
Python 實現
self.driver.implicitly_wait(30)
Java 實現
driver.manage().timeouts().implicitlyWait(10,TimeUnit.SECONDS);
顯式等待
顯示等待的機制是:顯式等待是在程式碼中定義等待條件,觸發該條件後再執行後續程式碼,就能夠根據判斷條件進行等待。程式每隔一段時間進行條件判斷,如果條件成立,則執行下一步,否則繼續等待,直到超過設定的最長時間。示例程式碼如下:
Python 實現
匯入顯式等待
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions
...
# 設定10秒的最大等待時間,等待 (By.TAG_NAME, "title") 這個元素點選
WebDriverWait(driver, 10).until(
expected_conditions.element_to_be_clickable((By.TAG_NAME, "title"))
)
...
Java 實現
importorg.openqa.selenium.*;
importorg.openqa.selenium.chrome.ChromeDriver;
importorg.openqa.selenium.support.ui.ExpectedConditions;
importorg.openqa.selenium.support.ui.WebDriverWait;
importjava.time.Duration;
publicclass demo3{
publicstaticvoidmain(String[]args){
WebDriverdriver=newChromeDriver();
driver.get("https://ceshiren.com");
//顯示等待,直到元素(id為kw)出現,才停止等待
WebElementelement=(newWebDriverWait(driver,Duration.ofSeconds(5)))
.until(ExpectedConditions.presenceOfElementLocated(By.id("kw")));
driver.close();
//關閉瀏覽器程式
driver.quit();
}
}
這裡透過匯入 expected_conditions 這個庫來滿足顯式等待所需的使用場景,但是 expected_conditions 庫並不能滿足所有場景,這個時候就需要定製化開發來滿足特定場景。
實戰演示
假設:要判斷某個元素超過指定的個數,就可以執行下面的操作。
Python 實現
def ceshiren():
# 定義一個方法
def wait_ele_for(driver):
# 將找到的元素個數賦值給 eles
eles = driver.find_elements(By.XPATH, '//*[@id="site-logo"]')
# 放回結果
return len(eles) > 0
driver = webdriver.Chrome()
driver.get('https://ceshiren.com')
# 顯式等待10秒,直到 wait_ele_for 返回 true
WebDriverWait(driver, 10).until(wait_ele_for)
Java 實現
importorg.openqa.selenium.By;
importorg.openqa.selenium.WebDriver;
importorg.openqa.selenium.WebElement;
importorg.openqa.selenium.chrome.ChromeDriver;
importorg.openqa.selenium.support.ui.ExpectedConditions;
importorg.openqa.selenium.support.ui.WebDriverWait;
importjava.time.Duration;
importjava.util.List;
publicclass demo4{
publicstaticvoidmain(String[]args){
WebDriverdriver=newChromeDriver();
driver.get("https://ceshiren.com");
// 顯式等待,等待元素出現超過指定個數
WebDriverWaitwait=newWebDriverWait(driver,Duration.ofSeconds(10));
List<WebElement>elements=wait.until(ExpectedConditions.visibilityOfAllElementsLocated(By.xpath("//*[@id=\"site-logo\"]")));
intcount=elements.size();
if(count>0){
// 執行操作
System.out.println("元素超過指定個數");
}else{
System.out.println("元素未超過指定個數");
}
driver.quit();
}
}
強制等待
強制等待是使執行緒休眠一定時間。強制等待一般在隱式等待和顯式等待都不起作用時使用。示例程式碼如下:
Python 實現
# 等待十秒
time.sleep(10)
Java 實現
//等待1s
Thread.sleep(1000)
實戰演示
訪問測試人社群(https://ceshiren.com),點選分類,然後點選開源專案:
當點選分類時,元素還未載入完成,這裡就需要隱式等待。在點選開源專案時,元素已載入完成,但是還處在不可點選的狀態,這時要用到顯式等待。
Python 實現
#匯入依賴
import time
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions
from selenium.webdriver.support.wait import WebDriverWait
class TestHogwarts():
def setup(self):
self.driver = webdriver.Chrome()
self.driver.get('https://ceshiren.com/')
# 加入隱式等待
self.driver.implicitly_wait(5)
def teardown(self):
# 強制等待
time.sleep(10)
self.driver.quit()
def test_hogwarts(self):
# 點選類別
self.driver.find_element(By.CSS_SELECTOR, '[title="按類別分組的所有話題"]').click()
# 元素定位,這裡的category_name是一個元組。
category_name = (By.XPATH, "//*[@class='category-text-title']//*[text()='開源專案']")
# 加入顯式等待
WebDriverWait(self.driver, 10).until(
expected_conditions.element_to_be_clickable(category_name))
# 點選開源專案
self.driver.find_element(*category_name).click()
Java 實現
importorg.openqa.selenium.*;
importorg.openqa.selenium.chrome.ChromeDriver;
importjava.util.logging.Logger;
publicclass demo{
privatestaticfinalLoggerlogger=Logger.getLogger(demo.class.getName());
publicstaticvoidmain(String[]args)throwsInterruptedException{
WebDriverdriver=newChromeDriver();
driver.get("https://ceshiren.com");
Thread.sleep(2000);
driver.manage().window().setSize(newDimension(1936,1056));
driver.findElement(By.cssSelector("#ember18-header .name")).click();
driver.findElement(By.id("ember77")).click();
driver.close();
//關閉瀏覽器程式
driver.quit();
}
}