selenium库浅析

pip install selenium安装好后,在sitepackages下

2个主要的目录,commonwebdriver

1- common

该目录一共就一个模块exceptions.py

① exceptions.py

其中定义了32个异常,竟然有个同学面试的时候被问过

  1. Stale means the element no longer appears on the DOM of the page.
  2. WebDriverException3个初始化参数,msg/screen/stacktrace,仅仅定义了__str__
  3. UnexpectedAlertPresentException就它定义了自己的__str__,加了alert_text进来

2- webdriver

这是selenium的核心,主要包括11个文件夹

chrome
chromium
common
edge
firefox
ie
remote
safari
support
webkitgtk
wpewebkit

其中chrome chromium edge firefox ie safari webkitgtk wpewebkit 这是8个典型的浏览器

每个目录下存在三个主要的文件

options.py
service.py
webdriver.py

其中有点特殊的就是

chromium多了remote_connection.py

firefox多了

extension_connection.py
firefox_binary.py
firefox_profile.py
remote_connection.py
webdriver_prefs.json

safari多了

permissions.py
remote_connection.py

主要是3个包,commonsupportremote

这是selenium的核心功能所在

① chrome包

puml源码见附录

  1. service的Service这个类原名是Service,但如果这么写,由于有重名就会关联错误
  2. 下面展示了chrome下3个文件中每个类的继承关系

selenium库浅析-LMLPHP

② common包

action_chains

alert

这个比较简单

一个类Alert包括

  • 一个属性text

  • 三个方法dismiss accept send_keys

by

一个类By

8个定位方式

keys

NULL = '\ue000'
CANCEL = '\ue001'  
HELP = '\ue002'
BACKSPACE = '\ue003'
BACK_SPACE = BACKSPACE
TAB = '\ue004'
CLEAR = '\ue005'
RETURN = '\ue006'
ENTER = '\ue007'
SHIFT = '\ue008'
LEFT_SHIFT = SHIFT
CONTROL = '\ue009'
LEFT_CONTROL = CONTROL
ALT = '\ue00a'
LEFT_ALT = ALT
PAUSE = '\ue00b'
ESCAPE = '\ue00c'
SPACE = '\ue00d'
PAGE_UP = '\ue00e'
PAGE_DOWN = '\ue00f'
END = '\ue010'
HOME = '\ue011'
LEFT = '\ue012'
ARROW_LEFT = LEFT
UP = '\ue013'
ARROW_UP = UP
RIGHT = '\ue014'
ARROW_RIGHT = RIGHT
DOWN = '\ue015'
ARROW_DOWN = DOWN
INSERT = '\ue016'
DELETE = '\ue017'
SEMICOLON = '\ue018'
EQUALS = '\ue019'
NUMPAD0 = '\ue01a'  
NUMPAD1 = '\ue01b'
NUMPAD2 = '\ue01c'
NUMPAD3 = '\ue01d'
NUMPAD4 = '\ue01e'
NUMPAD5 = '\ue01f'
NUMPAD6 = '\ue020'
NUMPAD7 = '\ue021'
NUMPAD8 = '\ue022'
NUMPAD9 = '\ue023'
MULTIPLY = '\ue024'
ADD = '\ue025'
SEPARATOR = '\ue026'
SUBTRACT = '\ue027'
DECIMAL = '\ue028'
DIVIDE = '\ue029'
F1 = '\ue031'  
F2 = '\ue032'
F3 = '\ue033'
F4 = '\ue034'
F5 = '\ue035'
F6 = '\ue036'
F7 = '\ue037'
F8 = '\ue038'
F9 = '\ue039'
F10 = '\ue03a'
F11 = '\ue03b'
F12 = '\ue03c'
META = '\ue03d'
COMMAND = '\ue03d'
ZENKAKU_HANKAKU = '\ue040'

③ remote包

webdriver

WebElement

④ support包

expected_conditions

relative_locator

2个函数with_tag_namelocate_with

一个类RelativeBy

主要是5个方法abovebelowto_left_ofto_right_ofnear

select

定义了一个Select

3个属性options、all_selected_options、first_selected_option

七个方法select_by_value select_by_index select_by_visible_text deselect_alldeselect_by_value deselect_by_index deselect_by_visible_text

wait

显式等待的核心逻辑

一个类WebDriverWait

2个方法untiluntil_not

