搞懂webdriver的底層原理,才敢說自己懂自動化!

搞懂webdriver的底層原理,才敢說自己懂自動化!

一:Selenium的歷史

selenium1.x:這個時候的selenium,使用的是JavaScript注入技術與瀏覽器打交道。需要Selenium RC啟動一個Server,將操作Web元素的API調用轉化為一段段Javascript,在Selenium內核啟動瀏覽器之後注入這段Javascript。

Javascript可以獲取並調用DOM的任何元素,自如的進行操作。由此才實現了Selenium的目的:自動化Web操作。這種Javascript注入技術的缺點是速度不理想,而且穩定性大大依賴於Selenium內核對API翻譯成的Javascript質量高低。

selenium2.x:相比於selenium1.x,2.x版本整合了webdriver以及原版selenium。兩個項目合二為一,雖然名字還叫selenium,但也可以叫Webdriver。這個版本的selenium是利用瀏覽器原生的API,封裝成一套更加面向對象的Selenium WebDriver API。

直接操作瀏覽器頁面裡的元素,甚至操作瀏覽器本身(截屏,窗口大小,啟動,關閉,安裝插件,配置證書之類的)。由於使用的是瀏覽器原生的API,速度大大提高,而且調用的穩定性交給了瀏覽器廠商本身,顯然是更加科學。然而帶來的一些副作用就是,不同的瀏覽器廠商,對Web元素的操作和呈現多少會有一些差異,這就直接導致了Selenium WebDriver要分瀏覽器廠商不同,而提供不同的實現。

二:結構

以下進入正題,要通過selenium實現自動化測試,最最主要是需要三種東西:測試需要用的代碼、webdriver、瀏覽器。今天想要分享的也是這三者關係。

代碼

selenium支持多種語言(java/c#/python/ruby)。測試工程師通過編程語言,調用瀏覽器對應API實現需要的功能。

webdriver

webdriver,就像是一個媒介。代碼驅動webdriver。上文提過,不同瀏覽器有不同的webdriver。例如火狐的FirefoxDriver,谷歌的 ChromeDriver。

瀏覽器

不同的瀏覽器對應不同的webdriver。

搞懂webdriver的底層原理,才敢說自己懂自動化!

從上圖,測試代碼輸入操作給webdriver,webdriver再去控制瀏覽器,最終達到的效果就是代碼實現對瀏覽器的操作。

三:查找元素

以查找元素為例,查看代碼與webdriver的交互。以下python為例:

搞懂webdriver的底層原理,才敢說自己懂自動化!

這裡driver是webdriver.Chrome()的對象,我們查看webdriver.Chrome()的源碼。發現本質是 from .chrome.webdriver import WebDriver as Chrome

從目錄名可知這來自chrome的webdriver,再次對這個WebDriver溯源,發現它是繼承了一個RemoteWebDriver類。註釋的含義是:控制ChromeDriver並允許驅動瀏覽器。

搞懂webdriver的底層原理,才敢說自己懂自動化!

再次對繼承的RemoteWebDriver類溯源。

發現其是:selenium.webdriver.remote.webdriver.WebDriver。

搞懂webdriver的底層原理,才敢說自己懂自動化!

註釋的含義是:通過向遠程服務器發送命令來控制瀏覽器。 該服務器應該運行WebDriver有線協議。這裡先停一下,等會我們會再回來繼續瞭解這個類。以python為例,我們在在selenium庫中,通過ID獲取界面元素的方法是這樣的:

搞懂webdriver的底層原理,才敢說自己懂自動化!

一個名為command_executor的對象執行了execute方法。 名為command_executor的對象是RemoteConnection類的對象。

並且這個對象是在新建selenium.webdriver.remote.webdriver.WebDriver類對象的時候就完成賦值的self.command_executor = RemoteConnection(command_executor, keep_alive=keep_alive)。

結合selenium.webdriver.remote.webdriver.WebDriver類的類註釋來看:WebDriver類的功能是通過給一個remote server發送指令來控制瀏覽器。而這個remote server是一個運行WebDriver wire protocol的server。而RemoteConnection類就是負責與Remote WebDriver server的連接的類。 可以注意到有這麼一個新建WebDriver類的對象時候的參數command_executor。

默認值等於'http://127.0.0.1:4444/wd/hubremote'。這個值表示的是訪問server的URL。因此這個值作為了RemoteConnection類的構造方法的參數。因為要連接remote server,URL是必須的。 現在再來看RemoteConnection類的實例方法execute。

搞懂webdriver的底層原理,才敢說自己懂自動化!

這個方法有兩個參數:command、params。

command表示期望執行的指令的名字。打開self._commands這個dict。查看Command.FIND_ELEMENT的value.。

指令的URL部分包含了幾個組成部分:

◆HTTP請求方法。WebDriver wire protocol中定義的指令是符合RESTful規範的,通過不同請求方法對應不同的指令操作。

◆sessionId. sessionId表示了remote server和瀏覽器的一個會話,指令通過這個會話變成對於瀏覽器的一個操作。

◆ element 這一部分用來表示具體的指令。

selenium.webdriver.remote.command.Command類裡的常量指令又在各個具體的類似find_elements的實例方法中作為execute方法的參數來使用。

這樣就實現了selenium.webdriver.remote.webdriver.WebDriver類中實現各種操作的實例方法與WebDriver wire protocol中定義的指令的一一對應。

selenium.webdriver.remote.webelement.WebElement中各種在WebElement上的操作也是用類似的原理實現的。實例方法execute的另一個參數params則是用來保存指令的參數的,這個參數將轉化為JSON格式,作為HTTP請求的body發送到remote server。

remote server在執行完對瀏覽器的操作後得到的數據將作為HTTP Response的body返回給測試代碼,測試代碼經過解析處理後得到想要的數據。

四:總結

搞懂webdriver的底層原理,才敢說自己懂自動化!

初學者文中難免可能有疏漏之處,希望各位大佬指正。

五:補充

為了怕同志們理解錯,把雨澤大佬上課說的selenium工作原理寫在下面。

本菜鳥是在此基礎上從另一角度出發來看:

◆ Service: service->subprocess調用命令行打開webdriver.exe

◆ Client: urlib3->訪問服務(接口)

本文到這裡就技術啦,大家有任何問題可以在留言區留言呦~

相關推薦

推薦中...