Selenium打開瀏覽器加載慢的原因


在自動化元素定位操作中經常使用智能等待來加強定位的強壯性,主要就是因為WebDriver沒有提供頁面加載場景的方法;在使用JavaScript知識的突然心生靈感,可以使用JavaScript來配合驗證頁面加載,結果發現我真是井底之蛙。

 

一、domcument.readyState

首先定位從Document對象出發,而Document對象是在html文檔加載完成便可操作使用,所以判斷文件裝載完成即可;Document對象的readyState屬性返回當前文檔裝載狀態:

uninitialized 表示未開始載入
loading 載入中,下載了html並且開始加載
interactive 已加載完html內容
complete 已加載完html內容和下載解析了子資源(js、css、image),不包含ajax異步。
public static void pageDOMLoadComplete(){
       JavaScriptExecutor js=(JavaScriptExecutor) SeleniumMethod.ThreadDriver.get();
       try {
              while(!"complete".equals(js.executeScript("return document.readyState"))){
                     Thread.sleep(2000);
       }
         logger.info("頁面元素加載完成");
       } catch (Exception e) {
              // TODO: handle exception
              e.printStackTrace();
              logger.info("判斷頁面元素加載異常");
       }     
}

  

如上代碼,如果結果返回的complete表示加載完成,這時候就可以開始元素定位操作。返回不是complete則使用線程循環等待,直到加載完成才跳出循環。

詳細了解的建議去腦補一下瀏覽器對頁面加載的過程。通過瀏覽器發送請求到服務器響應先得到html形成Document對象,瀏覽器解析html形成dom樹開始加載,當加載dom樹遇到外部資源時去請求外部資源,但加載dom樹並不會等待會繼續加載,當資源如JavaScript、css、圖片等等加載完成這時候document.readyState的值變成complete。

 

二、Selenium加載策略

因為Selenium從頭到位都沒有任何判斷頁面加載完成的關鍵字;而結合document.readyState的返回來確定頁面加載成功,然后再去執行定位操作,這樣來說是個合理的思想。根據想法編寫下面的代碼:

WebDriver driver = new ChromeDriver();
driver.get("https://www.sina.com.cn/");
try {
	while(!"complete".equals(((JavaScriptExecutor) driver).executeScript("return document.readyState"))) {
		Thread.sleep(1000);
	}
} catch(Exception e) {
	// TODO: handle exception
	e.printStackTrace();

}
driver.findElement(By.name("SerchKey")).sendKeys("軟件測試");
driver.findElement(By.name("SearchSubButton")).click();
driver.quit();

  

 

上面代碼利用JavaScript執行一段腳本document.readyState的值返回不是complete則一直循環並線程等待1S,直到返回的值是complete退出循環。

但是在代碼運行后發現,從來都沒有進入過循環。於是猜測,是get()方法在打開瀏覽器並訪問URL時,是不是就已經判斷過頁面加載完成了?驗證方法很簡單,把循環去掉,代碼直接打印document.readyState返回的值

System.out.print(((JavaScriptExecutor)driver).executeScript("return document.readyState"));

  

得到的結果每次都是complete,驗證確實get()方法后就已經頁面加載成功了。在使用WebDriver時,每次打開瀏覽器都知道它並不會帶有任何緩存數據,而是一個全新初始化的瀏覽器,這點只要用過Selenium的同學,並做過登錄功能都應該知道,每次使用都需要重新登錄,瀏覽器並不會保存任何cookie、緩存信息。就是因為這個原因,WebDriver每次調起瀏覽器並訪問URL的時候因為沒有緩存所以頁面加載會非常慢(當然不僅僅是緩存,WebDriver還會去遍歷一些其他東西,如虛擬網卡、代理配置等);這個慢的現象大多數是頁面已經展示內容了,然后瀏覽器還在轉圈加載,然而使用document.readyState來判斷好像不現實了,因為WebDriver的get()方法默認就會等待頁面加載完。所以思路就轉化為,get()方法的探究。