其中until是核心

原始定义如下

    def until(self, method, message: str = ""):
        """Calls the method provided with the driver as an argument until the \
        return value does not evaluate to ``False``.

        :param method: callable(WebDriver)
        :param message: optional message for :exc:`TimeoutException`
        :returns: the result of the last call to `method`
        :raises: :exc:`selenium.common.exceptions.TimeoutException` if timeout occurs
        """
        screen = None
        stacktrace = None

        end_time = time.monotonic() + self._timeout
        from time import ctime
        while True:
            try:
                value = method(self._driver)
                if value:
                    return value
            except self._ignored_exceptions as exc:
                screen = getattr(exc, 'screen', None)
                stacktrace = getattr(exc, 'stacktrace', None)
            time.sleep(self._poll)
            if time.monotonic() > end_time:

                break
        raise TimeoutException(message, screen, stacktrace)

核心是

        end_time = time.monotonic() + self._timeout
        from time import ctime
        while True:
            try:
                value = method(self._driver)
                if value:
                    return value
            time.sleep(self._poll)
            if time.monotonic() > end_time:
                break
        raise TimeoutException(message, screen, stacktrace)

这么解释

  1. 用传过来的method,call它,传入self._driver

  2. 得到一个value,如果有value就直接return

  3. 如果没有得到就time.sleep(轮询间隔)

  4. 加个判断如果当前时间超过了你的预设时间end_time(就是程序开始的时间+最大等待时间self._time_out),那就退出循环,抛出TimeoutException异常

3- 实例浅析

下面的代码

from selenium import webdriver
driver = webdriver.Chrome()
driver.maximize_window()
driver.get('http://121.5.150.55:8090/')
driver.find_element('id','ls_username').send_keys('admin')
driver.find_element('id','ls_password').send_keys('123456')
driver.find_element('css selector','.pn.vm').click()

① 导包

from selenium import webdriver

你执行了webdriver/__init__.py

这里做了很多命名,如,你才可以用上面代码的第二行

from .chrome.webdriver import WebDriver as Chrome

② 实例化某个浏览器

driver = webdriver.Chrome()

做完这个,正常情况你会打开一个浏览器

这是相对比较复杂的一个过程

其继承关系如下

selenium库浅析-LMLPHP

  1. 其中RemoteWebDriver是别名,实际是WebDriver,不过是remote下的,跟第一个不同

  2. BaseWebDriver是个抽象基类

  3. RemoteWebDriver中会执行self.start_session(capabilities, browser_profile)

  4. start_session源码如下,作用就是用提供的预期能力值启动会话

   def start_session(self, capabilities: dict, browser_profile=None) -> None:
       """
       Creates a new session with the desired capabilities.

       :Args:
        - capabilities - a capabilities dict to start the session with.
        - browser_profile - A selenium.webdriver.firefox.firefox_profile.FirefoxProfile object. Only used if Firefox is requested.
       """
       if not isinstance(capabilities, dict):
           raise InvalidArgumentException("Capabilities must be a dictionary")
       if browser_profile:
           if "moz:firefoxOptions" in capabilities:
               capabilities["moz:firefoxOptions"]["profile"] = browser_profile.encoded
           else:
               capabilities.update({'firefox_profile': browser_profile.encoded})
       w3c_caps = _make_w3c_caps(capabilities)
       parameters = {"capabilities": w3c_caps}
       response = self.execute(Command.NEW_SESSION, parameters)
       if 'sessionId' not in response:
           response = response['value']
       self.session_id = response['sessionId']
       self.caps = response.get('value')

       # if capabilities is none we are probably speaking to
       # a W3C endpoint
       if not self.caps:
           self.caps = response.get('capabilities')
  1. 就是这句
response = self.execute(Command.NEW_SESSION, parameters)

③ driver操作

driver.maximize_window()
driver.get('http://121.5.150.55:8090/')
driver.find_element('id','ls_username').send_keys('admin')
driver.find_element('id','ls_password').send_keys('123456')
driver.find_element('css selector','.pn.vm').click()

