基于4.3
pip install selenium
安装好后,在sitepackages下
2个主要的目录,common
和webdriver
该目录一共就一个模块exceptions.py
其中定义了32个异常
,竟然有个同学面试的时候被问过
异常 | 说明 |
---|---|
WebDriverException | 主异常,下面的都继承于它 |
InvalidSwitchToTargetException | Thrown when frame or window target to be switched doesn't exist. |
NoSuchFrameException | Thrown when frame target to be switched doesn't exist. |
NoSuchWindowException | Thrown when window target to be switched doesn't exist. |
NoSuchElementException | Thrown when element could not be found. |
NoSuchAttributeException | Thrown when the attribute of element could not be found. |
NoSuchShadowRootException | Thrown when trying to access the shadow root of an element when it does not have a shadow root attached. |
StaleElementReferenceException | Thrown when a reference to an element is now "stale". |
InvalidElementStateException | Thrown when a command could not be completed because the element is in an invalid state. |
UnexpectedAlertPresentException | Thrown when an unexpected alert has appeared. |
NoAlertPresentException | Thrown when switching to no presented alert. |
ElementNotVisibleException | Thrown when an element is present on the DOM, but it is not visible, and so is not able to be interacted with. |
ElementNotInteractableException | Thrown when an element is present in the DOM but interactions with that element will hit another element due to paint order |
ElementNotSelectableException | Thrown when trying to select an unselectable element. |
InvalidCookieDomainException | Thrown when attempting to add a cookie under a different domain than the current URL. |
UnableToSetCookieException | Thrown when a driver fails to set a cookie. |
RemoteDriverServerException | 源码没有给__doc__ |
TimeoutException | Thrown when a command does not complete in enough time. |
MoveTargetOutOfBoundsException | Thrown when the target provided to the ActionsChains move() method is invalid, i.e. out of document. |
UnexpectedTagNameException | Thrown when a support class did not get an expected web element. |
InvalidSelectorException | Thrown when the selector which is used to find an element does not return a WebElement |
ImeNotAvailableException | Thrown when IME support is not available. |
ImeActivationFailedException | Thrown when activating an IME engine has failed. |
InvalidArgumentException | The arguments passed to a command are either invalid or malformed. |
JavascriptException | An error occurred while executing JavaScript supplied by the user. |
NoSuchCookieException | No cookie matching the given path name was found amongst the associated cookies of the current browsing context's active document. |
ScreenshotException | A screen capture was made impossible. |
ElementClickInterceptedException | The Element Click command could not be completed because the element receiving the events is obscuring the element that was requested to be clicked. |
InsecureCertificateException | Navigation caused the user agent to hit a certificate warning, which is usually the result of an expired or invalid TLS certificate. |
InvalidCoordinatesException | The coordinates provided to an interaction's operation are invalid. |
InvalidSessionIdException | Occurs if the given session id is not in the list of active sessions, meaning the session either does not exist or that it's not active. |
SessionNotCreatedException | A new session could not be created. |
UnknownMethodException | The requested command matched a known URL but did not match any methods for that URL. |
注
Stale
means the element no longer appears on the DOM of the page.WebDriverException
3个初始化参数,msg/screen/stacktrace,仅仅定义了__str__
UnexpectedAlertPresentException
就它定义了自己的__str__
,加了alert_text
进来这是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的核心功能所在
puml源码见附录
注
service的Service
这个类原名是Service
,但如果这么写,由于有重名就会关联错误File-Dir | 作用 |
---|---|
actions | 动作链的底层 |
bidi | W3C WebDriver的下一代协议, 旨在提供由所有浏览器实现稳定的API |
devtools | 开发者工具,适配不同的浏览器版本v85 v101等等,实现会有细微差异 |
html5 | 后续会移除 |
__init__.py |
|
action_chains.py |
鼠标动作链的所有方法(21个) |
alert.py |
警告框 |
by.py |
8个定位方法 |
desired_capabilities.py | 预期能力 |
keys.py |
65个按键 |
log.py | Bidi相关的日志处理 |
mutation-listener.js | 被log.py使用 |
options.py | 选项类的实现 |
print_page_options.py | 页面打印选项? |
proxy.py | 代理? |
service.py | Service基类 |
timeouts.py | 超时类 |
utils.py | 工具类 |
virtual_authenticator.py | 虚拟身份验证器 |
window.py | 窗口类型 |
鼠标方法 | 参数 | 说明 |
---|---|---|
click★★ | on_element=None | 点击 |
click_and_hold★ | on_element=None | 点击并按住 |
context_click★ | on_element=None | 右键 |
double_click★ | on_element=None | 双击 |
drag_and_drop★★ | source, target | 拖拽 |
drag_and_drop_by_offset★ | source, xoffset, yoffset | 拖拽(依据偏移量) |
key_down★ | value, element=None | 按下某个键 |
key_up★ | value, element=None | 抬起某个键 |
move_by_offset★ | xoffset, yoffset | 移动(依据偏移量) |
move_to_element★★ | to_element | 移动到元素 |
move_to_element_with_offset | to_element, xoffset, yoffset | 移动到元素(依据偏移量) |
pause | seconds | 暂停 |
perform★★★ | 无参数 | 执行 |
release★ | on_element=None | 释放 |
reset_actions | 无参数 | 重置动作 |
scroll | x: int, y: int, delta_x: int, delta_y: int, duration: int = 0, origin: str = "viewport" | 滚动(废弃) |
scroll_by_amount | delta_x: int, delta_y: int | 通过给定的偏差滚动 |
scroll_from_origin | scroll_origin: ScrollOrigin, delta_x: int, delta_y: int | 通过给定的原始位置+偏差滚动 |
scroll_to_element | element | 滚动到元素 |
send_keys★ | *keys_to_send | 发送按键 |
send_keys_to_element★ | element, *keys_to_send | 发送按键到元素 |
这个比较简单
一个类Alert
包括
一个属性text
三个方法dismiss
accept
send_keys
一个类By
8个定位方式
定位方式 | 说明 |
---|---|
id | 元素id属性的值 |
xpath | xpath表达式 |
link text | a标签的文本 |
partial link text | a标签的部分文本 |
name | 元素name属性的值 |
tag name | 标签名 |
class name | 元素class属性的值 |
css selector | css 选择器表达式 |
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'
File | 作用 |
---|---|
__init__.py |
空 |
bidi_connection.py | bidi连接 |
command.py | 元命令 |
errorhandler.py | 错 误处理 |
file_detector.py | 文件检测 |
findElements.js | 定位元素的js |
getAttribute.js | 获取属性的js |
isDisplayed.js | 是否显示的js |
mobile.py | 移动设备相关 |
remote_connection.py | 远程连接 |
script_key.py | 一个uuid的处理 |
shadowroot.py | Shadow DOM 下的根相关内容 |
switch_to.py | 切换 |
utils.py | 工具模块 |
webdriver.py |
webdriver核心技术 |
webelement.py |
webelement核心技术 |
属性方法 | 说明 |
---|---|
add_cookie | 添加cookie |
add_credential | |
add_virtual_authenticator | 添加虚拟身份验证器 |
application_cache | |
back | 浏览器后腿 |
bidi_connection | |
capabilities | |
caps | |
close | 关闭tab页 |
command_executor | |
create_options | |
create_web_element | |
current_url | 当前的URL地址 |
current_window_handle | 当前的窗口句柄 |
delete_all_cookies | 删除所有cookies |
delete_cookie | 删除某个cookie |
delete_network_conditions | |
desired_capabilities | |
error_handler | |
execute | |
execute_async_script | |
execute_cdp_cmd | |
execute_script | 执行js |
file_detector | |
file_detector_context | |
find_element | 单个元素定位 |
find_elements | 多个元素定位 |
forward | 前进 |
fullscreen_window | 全屏 |
get | 打开网址 |
get_cookie | 获取某个cookie值 |
get_cookies | 获取所有cookie |
get_credentials | |
get_issue_message | |
get_log | |
get_network_conditions | |
get_pinned_scripts | |
get_screenshot_as_base64 | |
get_screenshot_as_file | |
get_screenshot_as_png | |
get_sinks | |
get_window_position | 获取窗口位置(xy值) |
get_window_rect | 获取窗口矩形数据(包括position和size) |
get_window_size | 获取窗口大小(width和height) |
implicitly_wait | 隐式等待 |
launch_app | |
log_types | |
maximize_window | 最大化 |
minimize_window | 最小化 |
mobile | |
name | 浏览器名 |
orientation | |
page_source | 页面源码 |
pin_script | |
pinned_scripts | |
port | |
print_page | |
quit | 退出浏览器进程 |
refresh | 刷新 |
remove_all_credentials | |
remove_credential | |
remove_virtual_authenticator | |
save_screenshot | 保存页面截图 |
service | |
session_id | |
set_network_conditions | |
set_page_load_timeout | |
set_permissions | |
set_script_timeout | |
set_sink_to_use | |
set_user_verified | |
set_window_position | 设置窗口位置 |
set_window_rect | 设置窗口矩形 |
set_window_size | 设置窗口大小 |
start_client | |
start_desktop_mirroring | |
start_session | |
start_tab_mirroring | |
stop_casting | |
stop_client | |
switch_to | 切换 |
timeouts | |
title | 标题 |
unpin | |
vendor_prefix | |
virtual_authenticator_id | |
window_handles | 窗口句柄组成的列表 |
属性方法 | 说明 |
---|---|
accessible_name | |
aria_role | |
clear | 清空内容 |
click | 点击元素 |
find_element | 元素上定位单个子元素 |
find_elements | 元素上定位多个子元素 |
get_attribute | 获取html属性 |
get_dom_attribute | |
get_property | |
id | |
is_displayed | 是否显示 |
is_enabled | 是否使能 |
is_selected | 是否选中 |
location | 位置 |
location_once_scrolled_into_view | 滚动到可见 |
parent | |
rect | 矩形 |
screenshot | |
screenshot_as_base64 | 元素截图base64编码 |
screenshot_as_png | 元素截图保存为png |
send_keys | 发送按键信息(输入内容) |
shadow_root | |
size | 元素大小 |
submit | 提交内容 |
tag_name | 标签名 |
text | 标签文本 |
value_of_css_property | css属性值 |
File | 作用 |
---|---|
__init__.py |
空 |
abstract_event_listener.py | |
color.py |
颜色处理 |
event_firing_webdriver.py | |
events.py | |
expected_conditions.py |
预期条件 |
relative_locator.py |
相对定位 |
select.py |
select控件 |
ui.py | 暂未实现 |
wait.py |
等待处理 |
方法 | 说明 |
---|---|
alert_is_present | 判断alert是否存在,若存在则切换到alert,若不存在则返回False |
all_of | 传入多个条件,都成立才返回True |
any_of | 传入多个条件,任意一个成立就返回True |
element_attribute_to_include | 判断元素属性是否存在,传入元素定位器和属性名 |
element_located_selection_state_to_be | 判断某元素是否与预期相同,相同则返回True,不同则返回False,locator为一个(by, path)元组 |
element_located_to_be_selected | 判断某元素是否被选,locator为一个(by, path)元组 |
element_selection_state_to_be | 判断某元素的选中状态是否与预期相同,相同则返回True,不同则返回False |
element_to_be_clickable | 判断某元素是否可访问并且可启用,比如能够点击,若可以则返回元素本身,否则返回False |
element_to_be_selected | 判断某元素是否被选中 |
frame_to_be_available_and_switch_to_it | 判断某个frame是否可以切换过去,若可以则切换到该frame,否则返回False |
invisibility_of_element | 判断元素是否隐藏[吴],继承自invisibility_of_element_located,入参可以是一个locator也可以是webelement |
invisibility_of_element_locate | 判断元素是否隐藏,入参是locator |
new_window_is_opened | 新窗口是否打开,入参是当前的句柄列表 |
none_of | 传入多个条件,都不成立才返回True |
number_of_windows_to_be | 判断window数量是否为N,入参N是数字 |
presence_of_all_elements_located | 用于判断定位的元素范围内,至少有一个元素存在于页面当中,存在则以list形式返回元素本身,不存在则报错 |
presence_of_element_located | 用于判断一个元素存在于页面DOM树中,存在则返回元素本身,不存在则报错 |
staleness_of | 判断某个元素是否不再附加于于DOM树中,不再附加的话返回True,依旧存在返回False。可以用于判断页面是否刷新了 |
text_to_be_present_in_element | 判断某文本是否是存在于特定元素的value值中,存在则返回True,不存在则返回False,对于查看没有value值的元素,也会返回False |
text_to_be_present_in_element_value | 文本在指定元素的value属性值中,入参是locator和文本 |
text_to_be_present_in_element_attribute | 文本出现在元素的属性中,传入元素定位器、属性和文本 |
title_contains | 用于判断网页title是否包含特定文本(英文区分大小写),若包含则返回True,不包含返回False。 |
title_is | 用于判断网页title是否是特定文本(英文区分大小写),若完全相同则返回True,否则返回False |
url_changes | url是否改变,入参是url |
url_contains | url是否包含,入参是url,入参in当前的url |
url_matches | url是否匹配指定模式,传入一个正则表达式模式 |
url_to_be | url应该是,入参和当前的url比较 |
visibility_of | visibility_of(element)同面visibility_of_element_located(locator),不过参数从locator的元组变为元素 |
visibility_of_all_elements_located | 所有元素都可见,传入一个locator定位一组元素 |
visibility_of_any_elements_located | 只要有一个元素可见,传入一个locator定位一组元素 |
visibility_of_element_located | 用于判断特定元素是否存在于DOM树中并且可见,可见意为元素的高和宽都大于0,元素存在返回元素本身,否则返回False |
2个函数with_tag_name
和locate_with
一个类RelativeBy
主要是5个方法above
、below
、to_left_of
、to_right_of
、near
定义了一个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
显式等待的核心逻辑
一个类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
异常
下面的代码
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.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的操作本质都是类似的
操作 | 源码 |
---|---|
driver.maximize_window() | driver.execute(Command.W3C_MAXIMIZE_WINDOW,None) |
driver.get(url) | driver.execute(Command.GET, {'url': url}) |
driver.find_element('id','ls_username') | driver.execute(Command.FIND_ELEMENT, { 'using': 'id', 'value': 'ls_username'})['value'] |
其中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)
@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
Playwright是新兴的自动化测试工具,拥有丰富的功能和API,隐藏在众多的爬虫和自动化工具背后,而多模LLM的出现让Playwright可以如虎添翼,自动化智能化的RPA工具预计将会井喷般出现。