成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專(zhuān)欄INFORMATION COLUMN

透過(guò)源碼看本質(zhì)-關(guān)于Selenium Webdriver 實(shí)現(xiàn)原理的一點(diǎn)思考和分享

Loong_T / 1060人閱讀

摘要:最近針對(duì)這個(gè)問(wèn)題看了不少了文章和書(shū)籍,在加上一點(diǎn)自己的思考和整理,與大家一起分享,一起學(xué)習(xí)。本文將以為例進(jìn)行說(shuō)明。這個(gè)值表示的是訪問(wèn)的。以為例可以看到,指令的部分包含了幾個(gè)組成部分請(qǐng)求方法。這一部分用來(lái)表示具體的指令。

作為一名使用Selenium開(kāi)發(fā)UI自動(dòng)化多年的工程師,一直都對(duì)Selenium Webdriver的實(shí)現(xiàn)原理感覺(jué)不是很清楚。怎么就通過(guò)腳本控制瀏覽器進(jìn)行各種操作了呢?相信很多Selenium的使用者也會(huì)有類(lèi)似的疑惑。最近針對(duì)這個(gè)問(wèn)題看了不少了文章和書(shū)籍,在加上一點(diǎn)自己的思考和整理,與大家一起分享,一起學(xué)習(xí)。文章中如果有不準(zhǔn)確的地方,希望大家給予指正。

結(jié)構(gòu)

想要使用Selenium實(shí)現(xiàn)自動(dòng)化測(cè)試,主要需要三個(gè)東西。

測(cè)試代碼

Webdriver

瀏覽器

測(cè)試代碼

測(cè)試代碼就是程序員利用不同的語(yǔ)言和相應(yīng)的selenium API庫(kù)完成的代碼。本文將以python為例進(jìn)行說(shuō)明。

Webdriver

Webdriver是針對(duì)不同的瀏覽器開(kāi)發(fā)的,不同的瀏覽器有不同的webdriver。例如針對(duì)Chrome使用的chromedriver。

瀏覽器

瀏覽器和相應(yīng)的Webdriver對(duì)應(yīng)。

首先我們來(lái)看一下這三個(gè)部分的關(guān)系。
對(duì)于三個(gè)部分的關(guān)系模型,可以用一個(gè)日常生活中常見(jiàn)的例子來(lái)類(lèi)比。

對(duì)于打的這個(gè)行為來(lái)說(shuō),乘客和出租車(chē)司機(jī)進(jìn)行交互,告訴出租車(chē)想去的目的地,出租車(chē)司機(jī)駕駛汽車(chē)把乘客送到目的地,這樣乘客就乘坐出租車(chē)到達(dá)了自己想去的地方。
這和Webdriver的實(shí)現(xiàn)原理是類(lèi)似的,測(cè)試代碼中包含了各種期望的對(duì)瀏覽器界面的操作,例如點(diǎn)擊。測(cè)試代碼通過(guò)給Webdriver發(fā)送指令,讓W(xué)ebdriver知道想要做的操作,而Webdriver根據(jù)這些操作在瀏覽器界面上進(jìn)行控制,由此測(cè)試代碼達(dá)到了在瀏覽器界面上操作的目的。
理清了Selenium自動(dòng)化測(cè)試三個(gè)重要組成之間的關(guān)系,接下來(lái)我們來(lái)具體分析其中一個(gè)最重要的關(guān)系。

測(cè)試代碼與Webdriver的交互

接下來(lái)我會(huì)以獲取界面元素這個(gè)基本的操作為例來(lái)分析兩者之間的關(guān)系。
在測(cè)試代碼中,我們第一步要做的是新建一個(gè)webdriver類(lèi)的對(duì)象:

from selenium import webdriver
driver = webdriver.Chrome()

這里新建的driver對(duì)象是一個(gè)webdriver.Chrome()類(lèi)的對(duì)象,而webdriver.Chrome()類(lèi)的本質(zhì)是

from .chrome.webdriver import WebDriver as Chrome

也就是一個(gè)來(lái)自chrome的WebDriver類(lèi)。這個(gè).chrome.webdriver.WebDriver是繼承了selenium.webdriver.remote.webdriver.WebDriver

from selenium.webdriver.remote.webdriver import WebDriver as RemoteWebDriver
...
class WebDriver(RemoteWebDriver):
    """
    Controls the ChromeDriver and allows you to drive the browser.

    You will need to download the ChromeDriver executable from
    http://chromedriver.storage.googleapis.com/index.html
    """

    def __init__(self, executable_path="chromedriver", port=0,
                 chrome_options=None, service_args=None,
                 desired_capabilities=None, service_log_path=None):
...

以python為例,在selenium庫(kù)中,通過(guò)ID獲取界面元素的方法是這樣的:

from selenium import webdriver
driver = webdriver.Chrome()
driver.find_element_by_id(id)

find_elements_by_idselenium.webdriver.remote.webdriver.WebDriver類(lèi)的實(shí)例方法。在代碼中,我們直接使用的其實(shí)不是selenium.webdriver.remote.webdriver.WebDriver這個(gè)類(lèi),而是針對(duì)各個(gè)瀏覽器的webdriver類(lèi),例如webdriver.Chrome()。
所以說(shuō)在測(cè)試代碼中執(zhí)行各種瀏覽器操作的方法其實(shí)都是selenium.webdriver.remote.webdriver.WebDriver類(lèi)的實(shí)例方法。
接下來(lái)我們?cè)偕钊?b>selenium.webdriver.remote.webdriver.WebDriver類(lèi)來(lái)看看具體是如何實(shí)現(xiàn)例如find_element_by_id()的實(shí)例方法的。
通過(guò)Source code可以看到:

    def find_element(self, by=By.ID, value=None):
        """
        "Private" method used by the find_element_by_* methods.

        :Usage:
            Use the corresponding find_element_by_* instead of this.

        :rtype: WebElement
        """
        if self.w3c:
      ...
        return self.execute(Command.FIND_ELEMENT, {
            "using": by,
            "value": value})["value"]

這個(gè)方法最后call了一個(gè)execute方法,方法的定義如下:

    def execute(self, driver_command, params=None):
        """
        Sends a command to be executed by a command.CommandExecutor.

        :Args:
         - driver_command: The name of the command to execute as a string.
         - params: A dictionary of named parameters to send with the command.

        :Returns:
          The command"s JSON response loaded into a dictionary object.
        """
        if self.session_id is not None:
            if not params:
                params = {"sessionId": self.session_id}
            elif "sessionId" not in params:
                params["sessionId"] = self.session_id

        params = self._wrap_value(params)
        response = self.command_executor.execute(driver_command, params)
        if response:
            self.error_handler.check_response(response)
            response["value"] = self._unwrap_value(
                response.get("value", None))
            return response
        # If the server doesn"t send a response, assume the command was
        # a success
        return {"success": 0, "value": None, "sessionId": self.session_id}

正如注釋中提到的一樣,其中的關(guān)鍵在于

response = self.command_executor.execute(driver_command, params)

一個(gè)名為command_executor的對(duì)象執(zhí)行了execute方法。
名為command_executor的對(duì)象是RemoteConnection類(lèi)的對(duì)象,并且這個(gè)對(duì)象是在新建selenium.webdriver.remote.webdriver.WebDriver類(lèi)對(duì)象的時(shí)候就完成賦值的self.command_executor = RemoteConnection(command_executor, keep_alive=keep_alive)
結(jié)合selenium.webdriver.remote.webdriver.WebDriver類(lèi)的類(lèi)注釋來(lái)看:

class WebDriver(object):
    """
    Controls a browser by sending commands to a remote server.
    This server is expected to be running the WebDriver wire protocol
    as defined at
    https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol

    :Attributes:
     - session_id - String ID of the browser session started and controlled by this WebDriver.
     - capabilities - Dictionaty of effective capabilities of this browser session as returned
         by the remote server. See https://github.com/SeleniumHQ/selenium/wiki/DesiredCapabilities
     - command_executor - remote_connection.RemoteConnection object used to execute commands.
     - error_handler - errorhandler.ErrorHandler object used to handle errors.
    """

    _web_element_cls = WebElement

    def __init__(self, command_executor="http://127.0.0.1:4444/wd/hub",
                 desired_capabilities=None, browser_profile=None, proxy=None,
                 keep_alive=False, file_detector=None):