上面所有的driver的操作本质都是类似的

  1. 其中Command类定义了JsonWireProtocol,比如Command.W3C_MAXIMIZE_WINDOW='w3cMaximizeWindow'

  2. execute这个方法接收2个参数driver_commandparams,核心是response = self.command_executor.execute(driver_command, params)

  3. 其中command_executor你可以理解为是chromedriver这个驱动(REST API SERVER),虽然默认值是'http://127.0.0.1:4444' Grid的地址。它的本质会去调度self._request(command_info[0], url, body=data)这里跟requests库的调用就即可相似了,虽然底层的差异还是蛮多的

  4. 举个例子,调试第二行实例化得到的method/url/body分别是

POST 
http://localhost:11721/session 
{"capabilities": {"firstMatch": [{}], "alwaysMatch": {"browserName": "chrome", "pageLoadStrategy": "normal", "goog:chromeOptions": {"extensions": [], "args": []}}}}

第三行最大化

POST http://localhost:11721/session/3e0775932ad7ee1828609d5e38bb6984/window/maximize {}

第四行

POST http://localhost:11721/session/3e0775932ad7ee1828609d5e38bb6984/url {"url": "http://121.5.150.55:8090/"}

附录

代码结构

+-- common (25.62KB)
|   +-- exceptions.py (9.01KB)
|   +-- __init__.py (3.68KB)
+-- py.typed (0b)
+-- selenium.txt (88.12KB)
+-- types.py (932b)
+-- webdriver (7.54MB)
|   +-- chrome (12.5KB)
|   |   +-- options.py (1.4KB)
|   |   +-- service.py (1.71KB)
|   |   +-- webdriver.py (3.57KB)
|   |   +-- __init__.py (787b)
|   +-- chromium (38.02KB)
|   |   +-- options.py (6.08KB)
|   |   +-- remote_connection.py (2.53KB)
|   |   +-- service.py (1.93KB)
|   |   +-- webdriver.py (9.17KB)
|   |   +-- __init__.py (787b)
|   +-- common (6.85MB)
|   |   +-- actions (44.26KB)
|   |   |   +-- action_builder.py (3.41KB)
|   |   |   +-- input_device.py (1.24KB)
|   |   |   +-- interaction.py (1.4KB)
|   |   |   +-- key_actions.py (1.67KB)
|   |   |   +-- key_input.py (1.76KB)
|   |   |   +-- mouse_button.py (88b)
|   |   |   +-- pointer_actions.py (5.38KB)
|   |   |   +-- pointer_input.py (2.88KB)
|   |   |   +-- wheel_actions.py (1.29KB)
|   |   |   +-- wheel_input.py (2.55KB)
|   |   |   +-- __init__.py (787b)
|   |   +-- action_chains.py (13.03KB)
|   |   +-- alert.py (2.52KB)
|   |   +-- bidi (36.56KB)
|   |   |   +-- cdp.py (17.89KB)
|   |   |   +-- console.py (886b)
|   |   |   +-- __init__.py (787b)
|   |   +-- by.py (1.08KB)
|   |   +-- desired_capabilities.py (2.86KB)
|   |   +-- devtools (6.62MB)
|   |   |   +-- v101 (1.73MB)
|   |   |   |   +-- accessibility.py (21.4KB)
|   |   |   |   +-- animation.py (10.85KB)
|   |   |   |   +-- audits.py (43.67KB)
|   |   |   |   +-- background_service.py (5.62KB)
|   |   |   |   +-- browser.py (20.2KB)
|   |   |   |   +-- cache_storage.py (7.63KB)
|   |   |   |   +-- cast.py (4.28KB)
|   |   |   |   +-- console.py (2.7KB)
|   |   |   |   +-- css.py (54.31KB)
|   |   |   |   +-- database.py (3.83KB)
|   |   |   |   +-- debugger.py (42.92KB)
|   |   |   |   +-- device_orientation.py (1.18KB)
|   |   |   |   +-- dom.py (57.98KB)
|   |   |   |   +-- dom_debugger.py (9.24KB)
|   |   |   |   +-- dom_snapshot.py (35.48KB)
|   |   |   |   +-- dom_storage.py (4.91KB)
|   |   |   |   +-- emulation.py (24.4KB)
|   |   |   |   +-- event_breakpoints.py (1.26KB)
|   |   |   |   +-- fetch.py (18.17KB)
|   |   |   |   +-- headless_experimental.py (4.68KB)
|   |   |   |   +-- heap_profiler.py (11.47KB)
|   |   |   |   +-- indexed_db.py (12.46KB)
|   |   |   |   +-- input_.py (27.19KB)
|   |   |   |   +-- inspector.py (1.68KB)
|   |   |   |   +-- io.py (2.96KB)
|   |   |   |   +-- layer_tree.py (14.7KB)
|   |   |   |   +-- log.py (5.14KB)
|   |   |   |   +-- media.py (6.45KB)
|   |   |   |   +-- memory.py (6.65KB)
|   |   |   |   +-- network.py (120.84KB)
|   |   |   |   +-- overlay.py (49.08KB)
|   |   |   |   +-- page.py (99.17KB)
|   |   |   |   +-- performance.py (2.86KB)
|   |   |   |   +-- performance_timeline.py (6.47KB)
|   |   |   |   +-- profiler.py (15.4KB)
|   |   |   |   +-- py.typed (0b)
|   |   |   |   +-- runtime.py (54.73KB)
|   |   |   |   +-- schema.py (1.08KB)
|   |   |   |   +-- security.py (16.47KB)
|   |   |   |   +-- service_worker.py (10.81KB)
|   |   |   |   +-- storage.py (15.95KB)
|   |   |   |   +-- system_info.py (10.79KB)
|   |   |   |   +-- target.py (20.42KB)
|   |   |   |   +-- tethering.py (1.5KB)
|   |   |   |   +-- tracing.py (12.17KB)
|   |   |   |   +-- util.py (455b)
|   |   |   |   +-- web_audio.py (16.5KB)
|   |   |   |   +-- web_authn.py (12.06KB)
|   |   |   |   +-- __init__.py (1.26KB)
|   |   |   +-- v102 (1.74MB)
|   |   |   |   +-- accessibility.py (21.4KB)
|   |   |   |   +-- animation.py (10.85KB)
|   |   |   |   +-- audits.py (44.04KB)
|   |   |   |   +-- background_service.py (5.62KB)
|   |   |   |   +-- browser.py (20.2KB)
|   |   |   |   +-- cache_storage.py (7.63KB)
|   |   |   |   +-- cast.py (4.28KB)
|   |   |   |   +-- console.py (2.7KB)
|   |   |   |   +-- css.py (54.31KB)
|   |   |   |   +-- database.py (3.83KB)
|   |   |   |   +-- debugger.py (42.92KB)
|   |   |   |   +-- device_orientation.py (1.18KB)
|   |   |   |   +-- dom.py (57.98KB)
|   |   |   |   +-- dom_debugger.py (9.24KB)
|   |   |   |   +-- dom_snapshot.py (35.48KB)
|   |   |   |   +-- dom_storage.py (4.91KB)
|   |   |   |   +-- emulation.py (24.4KB)
|   |   |   |   +-- event_breakpoints.py (1.26KB)
|   |   |   |   +-- fetch.py (18.17KB)
|   |   |   |   +-- headless_experimental.py (4.68KB)
|   |   |   |   +-- heap_profiler.py (11.47KB)
|   |   |   |   +-- indexed_db.py (12.46KB)
|   |   |   |   +-- input_.py (27.19KB)
|   |   |   |   +-- inspector.py (1.68KB)
|   |   |   |   +-- io.py (2.96KB)
|   |   |   |   +-- layer_tree.py (14.7KB)
|   |   |   |   +-- log.py (5.14KB)
|   |   |   |   +-- media.py (7.45KB)
|   |   |   |   +-- memory.py (6.65KB)
|   |   |   |   +-- network.py (120.84KB)
|   |   |   |   +-- overlay.py (49.08KB)
|   |   |   |   +-- page.py (99.71KB)
|   |   |   |   +-- performance.py (2.86KB)
|   |   |   |   +-- performance_timeline.py (6.47KB)
|   |   |   |   +-- profiler.py (15.4KB)
|   |   |   |   +-- py.typed (0b)
|   |   |   |   +-- runtime.py (56.5KB)
|   |   |   |   +-- schema.py (1.08KB)
|   |   |   |   +-- security.py (16.47KB)
|   |   |   |   +-- service_worker.py (10.81KB)
|   |   |   |   +-- storage.py (15.95KB)
|   |   |   |   +-- system_info.py (10.79KB)
|   |   |   |   +-- target.py (20.42KB)
|   |   |   |   +-- tethering.py (1.5KB)
|   |   |   |   +-- tracing.py (12.17KB)
|   |   |   |   +-- util.py (455b)
|   |   |   |   +-- web_audio.py (16.5KB)
|   |   |   |   +-- web_authn.py (12.06KB)
|   |   |   |   +-- __init__.py (1.26KB)
|   |   |   +-- v103 (1.76MB)
|   |   |   |   +-- accessibility.py (21.4KB)
|   |   |   |   +-- animation.py (10.85KB)
|   |   |   |   +-- audits.py (46.55KB)
|   |   |   |   +-- background_service.py (5.62KB)
|   |   |   |   +-- browser.py (20.2KB)
|   |   |   |   +-- cache_storage.py (7.63KB)
|   |   |   |   +-- cast.py (4.28KB)
|   |   |   |   +-- console.py (2.7KB)
|   |   |   |   +-- css.py (54.31KB)
|   |   |   |   +-- database.py (3.83KB)
|   |   |   |   +-- debugger.py (43.44KB)
|   |   |   |   +-- device_orientation.py (1.18KB)
|   |   |   |   +-- dom.py (57.98KB)
|   |   |   |   +-- dom_debugger.py (9.24KB)
|   |   |   |   +-- dom_snapshot.py (35.48KB)
|   |   |   |   +-- dom_storage.py (6.11KB)
|   |   |   |   +-- emulation.py (24.76KB)
|   |   |   |   +-- event_breakpoints.py (1.26KB)
|   |   |   |   +-- fetch.py (18.17KB)
|   |   |   |   +-- headless_experimental.py (4.7KB)
|   |   |   |   +-- heap_profiler.py (12.05KB)
|   |   |   |   +-- indexed_db.py (12.46KB)
|   |   |   |   +-- input_.py (27.19KB)
|   |   |   |   +-- inspector.py (1.68KB)
|   |   |   |   +-- io.py (2.96KB)
|   |   |   |   +-- layer_tree.py (14.7KB)
|   |   |   |   +-- log.py (5.14KB)
|   |   |   |   +-- media.py (7.45KB)
|   |   |   |   +-- memory.py (6.65KB)
|   |   |   |   +-- network.py (120.84KB)
|   |   |   |   +-- overlay.py (49.08KB)
|   |   |   |   +-- page.py (101.57KB)
|   |   |   |   +-- performance.py (2.86KB)
|   |   |   |   +-- performance_timeline.py (6.47KB)
|   |   |   |   +-- profiler.py (15.4KB)
|   |   |   |   +-- py.typed (0b)
|   |   |   |   +-- runtime.py (56.63KB)
|   |   |   |   +-- schema.py (1.08KB)
|   |   |   |   +-- security.py (16.47KB)
|   |   |   |   +-- service_worker.py (10.81KB)
|   |   |   |   +-- storage.py (16.22KB)
|   |   |   |   +-- system_info.py (10.79KB)
|   |   |   |   +-- target.py (20.42KB)
|   |   |   |   +-- tethering.py (1.5KB)
|   |   |   |   +-- tracing.py (12.17KB)
|   |   |   |   +-- util.py (455b)
|   |   |   |   +-- web_audio.py (16.5KB)
|   |   |   |   +-- web_authn.py (12.54KB)
|   |   |   |   +-- __init__.py (1.26KB)
|   |   |   `-- v85 (1.39MB)
|   |   |       +-- accessibility.py (14.66KB)
|   |   |       +-- animation.py (10.85KB)
|   |   |       +-- application_cache.py (5.6KB)
|   |   |       +-- audits.py (16.67KB)
|   |   |       +-- background_service.py (5.62KB)
|   |   |       +-- browser.py (16.89KB)
|   |   |       +-- cache_storage.py (7.63KB)
|   |   |       +-- cast.py (3.89KB)
|   |   |       +-- console.py (2.7KB)
|   |   |       +-- css.py (41.9KB)
|   |   |       +-- database.py (3.83KB)
|   |   |       +-- debugger.py (42.45KB)
|   |   |       +-- device_orientation.py (1.18KB)
|   |   |       +-- dom.py (53.12KB)
|   |   |       +-- dom_debugger.py (8.39KB)
|   |   |       +-- dom_snapshot.py (33.27KB)
|   |   |       +-- dom_storage.py (4.91KB)
|   |   |       +-- emulation.py (20.29KB)
|   |   |       +-- fetch.py (15.68KB)
|   |   |       +-- headless_experimental.py (4.68KB)
|   |   |       +-- heap_profiler.py (10.94KB)
|   |   |       +-- indexed_db.py (12.46KB)
|   |   |       +-- input_.py (19.24KB)
|   |   |       +-- inspector.py (1.68KB)
|   |   |       +-- io.py (2.96KB)
|   |   |       +-- layer_tree.py (14.7KB)
|   |   |       +-- log.py (4.94KB)
|   |   |       +-- media.py (6.45KB)
|   |   |       +-- memory.py (6.65KB)
|   |   |       +-- network.py (84.85KB)
|   |   |       +-- overlay.py (24.24KB)
|   |   |       +-- page.py (69.14KB)
|   |   |       +-- performance.py (2.86KB)
|   |   |       +-- profiler.py (16.77KB)
|   |   |       +-- py.typed (0b)
|   |   |       +-- runtime.py (50.48KB)
|   |   |       +-- schema.py (1.08KB)
|   |   |       +-- security.py (16.52KB)
|   |   |       +-- service_worker.py (10.81KB)
|   |   |       +-- storage.py (8.08KB)
|   |   |       +-- system_info.py (10.79KB)
|   |   |       +-- target.py (18.08KB)
|   |   |       +-- tethering.py (1.5KB)
|   |   |       +-- tracing.py (10.31KB)
|   |   |       +-- util.py (455b)
|   |   |       +-- web_audio.py (16.5KB)
|   |   |       +-- web_authn.py (9.2KB)
|   |   |       +-- __init__.py (1.23KB)
|   |   +-- html5 (3.82KB)
|   |   |   +-- application_cache.py (1.59KB)
|   |   |   +-- __init__.py (787b)
|   |   +-- keys.py (2.29KB)
|   |   +-- log.py (5.92KB)
|   |   +-- mutation-listener.js (1.9KB)
|   |   +-- options.py (8.79KB)
|   |   +-- print_page_options.py (8.3KB)
|   |   +-- proxy.py (10.52KB)
|   |   +-- service.py (5.66KB)
|   |   +-- timeouts.py (3.74KB)
|   |   +-- utils.py (4.37KB)
|   |   +-- virtual_authenticator.py (8.65KB)
|   |   +-- window.py (929b)
|   |   +-- __init__.py (787b)
|   +-- edge (13.8KB)
|   |   +-- options.py (1.66KB)
|   |   +-- service.py (2.21KB)
|   |   +-- webdriver.py (3.23KB)
|   |   +-- __init__.py (787b)
|   +-- firefox (90.62KB)
|   |   +-- extension_connection.py (2.77KB)
|   |   +-- firefox_binary.py (8.58KB)
|   |   +-- firefox_profile.py (14.14KB)
|   |   +-- options.py (5.25KB)
|   |   +-- remote_connection.py (1.68KB)
|   |   +-- service.py (2.62KB)
|   |   +-- webdriver.py (13.15KB)
|   |   +-- webdriver_prefs.json (2.76KB)
|   |   +-- __init__.py (787b)
|   +-- ie (36.68KB)
|   |   +-- options.py (11.26KB)
|   |   +-- service.py (2.28KB)
|   |   +-- webdriver.py (5.38KB)
|   |   +-- __init__.py (787b)
|   +-- remote (341.63KB)
|   |   +-- bidi_connection.py (968b)
|   |   +-- command.py (4.89KB)
|   |   +-- errorhandler.py (11.7KB)
|   |   +-- file_detector.py (1.77KB)
|   |   +-- findElements.js (52.56KB)
|   |   +-- getAttribute.js (42.15KB)
|   |   +-- isDisplayed.js (42.96KB)
|   |   +-- mobile.py (2.61KB)
|   |   +-- remote_connection.py (17.59KB)
|   |   +-- script_key.py (1009b)
|   |   +-- shadowroot.py (2.94KB)
|   |   +-- switch_to.py (4.96KB)
|   |   +-- utils.py (978b)
|   |   +-- webdriver.py (42.39KB)
|   |   +-- webelement.py (16.79KB)
|   |   +-- __init__.py (787b)
|   +-- safari (27.63KB)
|   |   +-- options.py (4.14KB)
|   |   +-- permissions.py (934b)
|   |   +-- remote_connection.py (1.47KB)
|   |   +-- service.py (2.44KB)
|   |   +-- webdriver.py (6.12KB)
|   |   +-- __init__.py (787b)
|   +-- support (115.69KB)
|   |   +-- abstract_event_listener.py (1.98KB)
|   |   +-- color.py (12.01KB)
|   |   +-- events.py (92b)
|   |   +-- event_firing_webdriver.py (8.79KB)
|   |   +-- expected_conditions.py (15.25KB)
|   |   +-- relative_locator.py (5.89KB)
|   |   +-- select.py (9.04KB)
|   |   +-- ui.py (863b)
|   |   +-- wait.py (5.02KB)
|   |   +-- __init__.py (787b)
|   +-- webkitgtk (13.78KB)
|   |   +-- options.py (2.61KB)
|   |   +-- service.py (1.59KB)
|   |   +-- webdriver.py (2.9KB)
|   |   +-- __init__.py (787b)
|   +-- wpewebkit (12.68KB)
|   |   +-- options.py (2.16KB)
|   |   +-- service.py (1.59KB)
|   |   +-- webdriver.py (2.69KB)
|   |   +-- __init__.py (787b)
|   +-- __init__.py (2.37KB)
+-- __init__.py (811b)

puml

@startuml

package chrome <<folder>> {
    package options.py <<Frame>> {
        class Options
        {
        +default_capabilities
        +enable_mobile()
        }
    }
    package service.py <<Frame>> {
        class Service
        {
        +__init__()
        }
    }
    package webdriver.py <<Frame>> {
        class WebDriver
        {
        +__init__()
        }
    }
    }

package chromium <<folder>> {
    package options.py <<Frame>> {
        class ChromiumOptions
        {
        +__init__()
        +binary_location
        +debugger_address
        +extensions
        +add_extension()
        +add_encoded_extension()
        +experimental_options
        +add_experimental_option()
        +headless
        +to_capabilities()
        +default_capabilities
        }
    }
    package remote_connection.py <<Frame>> {
        class ChromiumRemoteConnection
        {
        +__init__()
        }
    }
    package service.py <<Frame>> {
        class ChromiumService
        {
        +__init__()
        +command_line_args()
        }
    }
    package webdriver.py <<Frame>> {
        class ChromiumDriver
        {
        +__init__()
        +launch_app()
        +get_network_conditions()
        +set_network_conditions()
        +delete_network_conditions()
        +set_permissions()
        +execute_cdp_cmd()
        +get_sinks()
        +get_issue_message()
        +set_sink_to_use()
        +start_desktop_mirroring()
        +start_tab_mirroring()
        +stop_casting()
        +quit()
        +create_options()
        }
    }
    }

package common <<folder>> {
    package options.py <<Frame>> {
        class BaseOptions {}
        class ArgOptions {
        +__init__()
        +arguments
        +add_argument()
        +ignore_local_proxy_environment_variables()
        +to_capabilities()
        +default_capabilities
        }

    }
    package service.py <<Frame>> {
        class service的Service
        {
        +__init__()
        +service_url
        +command_line_args()
        +start()
        +assert_process_still_running()
        +is_connectable()
        +send_remote_shutdown_command()
        +stop()
        +__del__()
        }
    }
}

package remote <<folder>> {
    package webdriver.py <<Frame>> {
        class RemoteWebDriver
        {
        +get_timeout()
        +reset_timeout()
        +get_certificate_bundle_path()
        +set_certificate_bundle_path()
        +get_remote_connection_headers()
        +_get_proxy_url()
        +_identify_http_proxy_auth()
        +_seperate_http_proxy_auth()
        +_get_connection_manager()
        +__init__()
        +execute()
        +_request()
        +close()
        }
        class BaseWebDriver{}

    }
    package remote_connection.py <<Frame>> {
        class RemoteConnection
    }
    }


Options --> ChromiumOptions: 继承
Service --> ChromiumService: 继承
WebDriver --> ChromiumDriver: 继承
ChromiumRemoteConnection --> RemoteConnection:继承

ChromiumOptions -->ArgOptions: 继承
ArgOptions --> BaseOptions: 继承
ChromiumService --> service的Service: 继承

ChromiumDriver --> RemoteWebDriver: 继承
RemoteWebDriver --> BaseWebDriver: 继承



@enduml
09-22 12:19