(五十八)Selenium Grid2的Remote應用之WebDriver驅動分析


隨筆記錄方便自己和同路人查閱。

 

#------------------------------------------------我是可恥的分割線-------------------------------------------

Remote應用

要解釋清楚Remote的作用並不太容易,不過我們可以通過分析selenium代碼的方式來理解它的作用。我們知道WebDriver支持多瀏覽器下的執行,這是因為WebDriver針對每一種瀏覽器驅動都重寫WebDriver方法。所以,在腳本運行之前需要先確定瀏覽器驅動,具體如下:

 

driver = webdriver.Firefox()
driver = webdriver.Chrome()
driver = webdriver.Ie()

 

下面就對這些驅動進行簡單分析。

WebDriver驅動分析

selenium包的WebDriver目錄下可以看到如下圖所示的目錄結構。

 

 

 

查看其中任何一個驅動的目錄發現都有一個webdriver.py文件,除了我們熟悉的FirefoxChromeIE等驅動外,其中還包括非常重要的remote。從這個角度看,也可以把它看作是一種驅動類型,而這種驅動類型比較特殊,它不是支持某一款特定的瀏覽器或平台而是一種配置模式,我們在這種配置模式下制定任意的平台或瀏覽器,這種模式的執行都需要Selenium Server的支持。

 

打開Selenium包下的webdriver/firefox目錄,先看Firefoxwebdriver.py文件的實現。

 

from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
from selenium.webdriver.remote.webdriver import WebDriver as RemoteWebDriver

from .extension_connection import ExtensionConnection
from .firefox_binary import FirefoxBinary
from .firefox_profile import FirefoxProfile
from .options import Options
from .remote_connection import FirefoxRemoteConnection
from .service import Service
from .webelement import FirefoxWebElement


class WebDriver(RemoteWebDriver):

    # There is no native event support on Mac
    NATIVE_EVENTS_ALLOWED = sys.platform != "darwin"

    CONTEXT_CHROME = "chrome"
    CONTEXT_CONTENT = "content"

    _web_element_cls = FirefoxWebElement

    def __init__(self, firefox_profile=None, firefox_binary=None,
                 timeout=30, capabilities=None, proxy=None,
                 executable_path="geckodriver", options=None,
                 service_log_path="geckodriver.log", firefox_options=None,
                 service_args=None, desired_capabilities=None, log_path=None,
                 keep_alive=True):

 

主機查看WebDriver類的__init__()初始化方法,因為Selenium自帶Firefox瀏覽器驅動,所以,這個驅動的重要配置在於firefox_profilefirefox_binary兩個參數。而這兩個參數分別調用當前目錄下的firefox_binary.pyfirefox_profile.py文件,感興趣的讀者可以進一步研究這兩個文件的實現。

我們在腳本中調用Firefox瀏覽器驅動時的路徑為:selenium.webdriver.Firefox(),那么,它是如何指向../selenium/webdriver/firefox/webdriver.py文件中WebDriver類的內?秘密在於../selenium/webdriver/目錄下的__init__.py文件。查看__init__.py文件

 

from .firefox.webdriver import WebDriver as Firefox  # noqa
from .firefox.firefox_profile import FirefoxProfile  # noqa
from .firefox.options import Options as FirefoxOptions  # noqa
from .chrome.webdriver import WebDriver as Chrome  # noqa
from .chrome.options import Options as ChromeOptions  # noqa
from .ie.webdriver import WebDriver as Ie  # noqa
from .ie.options import Options as IeOptions  # noqa
from .edge.webdriver import WebDriver as Edge  # noqa
from .opera.webdriver import WebDriver as Opera  # noqa
from .safari.webdriver import WebDriver as Safari  # noqa
from .blackberry.webdriver import WebDriver as BlackBerry  # noqa
from .phantomjs.webdriver import WebDriver as PhantomJS  # noqa
from .android.webdriver import WebDriver as Android  # noqa
from .webkitgtk.webdriver import WebDriver as WebKitGTK # noqa
from .webkitgtk.options import Options as WebKitGTKOptions # noqa
from .remote.webdriver import WebDriver as Remote  # noqa
from .common.desired_capabilities import DesiredCapabilities  # noqa
from .common.action_chains import ActionChains  # noqa
from .common.touch_actions import TouchActions  # noqa
from .common.proxy import Proxy  # noqa