WebDriver類(lèi)的功能是通過(guò)給一個(gè)remote server發(fā)送指令來(lái)控制瀏覽器。而這個(gè)remote server是一個(gè)運(yùn)行WebDriver wire protocol的server。而RemoteConnection類(lèi)就是負(fù)責(zé)與Remote WebDriver server的連接的類(lèi)。
可以注意到有這么一個(gè)新建WebDriver類(lèi)的對(duì)象時(shí)候的參數(shù)command_executor,默認(rèn)值="http://127.0.0.1:4444/wd/hub"。這個(gè)值表示的是訪問(wèn)remote server的URL。因此這個(gè)值作為了RemoteConnection類(lèi)的構(gòu)造方法的參數(shù),因?yàn)橐B接remote server,URL是必須的。
現(xiàn)在再來(lái)看RemoteConnection類(lèi)的實(shí)例方法execute。

    def execute(self, command, params):
        """
        Send a command to the remote server.

        Any path subtitutions required for the URL mapped to the command should be
        included in the command parameters.

        :Args:
         - command - A string specifying the command to execute.
         - params - A dictionary of named parameters to send with the command as
           its JSON payload.
        """
        command_info = self._commands[command]
        assert command_info is not None, "Unrecognised command %s" % command
        data = utils.dump_json(params)
        path = string.Template(command_info[1]).substitute(params)
        url = "%s%s" % (self._url, path)
        return self._request(command_info[0], url, body=data)

這個(gè)方法有兩個(gè)參數(shù):

command

params

command表示期望執(zhí)行的指令的名字。通過(guò)觀察self._commands這個(gè)dict可以看到,self._commands存儲(chǔ)了selenium.webdriver.remote.command.Command類(lèi)里的常量指令和WebDriver wire protocol中定義的指令的對(duì)應(yīng)關(guān)系。