通過官方資料查詢,發現WebDriver有pageLoadStrategy加載策略這一說,地址如下:https://www.w3.org/TR/webdriver/#dfn-table-of-page-load-strategies,大家可以自己去瞧瞧。加載策略有如下三種:

none:沒有說明對應關系
eager:對應ducument readiness state為”interactive”
normal:對應ducument readiness state為”complete”
 

從上面三種加載策略可以看到,官方除了none這種沒有具體說明外,另外兩種對應的正式document.readyState返回的狀態。而默認的加載策略是normal,所以再次驗證為什么使用document.readyState得到的值是complete。驗證代碼如下:

DesiredCapabilities capabilities = DesiredCapabilities.chrome();
capabilities.setCapability("pageLoadStrategy", "none");
WebDriver driver = new ChromeDriver(capabilities);
driver.get("https://www.sina.com.cn/");
System.out.println(((JavaScriptExecutor) driver).executeScript("return document.readyState"));
driver.findElement(By.name("SerchKey")).sendKeys("軟件測試");
driver.findElement(By.name("SearchSubButton")).click();
System.out.println(((JavaScriptExecutor) driver).executeScript("return document.readyState"));
driver.quit();

  

 

 執行代碼,打印document.readyState返回的結果是loading;在使用findElement查找元素時報錯“Unable to locate element”。當加載策略為none時,對應document.readyState結果是loading的時候,頁面還在加載中,進行元素查找會報錯,這很好理解,Dom樹還在加載過程中,是無法解析任何元素的查找的,所以報錯。

接下來分別嘗試了eager加載策略,需要注意一點的是Chrome瀏覽器並不支持這種加載策略,所以改為了Firefox驗證。

DesiredCapabilities capabilities = DesiredCapabilities.firefox();
capabilities.setCapability("pageLoadStrategy", "eager");
WebDriver driver = new FirefoxDriver(capabilities);

  

 

其他代碼不變,執行代碼打印document.readyState返回的結果是interactive,但是不同的是使用findElement查找元素沒有報錯,並且全部執行成功。當加載策略為eager,頁面加載結果interactive時,整個DOM樹加載完成,這時候就已經可以定位元素並執行操作了;根據document.readyState與WebDriver的加載策略得出以下結論:

 

(1)loading與none

 DOM樹 載入中,也就是說已經下載了html並且開始加載;這時候是無法查找元素的,get()方法的執行時間非常短,可以馬上執行get()方法后面的代碼。所以這時候就可以使用下面代碼再次進行判斷后再執行。

while(!"complete".equals(((JavascriptExecutor)driver).executeScript("return document.readyState"))){}

  

 這樣的作法好像與加載策略的默認方法沒什么不同,但是WebDriver的get()方法可不僅僅是等待頁面為complete而已,它還會去判斷一些瀏覽器其他的配置。

這種情況還有一種不建議使用的方式,就是使用隱式等待,每次查找元素找不到時,等待一定時間。隱式等待在當前driver的整個生命周期中都生效,是非常適合配合none這種加載策略的。

driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);

  

新片場https://www.wode007.com/sites/73286.html 傲視網https://www.wode007.com/sites/73285.html

(2)interactive與eager

已加載完html內容,但是沒有解析子資源;這時候DOM樹加載完成,並且去請求子資源了,是可以查找元素並正確返回了。有個弊端就是如果一些數據是通過JavaScript去賦值的,這時候查找元素某些屬性數據可能得到空。

 

(3)complete與normal

 已加載完html內容和下載解析了子資源(JavaScript、css、image),不包含ajax異步。前面應該都沒疑問,重要的是ajax異步請求的加載。如果頁面上一些數據是通過ajax異步去請求並加載的,同樣在ajax請求中數據響應沒有及時回來的情況下,拿到的也是空。當然這並不需要擔心,只要不是太大數據請求響應還是非常快速的。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM