selenium库浅析
pip install selenium
安装好后,在sitepackages下
2个主要的目录,common
和webdriver
1- common
该目录一共就一个模块exceptions.py
① exceptions.py
其中定义了32个异常
,竟然有个同学面试的时候被问过
注
Stale
means the element no longer appears on the DOM of the page.WebDriverException
3个初始化参数,msg/screen/stacktrace,仅仅定义了__str__
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个包,common
和support
和remote
这是selenium的核心功能所在
① chrome包
puml源码见附录
注
service的Service
这个类原名是Service
,但如果这么写,由于有重名就会关联错误- 下面展示了chrome下3个文件中每个类的继承关系
② 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_name
和locate_with
一个类RelativeBy
主要是5个方法above
、below
、to_left_of
、to_right_of
、near
select
定义了一个Select
类
3个属性options、all_selected_options、first_selected_option
七个方法select_by_value
select_by_index
select_by_visible_text
deselect_all
和deselect_by_value
deselect_by_index
deselect_by_visible_text
wait
显式等待的核心逻辑
一个类WebDriverWait
2个方法until
和until_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)
这么解释
用传过来的
method
,call它,传入self._driver
得到一个
value
,如果有value就直接return如果没有得到就
time.sleep(轮询间隔)
加个判断如果当前时间超过了你的预设时间
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()
做完这个,正常情况你会打开一个浏览器
这是相对比较复杂的一个过程
其继承关系如下
注
其中
RemoteWebDriver
是别名,实际是WebDriver
,不过是remote
下的,跟第一个不同BaseWebDriver
是个抽象基类RemoteWebDriver
中会执行self.start_session(capabilities, browser_profile)
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')
- 就是这句
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的操作本质都是类似的
其中
Command
类定义了JsonWireProtocol
,比如Command.W3C_MAXIMIZE_WINDOW='w3cMaximizeWindow'
而
execute
这个方法接收2个参数driver_command
和params
,核心是response = self.command_executor.execute(driver_command, params)
其中
command_executor
你可以理解为是chromedriver
这个驱动(REST API SERVER),虽然默认值是'http://127.0.0.1:4444'
Grid的地址。它的本质会去调度self._request(command_info[0], url, body=data)
这里跟requests
库的调用就即可相似了,虽然底层的差异还是蛮多的举个例子,调试第二行
实例化
得到的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