self._commands = {
            Command.STATUS: ("GET", "/status"),
            Command.NEW_SESSION: ("POST", "/session"),
            Command.GET_ALL_SESSIONS: ("GET", "/sessions"),
            Command.QUIT: ("DELETE", "/session/$sessionId"),
...
            Command.FIND_ELEMENT: ("POST", "/session/$sessionId/element"),

以FIND_ELEMENT為例可以看到,指令的URL部分包含了幾個(gè)組成部分:

HTTP請(qǐng)求方法。WebDriver wire protocol中定義的指令是符合RESTful規(guī)范的,通過(guò)不同請(qǐng)求方法對(duì)應(yīng)不同的指令操作。

sessionId。Session的概念是這么定義的:

The server should maintain one browser per session. Commands sent to a session will be directed to the corresponding browser.

也就是說(shuō)sessionId表示了remote server和瀏覽器的一個(gè)會(huì)話,指令通過(guò)這個(gè)會(huì)話變成對(duì)于瀏覽器的一個(gè)操作。

element。這一部分用來(lái)表示具體的指令。

selenium.webdriver.remote.command.Command類(lèi)里的常量指令又在各個(gè)具體的類(lèi)似find_elements的實(shí)例方法中作為execute方法的參數(shù)來(lái)使用,這樣就實(shí)現(xiàn)了selenium.webdriver.remote.webdriver.WebDriver類(lèi)中實(shí)現(xiàn)各種操作的實(shí)例方法與WebDriver wire protocol中定義的指令的一一對(duì)應(yīng)。
selenium.webdriver.remote.webelement.WebElement中各種在WebElement上的操作也是用類(lèi)似的原理實(shí)現(xiàn)的。

實(shí)例方法execute的另一個(gè)參數(shù)params則是用來(lái)保存指令的參數(shù)的,這個(gè)參數(shù)將轉(zhuǎn)化為JSON格式,作為HTTP請(qǐng)求的body發(fā)送到remote server。
remote server在執(zhí)行完對(duì)瀏覽器的操作后得到的數(shù)據(jù)將作為HTTP Response的body返回給測(cè)試代碼,測(cè)試代碼經(jīng)過(guò)解析處理后得到想要的數(shù)據(jù)。

Webdriver與瀏覽器的關(guān)系

這一部分屬于各個(gè)瀏覽器開(kāi)發(fā)者和Webdriver開(kāi)發(fā)者的范疇,所以我們不需要太關(guān)注,我們所關(guān)心的主要還是測(cè)試代碼和Webdriver的關(guān)系,就好像出租車(chē)駕駛員如何駕駛汽車(chē)我們不需要關(guān)心一樣。

總結(jié)


最后通過(guò)這個(gè)關(guān)系圖來(lái)簡(jiǎn)單的描述Selenium三個(gè)組成部分的關(guān)系。通過(guò)對(duì)python selenium庫(kù)的分析,希望能夠幫助大家對(duì)selenium和webdriver的實(shí)現(xiàn)原理有更進(jìn)一步的了解,在日常的自動(dòng)化腳本開(kāi)發(fā)中更加快捷的定位問(wèn)題和解決問(wèn)題。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/44786.html

相關(guān)文章

  • 以后再有人問(wèn)你selenium是什么,你就把這篇文章給他

    摘要:不同目標(biāo)的自動(dòng)化測(cè)試有不同的測(cè)試工具,但是任何工具都無(wú)不例外的需要編程的過(guò)程,實(shí)現(xiàn)源代碼,也可以稱之為測(cè)試腳本。 寫(xiě)在最前面:目前自動(dòng)化測(cè)試并不屬于新鮮的事物,或者說(shuō)自動(dòng)化測(cè)試的各種方法論已經(jīng)層出不窮,但是,能夠在項(xiàng)目中持之以恒的實(shí)踐自動(dòng)化測(cè)試的團(tuán)隊(duì),卻依舊不是非常多。有的團(tuán)隊(duì)知道怎么做,做的還不夠好;有的團(tuán)隊(duì)還正在探索和摸索怎么做,甚至還有一些多方面的技術(shù)上和非技術(shù)上的舊系統(tǒng)需要重構(gòu)……...

    Keven 評(píng)論0 收藏0
  • 使用selenium模擬瀏覽器抓取淘寶商品美食信息

    摘要:目標(biāo)通過(guò)模擬瀏覽器抓取淘寶商品美食信息,并存儲(chǔ)到數(shù)據(jù)庫(kù)中。流程框架淘寶頁(yè)面比較復(fù)雜,含有各種請(qǐng)求參數(shù)和加密參數(shù),如果直接請(qǐng)求或者分析將會(huì)非常繁瑣。 目標(biāo) 通過(guò)Selenium模擬瀏覽器抓取淘寶商品美食信息,并存儲(chǔ)到MongoDB數(shù)據(jù)庫(kù)中。 流程框架 淘寶頁(yè)面比較復(fù)雜,含有各種請(qǐng)求參數(shù)和加密參數(shù),如果直接請(qǐng)求或者分析Ajax將會(huì)非常繁瑣。Selenium是一個(gè)自動(dòng)化測(cè)試工具,可以驅(qū)動(dòng)瀏覽...

    djfml 評(píng)論0 收藏0
  • Python 從零開(kāi)始爬蟲(chóng)(八)——?jiǎng)討B(tài)爬取解決方案 之 selenium

    摘要:然而讓蟲(chóng)師們垂涎的并不是以上的種種,而是其通過(guò)驅(qū)動(dòng)瀏覽器獲得的解析的能力。所以說(shuō)這貨在動(dòng)態(tài)爬取方面簡(jiǎn)直是掛逼級(jí)別的存在,相較于手動(dòng)分析更簡(jiǎn)單易用,節(jié)省分析打碼時(shí)間。一旦設(shè)置了隱式等待時(shí)間,它的作用范圍就是對(duì)象實(shí)例的整個(gè)生命周期。 selenium——自動(dòng)化測(cè)試工具,專(zhuān)門(mén)為Web應(yīng)用程序編寫(xiě)的一個(gè)驗(yàn)收測(cè)試工具,測(cè)試其兼容性,功能什么的。然而讓蟲(chóng)師們垂涎的并不是以上的種種,而是其通過(guò)驅(qū)動(dòng)瀏...

    fobnn 評(píng)論0 收藏0
  • [Python自動(dòng)化]selenium之文件批量下載

    摘要:自動(dòng)化這一專(zhuān)欄,將以目的為導(dǎo)向,以簡(jiǎn)化或自動(dòng)化完成工作任務(wù)為目標(biāo),將運(yùn)用于實(shí)踐中,解決實(shí)際問(wèn)題,以激發(fā)讀者對(duì)這門(mén)腳本語(yǔ)言的學(xué)習(xí)興趣。 Python 自動(dòng)化 這一專(zhuān)欄...

    wzyplus 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<