基于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工具预计将会井喷般出现。