__version__ = '3.14.1'

 

通過查看該文件就明白了它的原理,它其實對不同驅動的路徑做了簡化,並且將不同目錄下的WebDriver類重命名為相應的瀏覽器(FirefoxChromeIE等),所以,在調用不同瀏覽器的驅動時就簡化了層級。

再打開selenium包下的webdriver/chrome目錄,查看Chromewebdriver.py文件的實現。

 

import warnings

from selenium.webdriver.remote.webdriver import WebDriver as RemoteWebDriver
from .remote_connection import ChromeRemoteConnection
from .service import Service
from .options import Options


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,
                 options=None, service_args=None,
                 desired_capabilities=None, service_log_path=None,
                 chrome_options=None, keep_alive=True):

 

同樣查看WebDriver類的__init__()初始化方法,因為Selenium模塊不自帶chromedriver.exe驅動,隨意executable_path參數會指定chromedriver驅動。

通過查看兩個文件注意到一個細節,是FirefoxChromeWebDriver類都繼承RemoteWebDriver類,也就是remoteWebDriver類,那么我們很好奇這個WebDriver類實現了什么功能呢?

打開selenium包下webdriver/remote目錄下的webdriver.py文件。

 

class WebDriver(object):

    _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, options=None):
        """
        Create a new driver that will issue commands using the wire protocol.

        :Args:
         - command_executor - Either a string representing URL of the remote server or a custom
             remote_connection.RemoteConnection object. Defaults to 'http://127.0.0.1:4444/wd/hub'.
         - desired_capabilities - A dictionary of capabilities to request when
             starting the browser session. Required parameter.
         - browser_profile - A selenium.webdriver.firefox.firefox_profile.FirefoxProfile object.
             Only used if Firefox is requested. Optional.
         - proxy - A selenium.webdriver.common.proxy.Proxy object. The browser session will
             be started with given proxy settings, if possible. Optional.
         - keep_alive - Whether to configure remote_connection.RemoteConnection to use
             HTTP keep-alive. Defaults to False.
         - file_detector - Pass custom file detector object during instantiation. If None,
             then default LocalFileDetector() will be used.
         - options - instance of a driver options.Options class
        """
        capabilities = {}
        if options is not None:
            capabilities = options.to_capabilities()
        if desired_capabilities is not None:
            if not isinstance(desired_capabilities, dict):
                raise WebDriverException("Desired Capabilities must be a dictionary")
            else:
                capabilities.update(desired_capabilities)
        if proxy is not None:
            warnings.warn("Please use FirefoxOptions to set proxy",
                          DeprecationWarning, stacklevel=2)
            proxy.add_to_capabilities(capabilities)
        self.command_executor = command_executor
        if type(self.command_executor) is bytes or isinstance(self.command_executor, str):
            self.command_executor = RemoteConnection(command_executor, keep_alive=keep_alive)
        self._is_remote = True
        self.session_id = None
        self.capabilities = {}
        self.error_handler = ErrorHandler()
        self.start_client()
        if browser_profile is not None:
            warnings.warn("Please use FirefoxOptions to set browser profile",
                          DeprecationWarning, stacklevel=2)
        self.start_session(capabilities, browser_profile)
        self._switch_to = SwitchTo(self)
        self._mobile = Mobile(self)
        self.file_detector = file_detector or LocalFileDetector()

 

WebDriver類的__init__()初始化方法提供了一個重要信息,即command_executor參數,它默認指向本機(127.0.0.1)的444端口號,通過修改這個參數可以使其指向任意的某平台主機。

除此之外,我們還需要對瀏覽器進行配置。瀏覽器的配置由desired_capabilities參數決定,這個參數的秘密在selenium包的webdriver/common目錄下的desired_capabilities.py文件中。

class DesiredCapabilities(object):

    FIREFOX = {
        "browserName": "firefox",
        "marionette": True,
        "acceptInsecureCerts": True,
    }

    INTERNETEXPLORER = {
        "browserName": "internet explorer",
        "version": "",
        "platform": "WINDOWS",
    }

    EDGE = {
        "browserName": "MicrosoftEdge",
        "version": "",
        "platform": "WINDOWS"
    }

    CHROME = {
        "browserName": "chrome",
        "version": "",
        "platform": "ANY",
    }

    OPERA = {
        "browserName": "opera",
        "version": "",
        "platform": "ANY",
    }

    SAFARI = {
        "browserName": "safari",
        "version": "",
        "platform": "MAC",
    }

    HTMLUNIT = {
        "browserName": "htmlunit",
        "version": "",
        "platform": "ANY",
    }

    HTMLUNITWITHJS = {
        "browserName": "htmlunit",
        "version": "firefox",
        "platform": "ANY",
        "javascriptEnabled": True,
    }

    IPHONE = {
        "browserName": "iPhone",
        "version": "",
        "platform": "MAC",
    }

    IPAD = {
        "browserName": "iPad",
        "version": "",
        "platform": "MAC",
    }

    ANDROID = {
        "browserName": "android",
        "version": "",
        "platform": "ANDROID",
    }

    PHANTOMJS = {
        "browserName": "phantomjs",
        "version": "",
        "platform": "ANY",
        "javascriptEnabled": True,
    }

    WEBKITGTK = {
        "browserName": "MiniBrowser",
        "version": "",
        "platform": "ANY",
    }

‘browserName’:’chrome’  瀏覽器(ChromeFirefox

‘version’:’’  瀏覽器版本。

‘platfrom’:’ANY’  測試平台(ANY表示默認平台)

‘javascriptEnabled’:’True’  JavaScript啟動狀態。

‘marionette’:False  marionettePython客戶端允許你遠程控制基於gecko的瀏覽器或設備運行一個marionette服務器,包括桌面FirefoxFirefox OS。該參數為Firefox特有。

DesiredCapabilities平台及瀏覽器的參數如下

 

FIREFOX = {
        "browserName": "firefox",
        "version": "",
        "platform": "ANY",
        "javascriptEnabled":"True",
        "marionette":"False"
    }
INTERNETEXPLORER = {
        "browserName": "internet explorer",
        "version": "",
        "platform": "WINDOWS",
        "javascriptEnabled":True,
    }
EDGE = {
        "browserName": "MicrosoftEdge",
        "version": "",
        "platform": "WINDOWS",
    }
CHROME = {
        "browserName": "chrome",
        "version": "",
        "platform": "ANY",
        "javascriptEnabled":True,
    }
OPERA = {
        "browserName": "opera",
        "version": "",
        "platform": "ANY",
        "javascriptEnabled":True,
    }
SAFARI = {
        "browserName": "safari",
        "version": "",
        "platform": "ANY",
        "javascriptEnabled":True,
    }
HTMLUNITWITHJS = {
        "browserName": "htmlunit",
        "version": "firefox",
        "platform": "ANY",
        "javascriptEnabled":True,
    }
IPHONE = {
        "browserName": "iPhone",
        "version": "",
        "platform": "MAC",
        "javascriptEnabled":True,
    }
IPAD = {
        "browserName": "iPad",
        "version": "",
        "platform": "MAC",
        "javascriptEnabled":True,
    }
ANDROID = {
        "browserName": "android",
        "version": "",
        "platform": "ANDROID",
        "javascriptEnabled":True,
    }
PHANTOMJS = {
        "browserName": "phantomjs",
        "version": "",
        "platform": "ANY",
        "javascriptEnabled":True,
    }


免責聲明!

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



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