元素动作返回元素自己;修改NoneElement打印的值;修复is_displayed参数有时不正确问题

This commit is contained in:
g1879 2024-08-14 18:38:38 +08:00
parent cdced6e8d7
commit 99f2de7e5b
21 changed files with 1329 additions and 946 deletions

View File

@ -13,10 +13,6 @@ from .options_manage import OptionsManager
class ChromiumOptions(object):
def __init__(self, read_file=True, ini_path=None):
"""
:param read_file: 是否从默认ini文件中读取配置信息
:param ini_path: ini文件路径为None则读取默认ini文件
"""
self._user_data_path = None
self._user = 'Default'
self._prefs_to_del = []
@ -82,105 +78,81 @@ class ChromiumOptions(object):
@property
def download_path(self):
"""默认下载路径文件路径"""
return self._download_path
@property
def browser_path(self):
"""浏览器启动文件路径"""
return self._browser_path
@property
def user_data_path(self):
"""返回用户数据文件夹路径"""
return self._user_data_path
@property
def tmp_path(self):
"""返回临时文件夹路径"""
return self._tmp_path
@property
def user(self):
"""返回用户配置文件夹名称"""
return self._user
@property
def load_mode(self):
"""返回页面加载策略,'normal', 'eager', 'none'"""
return self._load_mode
@property
def timeouts(self):
"""返回timeouts设置"""
return self._timeouts
@property
def proxy(self):
"""返回代理设置"""
return self._proxy
@property
def address(self):
"""返回浏览器地址ip:port"""
return self._address
@property
def arguments(self):
"""返回浏览器命令行设置列表"""
return self._arguments
@property
def extensions(self):
"""以list形式返回要加载的插件路径"""
return self._extensions
@property
def preferences(self):
"""返回用户首选项配置"""
return self._prefs
@property
def flags(self):
"""返回实验项配置"""
return self._flags
@property
def system_user_path(self):
"""返回是否使用系统安装的浏览器所使用的用户数据文件夹"""
return self._system_user_path
@property
def is_existing_only(self):
"""返回是否只接管现有浏览器方式"""
return self._existing_only
@property
def is_auto_port(self):
"""返回是否使用自动端口和用户文件如指定范围则返回范围tuple"""
return self._auto_port
@property
def retry_times(self):
"""返回连接失败时的重试次数"""
return self._retry_times
@property
def retry_interval(self):
"""返回连接失败时的重试间隔(秒)"""
return self._retry_interval
@property
def is_headless(self):
"""返回是否无头模式"""
return self._is_headless
def set_retry(self, times=None, interval=None):
"""设置连接失败时的重试操作
:param times: 重试次数
:param interval: 重试间隔
:return: 当前对象
"""
if times is not None:
self._retry_times = times
if interval is not None:
@ -188,11 +160,6 @@ class ChromiumOptions(object):
return self
def set_argument(self, arg, value=None):
"""设置浏览器配置的argument属性
:param arg: 属性名
:param value: 属性值有值的属性传入值没有的传入None如传入False删除该项
:return: 当前对象
"""
self.remove_argument(arg)
if value is not False:
if arg == '--headless':
@ -211,10 +178,6 @@ class ChromiumOptions(object):
return self
def remove_argument(self, value):
"""移除一个argument项
:param value: 设置项名有值的设置项传入设置名称即可
:return: 当前对象
"""
elements_to_delete = [arg for arg in self._arguments if arg == value or arg.startswith(f'{value}=')]
if not elements_to_delete:
return self
@ -227,10 +190,6 @@ class ChromiumOptions(object):
return self
def add_extension(self, path):
"""添加插件
:param path: 插件路径可指向文件夹
:return: 当前对象
"""
path = Path(path)
if not path.exists():
raise OSError('插件路径不存在。')
@ -238,43 +197,22 @@ class ChromiumOptions(object):
return self
def remove_extensions(self):
"""移除所有插件
:return: 当前对象
"""
self._extensions = []
return self
def set_pref(self, arg, value):
"""设置Preferences文件中的用户设置项
:param arg: 设置项名称
:param value: 设置项值
:return: 当前对象
"""
self._prefs[arg] = value
return self
def remove_pref(self, arg):
"""删除用户首选项设置,不能删除已设置到文件中的项
:param arg: 设置项名称
:return: 当前对象
"""
self._prefs.pop(arg, None)
return self
def remove_pref_from_file(self, arg):
"""删除用户配置文件中已设置的项
:param arg: 设置项名称
:return: 当前对象
"""
self._prefs_to_del.append(arg)
return self
def set_flag(self, flag, value=None):
"""设置实验项
:param flag: 设置项名称
:param value: 设置项的值为False则删除该项
:return: 当前对象
"""
if value is False:
self._flags.pop(flag, None)
else:
@ -282,32 +220,22 @@ class ChromiumOptions(object):
return self
def clear_flags_in_file(self):
"""删除浏览器配置文件中已设置的实验项"""
self.clear_file_flags = True
return self
def clear_flags(self):
"""清空本对象已设置的flag参数"""
self._flags = {}
return self
def clear_arguments(self):
"""清空本对象已设置的argument参数"""
self._arguments = []
return self
def clear_prefs(self):
"""清空本对象已设置的pref参数"""
self._prefs = {}
return self
def set_timeouts(self, base=None, page_load=None, script=None):
"""设置超时时间,单位为秒
:param base: 默认超时时间
:param page_load: 页面加载超时时间
:param script: 脚本运行超时时间
:return: 当前对象
"""
if base is not None:
self._timeouts['base'] = base
if page_load is not None:
@ -318,82 +246,42 @@ class ChromiumOptions(object):
return self
def set_user(self, user='Default'):
"""设置使用哪个用户配置文件夹
:param user: 用户文件夹名称
:return: 当前对象
"""
self.set_argument('--profile-directory', user)
self._user = user
return self
def headless(self, on_off=True):
"""设置是否隐藏浏览器界面
:param on_off: 开或关
:return: 当前对象
"""
on_off = 'new' if on_off else on_off
return self.set_argument('--headless', on_off)
def no_imgs(self, on_off=True):
"""设置是否加载图片
:param on_off: 开或关
:return: 当前对象
"""
on_off = None if on_off else False
return self.set_argument('--blink-settings=imagesEnabled=false', on_off)
def no_js(self, on_off=True):
"""设置是否禁用js
:param on_off: 开或关
:return: 当前对象
"""
on_off = None if on_off else False
return self.set_argument('--disable-javascript', on_off)
def mute(self, on_off=True):
"""设置是否静音
:param on_off: 开或关
:return: 当前对象
"""
on_off = None if on_off else False
return self.set_argument('--mute-audio', on_off)
def incognito(self, on_off=True):
"""设置是否使用无痕模式启动
:param on_off: 开或关
:return: 当前对象
"""
on_off = None if on_off else False
return self.set_argument('--incognito', on_off)
def new_env(self, on_off=True):
"""设置是否使用全新浏览器环境
:param on_off: 开或关
:return: 当前对象
"""
self._new_env = on_off
return self
def ignore_certificate_errors(self, on_off=True):
"""设置是否忽略证书错误
:param on_off: 开或关
:return: 当前对象
"""
on_off = None if on_off else False
return self.set_argument('--ignore-certificate-errors', on_off)
def set_user_agent(self, user_agent):
"""设置user agent
:param user_agent: user agent文本
:return: 当前对象
"""
return self.set_argument('--user-agent', user_agent)
def set_proxy(self, proxy):
"""设置代理
:param proxy: 代理url和端口
:return: 当前对象
"""
if search(r'.*?:.*?@.*?\..*', proxy):
print('你似乎在设置使用账号密码的代理,暂时不支持这种代理,可自行用插件实现需求。')
if proxy.lower().startswith('socks'):
@ -402,13 +290,6 @@ class ChromiumOptions(object):
return self.set_argument('--proxy-server', proxy)
def set_load_mode(self, value):
"""设置load_mode可接收 'normal', 'eager', 'none'
normal默认情况下使用, 等待所有资源下载完成
eagerDOM访问已准备就绪, 但其他资源 (如图像) 可能仍在加载中
none完全不阻塞
:param value: 可接收 'normal', 'eager', 'none'
:return: 当前对象
"""
if value not in ('normal', 'eager', 'none'):
raise ValueError("只能选择 'normal', 'eager', 'none'")
self._load_mode = value.lower()
@ -446,52 +327,28 @@ class ChromiumOptions(object):
return self
def set_local_port(self, port):
"""设置本地启动端口
:param port: 端口号
:return: 当前对象
"""
self._address = f'127.0.0.1:{port}'
self._auto_port = False
return self
def set_address(self, address):
"""设置浏览器地址,格式'ip:port'
:param address: 浏览器地址
:return: 当前对象
"""
address = address.replace('localhost', '127.0.0.1').lstrip('http://').lstrip('https://')
self._address = address
return self
def set_browser_path(self, path):
"""设置浏览器可执行文件路径
:param path: 浏览器路径
:return: 当前对象
"""
self._browser_path = str(path)
return self
def set_download_path(self, path):
"""设置下载文件保存路径
:param path: 下载路径
:return: 当前对象
"""
self._download_path = '.' if path is None else str(path)
return self
def set_tmp_path(self, path):
"""设置临时文件文件保存路径
:param path: 下载路径
:return: 当前对象
"""
self._tmp_path = str(path)
return self
def set_user_data_path(self, path):
"""设置用户文件夹路径
:param path: 用户文件夹路径
:return: 当前对象
"""
u = str(path)
self.set_argument('--user-data-dir', u)
self._user_data_path = u
@ -499,27 +356,14 @@ class ChromiumOptions(object):
return self
def set_cache_path(self, path):
"""设置缓存路径
:param path: 缓存路径
:return: 当前对象
"""
self.set_argument('--disk-cache-dir', str(path))
return self
def use_system_user_path(self, on_off=True):
"""设置是否使用系统安装的浏览器默认用户文件夹
:param on_off: 开或关
:return: 当前对象
"""
self._system_user_path = on_off
return self
def auto_port(self, on_off=True, scope=None):
"""自动获取可用端口
:param on_off: 是否开启自动获取端口号
:param scope: 指定端口范围不含最后的数字为None则使用[9600-59600)
:return: 当前对象
"""
if on_off:
self._auto_port = scope if scope else (9600, 59600)
else:
@ -527,18 +371,10 @@ class ChromiumOptions(object):
return self
def existing_only(self, on_off=True):
"""设置只接管已有浏览器,不自动启动新的
:param on_off: 是否开启自动获取端口号
:return: 当前对象
"""
self._existing_only = on_off
return self
def save(self, path=None):
"""保存设置到文件
:param path: ini文件的路径 None 保存到当前读取的配置文件传入 'default' 保存到默认ini文件
:return: 保存文件的绝对路径
"""
if path == 'default':
path = (Path(__file__).parent / 'configs.ini').absolute()
@ -585,7 +421,6 @@ class ChromiumOptions(object):
return path
def save_to_default(self):
"""保存当前配置到默认ini文件"""
return self.save('default')
def __repr__(self):

View File

@ -36,144 +36,368 @@ class ChromiumOptions(object):
_is_headless: bool = ...
_ua_set: bool = ...
def __init__(self, read_file: [bool, None] = True, ini_path: Union[str, Path] = None): ...
def __init__(self,
read_file: [bool, None] = True,
ini_path: Union[str, Path] = None):
"""
:param read_file: 是否从默认ini文件中读取配置信息
:param ini_path: ini文件路径为None则读取默认ini文件
"""
...
@property
def download_path(self) -> str: ...
def download_path(self) -> str:
"""默认下载路径文件路径"""
...
@property
def browser_path(self) -> str: ...
def browser_path(self) -> str:
"""浏览器启动文件路径"""
...
@property
def user_data_path(self) -> str: ...
def user_data_path(self) -> str:
"""返回用户数据文件夹路径"""
...
@property
def tmp_path(self) -> Optional[str]: ...
def tmp_path(self) -> Optional[str]:
"""返回临时文件夹路径"""
...
@property
def user(self) -> str: ...
def user(self) -> str:
"""返回用户配置文件夹名称"""
...
@property
def load_mode(self) -> str: ...
def load_mode(self) -> str:
"""返回页面加载策略,'normal', 'eager', 'none'"""
...
@property
def timeouts(self) -> dict: ...
def timeouts(self) -> dict:
"""返回timeouts设置"""
...
@property
def proxy(self) -> str: ...
def proxy(self) -> str:
"""返回代理设置"""
...
@property
def address(self) -> str: ...
def address(self) -> str:
"""返回浏览器地址ip:port"""
...
@property
def arguments(self) -> list: ...
def arguments(self) -> list:
"""返回浏览器命令行设置列表"""
...
@property
def extensions(self) -> list: ...
def extensions(self) -> list:
"""以list形式返回要加载的插件路径"""
...
@property
def preferences(self) -> dict: ...
def preferences(self) -> dict:
"""返回用户首选项配置"""
...
@property
def flags(self) -> dict: ...
def flags(self) -> dict:
"""返回实验项配置"""
...
@property
def system_user_path(self) -> bool: ...
def system_user_path(self) -> bool:
"""返回是否使用系统安装的浏览器所使用的用户数据文件夹"""
...
@property
def is_existing_only(self) -> bool: ...
def is_existing_only(self) -> bool:
"""返回是否只接管现有浏览器方式"""
...
@property
def is_auto_port(self) -> Union[bool, Tuple[int, int]]: ...
def is_auto_port(self) -> Union[bool, Tuple[int, int]]:
"""返回是否使用自动端口和用户文件如指定范围则返回范围tuple"""
...
@property
def retry_times(self) -> int: ...
def retry_times(self) -> int:
"""返回连接失败时的重试次数"""
...
@property
def retry_interval(self) -> float: ...
def retry_interval(self) -> float:
"""返回连接失败时的重试间隔(秒)"""
...
@property
def is_headless(self) -> bool: ...
def is_headless(self) -> bool:
"""返回是否无头模式"""
...
def set_retry(self, times: int = None, interval: float = None) -> ChromiumOptions: ...
def set_retry(self, times: int = None, interval: float = None) -> ChromiumOptions:
"""设置连接失败时的重试操作
:param times: 重试次数
:param interval: 重试间隔
:return: 当前对象
"""
...
def set_argument(self, arg: str, value: Union[str, None, bool] = None) -> ChromiumOptions: ...
def set_argument(self, arg: str, value: Union[str, None, bool] = None) -> ChromiumOptions:
"""设置浏览器配置的argument属性
:param arg: 属性名
:param value: 属性值有值的属性传入值没有的传入None如传入False删除该项
:return: 当前对象
"""
...
def remove_argument(self, value: str) -> ChromiumOptions: ...
def remove_argument(self, value: str) -> ChromiumOptions:
"""移除一个argument项
:param value: 设置项名有值的设置项传入设置名称即可
:return: 当前对象
"""
...
def add_extension(self, path: Union[str, Path]) -> ChromiumOptions: ...
def add_extension(self, path: Union[str, Path]) -> ChromiumOptions:
"""添加插件
:param path: 插件路径可指向文件夹
:return: 当前对象
"""
...
def remove_extensions(self) -> ChromiumOptions: ...
def remove_extensions(self) -> ChromiumOptions:
"""移除所有插件
:return: 当前对象
"""
...
def set_pref(self, arg: str, value: Any) -> ChromiumOptions: ...
def set_pref(self, arg: str, value: Any) -> ChromiumOptions:
"""设置Preferences文件中的用户设置项
:param arg: 设置项名称
:param value: 设置项值
:return: 当前对象
"""
...
def remove_pref(self, arg: str) -> ChromiumOptions: ...
def remove_pref(self, arg: str) -> ChromiumOptions:
"""删除用户首选项设置,不能删除已设置到文件中的项
:param arg: 设置项名称
:return: 当前对象
"""
...
def remove_pref_from_file(self, arg: str) -> ChromiumOptions: ...
def remove_pref_from_file(self, arg: str) -> ChromiumOptions:
"""删除用户配置文件中已设置的项
:param arg: 设置项名称
:return: 当前对象
"""
...
def set_flag(self, flag: str, value: Union[int, str, bool] = None) -> ChromiumOptions: ...
def set_flag(self, flag: str, value: Union[int, str, bool] = None) -> ChromiumOptions:
"""设置实验项
:param flag: 设置项名称
:param value: 设置项的值为False则删除该项
:return: 当前对象
"""
...
def clear_flags_in_file(self) -> ChromiumOptions: ...
def clear_flags_in_file(self) -> ChromiumOptions:
"""删除浏览器配置文件中已设置的实验项"""
...
def clear_flags(self) -> ChromiumOptions: ...
def clear_flags(self) -> ChromiumOptions:
"""清空本对象已设置的flag参数"""
...
def clear_arguments(self) -> ChromiumOptions: ...
def clear_arguments(self) -> ChromiumOptions:
"""清空本对象已设置的argument参数"""
...
def clear_prefs(self) -> ChromiumOptions: ...
def clear_prefs(self) -> ChromiumOptions:
"""清空本对象已设置的pref参数"""
...
def set_timeouts(self,
base: float = None,
page_load: float = None,
script: float = None) -> ChromiumOptions: ...
script: float = None) -> ChromiumOptions:
"""设置超时时间,单位为秒
:param base: 默认超时时间
:param page_load: 页面加载超时时间
:param script: 脚本运行超时时间
:return: 当前对象
"""
...
def set_user(self, user: str = 'Default') -> ChromiumOptions: ...
def set_user(self, user: str = 'Default') -> ChromiumOptions:
"""设置使用哪个用户配置文件夹
:param user: 用户文件夹名称
:return: 当前对象
"""
...
def headless(self, on_off: bool = True) -> ChromiumOptions: ...
def headless(self, on_off: bool = True) -> ChromiumOptions:
"""设置是否隐藏浏览器界面
:param on_off: 开或关
:return: 当前对象
"""
...
def no_imgs(self, on_off: bool = True) -> ChromiumOptions: ...
def no_imgs(self, on_off: bool = True) -> ChromiumOptions:
"""设置是否加载图片
:param on_off: 开或关
:return: 当前对象
"""
...
def no_js(self, on_off: bool = True) -> ChromiumOptions: ...
def no_js(self, on_off: bool = True) -> ChromiumOptions:
"""设置是否禁用js
:param on_off: 开或关
:return: 当前对象
"""
...
def mute(self, on_off: bool = True) -> ChromiumOptions: ...
def mute(self, on_off: bool = True) -> ChromiumOptions:
"""设置是否静音
:param on_off: 开或关
:return: 当前对象
"""
...
def incognito(self, on_off: bool = True) -> ChromiumOptions: ...
def incognito(self, on_off: bool = True) -> ChromiumOptions:
"""设置是否使用无痕模式启动
:param on_off: 开或关
:return: 当前对象
"""
...
def new_env(self, on_off: bool = True) -> ChromiumOptions: ...
def new_env(self, on_off: bool = True) -> ChromiumOptions:
"""设置是否使用全新浏览器环境
:param on_off: 开或关
:return: 当前对象
"""
...
def set_user_agent(self, user_agent: str) -> ChromiumOptions: ...
def ignore_certificate_errors(self, on_off=True) -> ChromiumOptions:
"""设置是否忽略证书错误
:param on_off: 开或关
:return: 当前对象
"""
...
def set_proxy(self, proxy: str) -> ChromiumOptions: ...
def set_user_agent(self, user_agent: str) -> ChromiumOptions:
"""设置user agent
:param user_agent: user agent文本
:return: 当前对象
"""
...
def ignore_certificate_errors(self, on_off=True) -> ChromiumOptions: ...
def set_proxy(self, proxy: str) -> ChromiumOptions:
"""设置代理
:param proxy: 代理url和端口
:return: 当前对象
"""
...
def set_load_mode(self, value: Literal['normal', 'eager', 'none']) -> ChromiumOptions: ...
def set_load_mode(self, value: Literal['normal', 'eager', 'none']) -> ChromiumOptions:
"""设置load_mode可接收 'normal', 'eager', 'none'
normal默认情况下使用, 等待所有资源下载完成
eagerDOM访问已准备就绪, 但其他资源 (如图像) 可能仍在加载中
none完全不阻塞
:param value: 可接收 'normal', 'eager', 'none'
:return: 当前对象
"""
...
def set_browser_path(self, path: Union[str, Path]) -> ChromiumOptions: ...
def set_local_port(self, port: Union[str, int]) -> ChromiumOptions:
"""设置本地启动端口
:param port: 端口号
:return: 当前对象
"""
...
def set_local_port(self, port: Union[str, int]) -> ChromiumOptions: ...
def set_address(self, address: str) -> ChromiumOptions:
"""设置浏览器地址,格式'ip:port'
:param address: 浏览器地址
:return: 当前对象
"""
...
def set_address(self, address: str) -> ChromiumOptions: ...
def set_browser_path(self, path: Union[str, Path]) -> ChromiumOptions:
"""设置浏览器可执行文件路径
:param path: 浏览器路径
:return: 当前对象
"""
...
def set_download_path(self, path: Union[str, Path]) -> ChromiumOptions: ...
def set_download_path(self, path: Union[str, Path]) -> ChromiumOptions:
"""设置下载文件保存路径
:param path: 下载路径
:return: 当前对象
"""
...
def set_tmp_path(self, path: Union[str, Path]) -> ChromiumOptions: ...
def set_tmp_path(self, path: Union[str, Path]) -> ChromiumOptions:
"""设置临时文件文件保存路径
:param path: 下载路径
:return: 当前对象
"""
...
def set_user_data_path(self, path: Union[str, Path]) -> ChromiumOptions: ...
def set_user_data_path(self, path: Union[str, Path]) -> ChromiumOptions:
"""设置用户文件夹路径
:param path: 用户文件夹路径
:return: 当前对象
"""
...
def set_cache_path(self, path: Union[str, Path]) -> ChromiumOptions: ...
def set_cache_path(self, path: Union[str, Path]) -> ChromiumOptions:
"""设置缓存路径
:param path: 缓存路径
:return: 当前对象
"""
...
def set_paths(self, browser_path: Union[str, Path] = None, local_port: Union[int, str] = None,
address: str = None, download_path: Union[str, Path] = None, user_data_path: Union[str, Path] = None,
cache_path: Union[str, Path] = None) -> ChromiumOptions: ...
def use_system_user_path(self, on_off: bool = True) -> ChromiumOptions: ...
def use_system_user_path(self, on_off: bool = True) -> ChromiumOptions:
"""设置是否使用系统安装的浏览器默认用户文件夹
:param on_off: 开或关
:return: 当前对象
"""
...
def auto_port(self,
on_off: bool = True,
scope: Tuple[int, int] = None) -> ChromiumOptions: ...
scope: Tuple[int, int] = None) -> ChromiumOptions:
"""自动获取可用端口
:param on_off: 是否开启自动获取端口号
:param scope: 指定端口范围不含最后的数字为None则使用[9600-59600)
:return: 当前对象
"""
...
def existing_only(self, on_off: bool = True) -> ChromiumOptions: ...
def existing_only(self, on_off: bool = True) -> ChromiumOptions:
"""设置只接管已有浏览器,不自动启动新的
:param on_off: 是否开启自动获取端口号
:return: 当前对象
"""
...
def save(self, path: Union[str, Path] = None) -> str: ...
def save(self, path: Union[str, Path] = None) -> str:
"""保存设置到文件
:param path: ini文件的路径 None 保存到当前读取的配置文件传入 'default' 保存到默认ini文件
:return: 保存文件的绝对路径
"""
...
def save_to_default(self) -> str: ...
def save_to_default(self) -> str:
"""保存当前配置到默认ini文件"""
...

View File

@ -14,9 +14,6 @@ class OptionsManager(object):
"""管理配置文件内容的类"""
def __init__(self, path=None):
"""初始化,读取配置文件,如没有设置临时文件夹,则设置并新建
:param path: ini文件的路径为None则找项目文件夹下的找不到则读取模块文件夹下的
"""
if path is False:
self.ini_path = None
else:
@ -79,18 +76,9 @@ class OptionsManager(object):
self.set_item('others', 'retry_interval', '2')
def __getattr__(self, item):
"""以dict形似返回获取大项信息
:param item: 项名
:return: None
"""
return self.get_option(item)
def get_value(self, section, item):
"""获取配置的值
:param section: 段名
:param item: 项名
:return: 项值
"""
try:
return eval(self._conf.get(section, item))
except (SyntaxError, NameError):
@ -99,10 +87,6 @@ class OptionsManager(object):
return None
def get_option(self, section):
"""把section内容以字典方式返回
:param section: 段名
:return: 段内容生成的字典
"""
items = self._conf.items(section)
option = dict()
@ -115,30 +99,15 @@ class OptionsManager(object):
return option
def set_item(self, section, item, value):
"""设置配置值
:param section: 段名
:param item: 项名
:param value: 项值
:return: None
"""
self._conf.set(section, item, str(value))
self.__setattr__(f'_{section}', None)
return self
def remove_item(self, section, item):
"""删除配置值
:param section: 段名
:param item: 项名
:return: None
"""
self._conf.remove_option(section, item)
return self
def save(self, path=None):
"""保存配置文件
:param path: ini文件的路径传入 'default' 保存到默认ini文件
:return: 保存路径
"""
default_path = (Path(__file__).parent / 'configs.ini').absolute()
if path == 'default':
path = default_path
@ -163,11 +132,9 @@ class OptionsManager(object):
return path
def save_to_default(self):
"""保存当前配置到默认ini文件"""
return self.save('default')
def show(self):
"""打印所有设置信息"""
for i in self._conf.sections():
print(f'[{i}]')
pprint(self.get_option(i))

View File

@ -15,20 +15,62 @@ class OptionsManager(object):
file_exists: bool = ...
_conf: RawConfigParser = ...
def __init__(self, path: Union[Path, str] = None): ...
def __init__(self, path: Union[Path, str] = None):
"""初始化,读取配置文件,如没有设置临时文件夹,则设置并新建
:param path: ini文件的路径为None则找项目文件夹下的找不到则读取模块文件夹下的
"""
...
def __getattr__(self, item) -> dict: ...
def __getattr__(self, item) -> dict:
"""以dict形似返回获取大项信息
:param item: 项名
:return: None
"""
...
def get_value(self, section: str, item: str) -> Any: ...
def get_value(self, section: str, item: str) -> Any:
"""获取配置的值
:param section: 段名
:param item: 项名
:return: 项值
"""
...
def get_option(self, section: str) -> dict: ...
def get_option(self, section: str) -> dict:
"""把section内容以字典方式返回
:param section: 段名
:return: 段内容生成的字典
"""
...
def set_item(self, section: str, item: str, value: Any) -> None: ...
def set_item(self, section: str, item: str, value: Any) -> None:
"""设置配置值
:param section: 段名
:param item: 项名
:param value: 项值
:return: None
"""
...
def remove_item(self, section: str, item: str) -> None: ...
def remove_item(self, section: str, item: str) -> None:
"""删除配置值
:param section: 段名
:param item: 项名
:return: None
"""
...
def save(self, path: str = None) -> str: ...
def save(self, path: str = None) -> str:
"""保存配置文件
:param path: ini文件的路径传入 'default' 保存到默认ini文件
:return: 保存路径
"""
...
def save_to_default(self) -> str: ...
def save_to_default(self) -> str:
"""保存当前配置到默认ini文件"""
...
def show(self) -> None: ...
def show(self) -> None:
"""打印所有设置信息"""
...

View File

@ -17,13 +17,8 @@ from .._functions.web import format_headers
class SessionOptions(object):
"""requests的Session对象配置类"""
def __init__(self, read_file=True, ini_path=None):
"""
:param read_file: 是否从文件读取配置
:param ini_path: ini文件路径
"""
self.ini_path = None
self._download_path = '.'
self._timeout = 10
@ -93,62 +88,39 @@ class SessionOptions(object):
# ===========须独立处理的项开始============
@property
def download_path(self):
"""返回默认下载路径属性信息"""
return self._download_path
def set_download_path(self, path):
"""设置默认下载路径
:param path: 下载路径
:return: 返回当前对象
"""
self._download_path = '.' if path is None else str(path)
return self
@property
def timeout(self):
"""返回timeout属性信息"""
return self._timeout
def set_timeout(self, second):
"""设置超时信息
:param second: 秒数
:return: 返回当前对象
"""
self._timeout = second
return self
@property
def proxies(self):
"""返回proxies设置信息"""
if self._proxies is None:
self._proxies = {}
return self._proxies
def set_proxies(self, http=None, https=None):
"""设置proxies参数
:param http: http代理地址
:param https: https代理地址
:return: 返回当前对象
"""
self._sets('proxies', {'http': http, 'https': https})
return self
@property
def retry_times(self):
"""返回连接失败时的重试次数"""
return self._retry_times
@property
def retry_interval(self):
"""返回连接失败时的重试间隔(秒)"""
return self._retry_interval
def set_retry(self, times=None, interval=None):
"""设置连接失败时的重试操作
:param times: 重试次数
:param interval: 重试间隔
:return: 当前对象
"""
if times is not None:
self._retry_times = times
if interval is not None:
@ -159,16 +131,11 @@ class SessionOptions(object):
@property
def headers(self):
"""返回headers设置信息"""
if self._headers is None:
self._headers = {}
return self._headers
def set_headers(self, headers):
"""设置headers参数
:param headers: 参数值传入None可在ini文件标记删除
:return: 返回当前对象
"""
if headers is None:
self._headers = None
self._del_set.add('headers')
@ -178,11 +145,6 @@ class SessionOptions(object):
return self
def set_a_header(self, name, value):
"""设置headers中一个项
:param name: 设置名称
:param value: 设置值
:return: 返回当前对象
"""
if self._headers is None:
self._headers = {}
@ -190,10 +152,6 @@ class SessionOptions(object):
return self
def remove_a_header(self, name):
"""从headers中删除一个设置
:param name: 要删除的设置
:return: 返回当前对象
"""
if self._headers is None:
return self
@ -202,156 +160,99 @@ class SessionOptions(object):
return self
def clear_headers(self):
"""清空已设置的header参数"""
self._headers = None
self._del_set.add('headers')
@property
def cookies(self):
"""以list形式返回cookies"""
if self._cookies is None:
self._cookies = []
return self._cookies
def set_cookies(self, cookies):
"""设置一个或多个cookies信息
:param cookies: cookies可为Cookie, CookieJar, list, tuple, str, dict传入None可在ini文件标记删除
:return: 返回当前对象
"""
cookies = cookies if cookies is None else list(cookies_to_tuple(cookies))
self._sets('cookies', cookies)
return self
@property
def auth(self):
"""返回认证设置信息"""
return self._auth
def set_auth(self, auth):
"""设置认证元组或对象
:param auth: 认证元组或对象
:return: 返回当前对象
"""
self._sets('auth', auth)
return self
@property
def hooks(self):
"""返回回调方法"""
if self._hooks is None:
self._hooks = {}
return self._hooks
def set_hooks(self, hooks):
"""设置回调方法
:param hooks: 回调方法
:return: 返回当前对象
"""
self._hooks = hooks
return self
@property
def params(self):
"""返回连接参数设置信息"""
if self._params is None:
self._params = {}
return self._params
def set_params(self, params):
"""设置查询参数字典
:param params: 查询参数字典
:return: 返回当前对象
"""
self._sets('params', params)
return self
@property
def verify(self):
"""返回是否验证SSL证书设置"""
return self._verify
def set_verify(self, on_off):
"""设置是否验证SSL证书
:param on_off: 是否验证 SSL 证书
:return: 返回当前对象
"""
self._sets('verify', on_off)
return self
@property
def cert(self):
"""返回SSL证书设置信息"""
return self._cert
def set_cert(self, cert):
"""SSL客户端证书文件的路径(.pem格式),或(cert, key)元组
:param cert: 证书路径或元组
:return: 返回当前对象
"""
self._sets('cert', cert)
return self
@property
def adapters(self):
"""返回适配器设置信息"""
if self._adapters is None:
self._adapters = []
return self._adapters
def add_adapter(self, url, adapter):
"""添加适配器
:param url: 适配器对应url
:param adapter: 适配器对象
:return: 返回当前对象
"""
self._adapters.append((url, adapter))
return self
@property
def stream(self):
"""返回是否使用流式响应内容设置信息"""
return self._stream
def set_stream(self, on_off):
"""设置是否使用流式响应内容
:param on_off: 是否使用流式响应内容
:return: 返回当前对象
"""
self._sets('stream', on_off)
return self
@property
def trust_env(self):
"""返回是否信任环境设置信息"""
return self._trust_env
def set_trust_env(self, on_off):
"""设置是否信任环境
:param on_off: 是否信任环境
:return: 返回当前对象
"""
self._sets('trust_env', on_off)
return self
@property
def max_redirects(self):
"""返回最大重定向次数"""
return self._max_redirects
def set_max_redirects(self, times):
"""设置最大重定向次数
:param times: 最大重定向次数
:return: 返回当前对象
"""
self._sets('max_redirects', times)
return self
def _sets(self, arg, val):
"""给属性赋值或标记删除
:param arg: 属性名称
:param val: 参数值
:return: None
"""
if val is None:
self.__setattr__(f'_{arg}', None)
self._del_set.add(arg)
@ -361,10 +262,6 @@ class SessionOptions(object):
self._del_set.remove(arg)
def save(self, path=None):
"""保存设置到文件
:param path: ini文件的路径传入 'default' 保存到默认ini文件
:return: 保存文件的绝对路径
"""
if path == 'default':
path = (Path(__file__).parent / 'configs.ini').absolute()
@ -412,15 +309,12 @@ class SessionOptions(object):
return path
def save_to_default(self):
"""保存当前配置到默认ini文件"""
return self.save('default')
def as_dict(self):
"""以字典形式返回本对象"""
return session_options_to_dict(self)
def make_session(self):
"""根据内在的配置生成Session对象headers从对象中分离"""
s = Session()
h = CaseInsensitiveDict(self.headers) if self.headers else CaseInsensitiveDict()
@ -438,11 +332,6 @@ class SessionOptions(object):
return s, h
def from_session(self, session, headers=None):
"""从Session对象中读取配置
:param session: Session对象
:param headers: headers
:return: 当前对象
"""
self._headers = CaseInsensitiveDict(copy(session.headers).update(headers)) if headers else session.headers
self._cookies = session.cookies
self._auth = session.auth
@ -463,10 +352,6 @@ class SessionOptions(object):
def session_options_to_dict(options):
"""把session配置对象转换为字典
:param options: session配置对象或字典
:return: 配置字典
"""
if options in (False, None):
return SessionOptions(read_file=False).as_dict()

View File

@ -12,125 +12,287 @@ from typing import Any, Union, Tuple, Optional
from requests import Session
from requests.adapters import HTTPAdapter
from requests.auth import HTTPBasicAuth
from requests.cookies import RequestsCookieJar
from requests.structures import CaseInsensitiveDict
class SessionOptions(object):
def __init__(self, read_file: [bool, None] = True, ini_path: Union[str, Path] = None):
self.ini_path: str = ...
self._download_path: str = ...
self._headers: dict = ...
self._cookies: list = ...
self._auth: tuple = ...
self._proxies: dict = ...
self._hooks: dict = ...
self._params: dict = ...
self._verify: bool = ...
self._cert: Union[str, tuple] = ...
self._adapters: list = ...
self._stream: bool = ...
self._trust_env: bool = ...
self._max_redirects: int = ...
self._timeout: float = ...
self._del_set: set = ...
self._retry_times: int = ...
self._retry_interval: float = ...
"""requests的Session对象配置类"""
ini_path: Optional[str] = ...
_download_path: str = ...
_headers: Union[dict, CaseInsensitiveDict, None] = ...
_cookies: Union[list, RequestsCookieJar, None] = ...
_auth: Optional[tuple] = ...
_proxies: Optional[dict] = ...
_hooks: Optional[dict] = ...
_params: Union[dict, None] = ...
_verify: Optional[bool] = ...
_cert: Union[str, tuple, None] = ...
_adapters: Optional[list] = ...
_stream: Optional[bool] = ...
_trust_env: Optional[bool] = ...
_max_redirects: Optional[int] = ...
_timeout: float = ...
_del_set: set = ...
_retry_times: int = ...
_retry_interval: float = ...
def __init__(self,
read_file: [bool, None] = True,
ini_path: Union[str, Path] = None):
"""
:param read_file: 是否从文件读取配置
:param ini_path: ini文件路径
"""
...
@property
def download_path(self) -> str: ...
def download_path(self) -> str:
"""返回默认下载路径属性信息"""
...
def set_download_path(self, path: Union[str, Path]) -> SessionOptions: ...
def set_download_path(self, path: Union[str, Path]) -> SessionOptions:
"""设置默认下载路径
:param path: 下载路径
:return: 返回当前对象
"""
...
@property
def timeout(self) -> float: ...
def timeout(self) -> float:
"""返回timeout属性信息"""
...
def set_timeout(self, second: float) -> SessionOptions: ...
def set_timeout(self, second: float) -> SessionOptions:
"""设置超时信息
:param second: 秒数
:return: 返回当前对象
"""
...
@property
def headers(self) -> dict: ...
def proxies(self) -> dict:
"""返回proxies设置信息"""
...
def set_headers(self, headers: Union[dict, str, None]) -> SessionOptions: ...
def set_a_header(self, name: str, value: str) -> SessionOptions: ...
def remove_a_header(self, name: str) -> SessionOptions: ...
def clear_headers(self) -> SessionOptions: ...
def set_proxies(self, http: Union[str, None], https: Union[str, None] = None) -> SessionOptions:
"""设置proxies参数
:param http: http代理地址
:param https: https代理地址
:return: 返回当前对象
"""
...
@property
def cookies(self) -> list: ...
def set_cookies(self, cookies: Union[Cookie, CookieJar, list, tuple, str, dict, None]) -> SessionOptions: ...
def retry_times(self) -> int:
"""返回连接失败时的重试次数"""
...
@property
def auth(self) -> Union[Tuple[str, str], HTTPBasicAuth]: ...
def retry_interval(self) -> float:
"""返回连接失败时的重试间隔(秒)"""
...
def set_auth(self, auth: Union[Tuple[str, str], HTTPBasicAuth, None]) -> SessionOptions: ...
def set_retry(self, times: int = None, interval: float = None) -> SessionOptions:
"""设置连接失败时的重试操作
:param times: 重试次数
:param interval: 重试间隔
:return: 当前对象
"""
...
@property
def proxies(self) -> dict: ...
def headers(self) -> dict:
"""返回headers设置信息"""
...
def set_proxies(self, http: Union[str, None], https: Union[str, None] = None) -> SessionOptions: ...
def set_headers(self, headers: Union[dict, str, None]) -> SessionOptions:
"""设置headers参数
:param headers: 参数值传入None可在ini文件标记删除
:return: 返回当前对象
"""
...
def set_a_header(self, name: str, value: str) -> SessionOptions:
"""设置headers中一个项
:param name: 设置名称
:param value: 设置值
:return: 返回当前对象
"""
...
def remove_a_header(self, name: str) -> SessionOptions:
"""从headers中删除一个设置
:param name: 要删除的设置
:return: 返回当前对象
"""
...
def clear_headers(self) -> SessionOptions:
"""清空已设置的header参数"""
...
@property
def retry_times(self) -> int: ...
def cookies(self) -> list:
"""以list形式返回cookies"""
...
def set_cookies(self, cookies: Union[Cookie, CookieJar, list, tuple, str, dict, None]) -> SessionOptions:
"""设置一个或多个cookies信息
:param cookies: cookies可为Cookie, CookieJar, list, tuple, str, dict传入None可在ini文件标记删除
:return: 返回当前对象
"""
...
@property
def retry_interval(self) -> float: ...
def auth(self) -> Union[Tuple[str, str], HTTPBasicAuth]:
"""返回认证设置信息"""
...
def set_retry(self, times: int = None, interval: float = None) -> SessionOptions: ...
def set_auth(self, auth: Union[Tuple[str, str], HTTPBasicAuth, None]) -> SessionOptions:
"""设置认证元组或对象
:param auth: 认证元组或对象
:return: 返回当前对象
"""
...
@property
def hooks(self) -> dict: ...
def hooks(self) -> dict:
"""返回回调方法"""
...
def set_hooks(self, hooks: Union[dict, None]) -> SessionOptions: ...
def set_hooks(self, hooks: Union[dict, None]) -> SessionOptions:
"""设置回调方法
:param hooks: 回调方法
:return: 返回当前对象
"""
...
@property
def params(self) -> dict: ...
def params(self) -> dict:
"""返回连接参数设置信息"""
...
def set_params(self, params: Union[dict, None]) -> SessionOptions: ...
def set_params(self, params: Union[dict, None]) -> SessionOptions:
"""设置查询参数字典
:param params: 查询参数字典
:return: 返回当前对象
"""
...
@property
def verify(self) -> bool: ...
def verify(self) -> bool:
"""返回是否验证SSL证书设置"""
...
def set_verify(self, on_off: Union[bool, None]) -> SessionOptions: ...
def set_verify(self, on_off: Union[bool, None]) -> SessionOptions:
"""设置是否验证SSL证书
:param on_off: 是否验证 SSL 证书
:return: 返回当前对象
"""
...
@property
def cert(self) -> Union[str, tuple]: ...
def cert(self) -> Union[str, tuple]:
"""返回SSL证书设置信息"""
...
def set_cert(self, cert: Union[str, Tuple[str, str], None]) -> SessionOptions: ...
def set_cert(self, cert: Union[str, Tuple[str, str], None]) -> SessionOptions:
"""SSL客户端证书文件的路径(.pem格式),或(cert, key)元组
:param cert: 证书路径或元组
:return: 返回当前对象
"""
...
@property
def adapters(self): list: ...
def adapters(self) -> list:
"""返回适配器设置信息"""
...
def add_adapter(self, url: str, adapter: HTTPAdapter) -> SessionOptions: ...
def add_adapter(self, url: str, adapter: HTTPAdapter) -> SessionOptions:
"""添加适配器
:param url: 适配器对应url
:param adapter: 适配器对象
:return: 返回当前对象
"""
...
@property
def stream(self) -> bool: ...
def stream(self) -> bool:
"""返回是否使用流式响应内容设置信息"""
...
def set_stream(self, on_off: Union[bool, None]) -> SessionOptions: ...
def set_stream(self, on_off: Union[bool, None]) -> SessionOptions:
"""设置是否使用流式响应内容
:param on_off: 是否使用流式响应内容
:return: 返回当前对象
"""
...
@property
def trust_env(self) -> bool: ...
def trust_env(self) -> bool:
"""返回是否信任环境设置信息"""
...
def set_trust_env(self, on_off: Union[bool, None]) -> SessionOptions: ...
def set_trust_env(self, on_off: Union[bool, None]) -> SessionOptions:
"""设置是否信任环境
:param on_off: 是否信任环境
:return: 返回当前对象
"""
...
@property
def max_redirects(self) -> int: ...
def max_redirects(self) -> int:
"""返回最大重定向次数"""
...
def set_max_redirects(self, times: Union[int, None]) -> SessionOptions: ...
def set_max_redirects(self, times: Union[int, None]) -> SessionOptions:
"""设置最大重定向次数
:param times: 最大重定向次数
:return: 返回当前对象
"""
...
def _sets(self, arg: str, val: Any) -> None: ...
def _sets(self, arg: str, val: Any) -> None:
"""给属性赋值或标记删除
:param arg: 属性名称
:param val: 参数值
:return: None
"""
...
def save(self, path: str = None) -> str: ...
def save(self, path: str = None) -> str:
"""保存设置到文件
:param path: ini文件的路径传入 'default' 保存到默认ini文件
:return: 保存文件的绝对路径
"""
...
def save_to_default(self) -> str: ...
def save_to_default(self) -> str:
"""保存当前配置到默认ini文件"""
...
def as_dict(self) -> dict: ...
def as_dict(self) -> dict:
"""以字典形式返回本对象"""
...
def make_session(self) -> Tuple[Session, Optional[CaseInsensitiveDict]]: ...
def make_session(self) -> Tuple[Session, Optional[CaseInsensitiveDict]]:
"""根据内在的配置生成Session对象headers从对象中分离"""
...
def from_session(self, session: Session, headers: CaseInsensitiveDict = None) -> SessionOptions: ...
def from_session(self, session: Session, headers: CaseInsensitiveDict = None) -> SessionOptions:
"""从Session对象中读取配置
:param session: Session对象
:param headers: headers
:return: 当前对象
"""
...
def session_options_to_dict(options: Union[dict, SessionOptions, None]) -> Union[dict, None]: ...
def session_options_to_dict(options: Union[dict, SessionOptions, None]) -> Union[dict, None]:
"""把session配置对象转换为字典
:param options: session配置对象或字典
:return: 配置字典
"""
...

View File

@ -566,6 +566,8 @@ class ChromiumElement(DrissionElement):
else:
self.owner.actions.type(vals)
return self
def clear(self, by_js=False):
if by_js:
self._run_js("this.value='';")
@ -574,6 +576,7 @@ class ChromiumElement(DrissionElement):
self._input_focus()
self.input(('\ue009', 'a', '\ue017'), clear=False)
return self
def _input_focus(self):
try:
@ -586,15 +589,18 @@ class ChromiumElement(DrissionElement):
self.owner._run_cdp('DOM.focus', backendNodeId=self._backend_id)
except Exception:
self._run_js('this.focus();')
return self
def hover(self, offset_x=None, offset_y=None):
self.owner.actions.move_to(self, offset_x=offset_x, offset_y=offset_y, duration=.1)
return self
def drag(self, offset_x=0, offset_y=0, duration=.5):
curr_x, curr_y = self.rect.midpoint
offset_x += curr_x
offset_y += curr_y
self.drag_to((offset_x, offset_y), duration)
return self
def drag_to(self, ele_or_loc, duration=.5):
if isinstance(ele_or_loc, ChromiumElement):
@ -602,6 +608,7 @@ class ChromiumElement(DrissionElement):
elif not isinstance(ele_or_loc, (list, tuple)):
raise TypeError('需要ChromiumElement对象或坐标。')
self.owner.actions.hold(self).move_to(ele_or_loc, duration=duration).release()
return self
def _get_obj_id(self, node_id=None, backend_id=None):
if node_id:
@ -675,6 +682,7 @@ class ChromiumElement(DrissionElement):
files = files.split('\n')
files = [str(Path(i).absolute()) for i in files]
self.owner._run_cdp('DOM.setFileInputFiles', files=files, backendNodeId=self._backend_id)
return self
class ShadowRoot(BaseElement):

View File

@ -526,7 +526,7 @@ class ChromiumElement(DrissionElement):
"""
...
def input(self, vals: Any, clear: bool = False, by_js: bool = False) -> None:
def input(self, vals: Any, clear: bool = False, by_js: bool = False) -> ChromiumElement:
"""输入文本或组合键也可用于输入文件路径到input元素路径间用\n间隔)
:param vals: 文本值或按键组合
:param clear: 输入前是否清空文本框
@ -535,7 +535,7 @@ class ChromiumElement(DrissionElement):
"""
...
def clear(self, by_js: bool = False) -> None:
def clear(self, by_js: bool = False) -> ChromiumElement:
"""清空元素文本
:param by_js: 是否用js方式清空为False则用全选+del模拟输入删除
:return: None
@ -546,11 +546,11 @@ class ChromiumElement(DrissionElement):
"""输入前使元素获取焦点"""
...
def focus(self) -> None:
def focus(self) -> ChromiumElement:
"""使元素获取焦点"""
...
def hover(self, offset_x: int = None, offset_y: int = None) -> None:
def hover(self, offset_x: int = None, offset_y: int = None) -> ChromiumElement:
"""鼠标悬停可接受偏移量偏移量相对于元素左上角坐标。不传入offset_x和offset_y值时悬停在元素中点
:param offset_x: 相对元素左上角坐标的x轴偏移量
:param offset_y: 相对元素左上角坐标的y轴偏移量
@ -558,7 +558,7 @@ class ChromiumElement(DrissionElement):
"""
...
def drag(self, offset_x: int = 0, offset_y: int = 0, duration: float = 0.5) -> None:
def drag(self, offset_x: int = 0, offset_y: int = 0, duration: float = 0.5) -> ChromiumElement:
"""拖拽当前元素到相对位置
:param offset_x: x变化值
:param offset_y: y变化值
@ -567,7 +567,9 @@ class ChromiumElement(DrissionElement):
"""
...
def drag_to(self, ele_or_loc: Union[Tuple[int, int], str, ChromiumElement], duration: float = 0.5) -> None:
def drag_to(self,
ele_or_loc: Union[Tuple[int, int], str, ChromiumElement],
duration: float = 0.5) -> ChromiumElement:
"""拖拽当前元素,目标为另一个元素或坐标元组(x, y)
:param ele_or_loc: 另一个元素或坐标元组坐标为元素中点的坐标
:param duration: 拖动用时传入0即瞬间到达

View File

@ -11,11 +11,6 @@ from ..errors import ElementNotFoundError
class NoneElement(object):
def __init__(self, page=None, method=None, args=None):
"""
:param page: 元素所在页面
:param method: 查找元素的方法
:param args: 查找元素的参数
"""
if method and Settings.raise_when_ele_not_found: # 无传入method时不自动抛出由调用者处理
raise ElementNotFoundError(None, method=method, arguments=args)
@ -49,11 +44,10 @@ class NoneElement(object):
raise ElementNotFoundError(None, self.method, self.args)
def __eq__(self, other):
if other is None:
return True
return other is None
def __bool__(self):
return False
def __repr__(self):
return 'None'
return f'<NoneElement method={self.method}, {", ".join([f"{k}={v}" for k, v in self.args.items()])}>'

View File

@ -0,0 +1,32 @@
# -*- coding:utf-8 -*-
"""
@Author : g1879
@Contact : g1879@qq.com
@Copyright: (c) 2024 by g1879, Inc. All Rights Reserved.
@License : BSD 3-Clause.
"""
from typing import Any
from .._base.base import BasePage
class NoneElement(object):
def __init__(self, page: BasePage = None,
method: str = None,
args: dict = None):
"""
:param page: 元素所在页面
:param method: 查找元素的方法
:param args: 查找元素的参数
"""
...
def __call__(self, *args, **kwargs) -> NoneElement: ...
def __getattr__(self, item: str) -> str: ...
def __eq__(self, other: Any) -> bool: ...
def __bool__(self) -> bool: ...
def __repr__(self) -> str: ...

View File

@ -21,10 +21,6 @@ from ..errors import BrowserConnectError
def connect_browser(option):
"""连接或启动浏览器
:param option: ChromiumOptions对象
:return: 返回是否接管的浏览器
"""
address = option.address.replace('localhost', '127.0.0.1').lstrip('http://').lstrip('https://')
browser_path = option.browser_path
@ -67,10 +63,6 @@ def connect_browser(option):
def get_launch_args(opt):
"""从ChromiumOptions获取命令行启动参数
:param opt: ChromiumOptions
:return: 启动参数列表
"""
# ----------处理arguments-----------
result = set()
user_path = False
@ -107,10 +99,6 @@ def get_launch_args(opt):
def set_prefs(opt):
"""处理启动配置中的prefs项目前只能对已存在文件夹配置
:param opt: ChromiumOptions
:return: None
"""
if not opt.user_data_path or (not opt.preferences and not opt._prefs_to_del):
return
prefs = opt.preferences
@ -149,10 +137,6 @@ def set_prefs(opt):
def set_flags(opt):
"""处理启动配置中的flags项
:param opt: ChromiumOptions
:return: None
"""
if not opt.user_data_path or (not opt.clear_file_flags and not opt.flags):
return
@ -185,12 +169,6 @@ def set_flags(opt):
def test_connect(ip, port, timeout=30):
"""测试浏览器是否可用
:param ip: 浏览器ip
:param port: 浏览器端口
:param timeout: 超时时间
:return: None
"""
end_time = perf_counter() + timeout
s = Session()
s.trust_env = False
@ -276,7 +254,6 @@ def _remove_arg_from_dict(target_dict: dict, arg: str) -> None:
def get_chrome_path(ini_path):
"""从ini文件或系统变量中获取chrome可执行文件的路径"""
# -----------从ini文件中获取--------------
if ini_path and Path(ini_path).exists():
path = OptionsManager(ini_path).chromium_options.get('browser_path', None)

View File

@ -10,19 +10,51 @@ from typing import Union
from .._configs.chromium_options import ChromiumOptions
def connect_browser(option: ChromiumOptions) -> bool: ...
def connect_browser(option: ChromiumOptions) -> bool:
"""连接或启动浏览器
:param option: ChromiumOptions对象
:return: 返回是否接管的浏览器
"""
...
def get_launch_args(opt: ChromiumOptions) -> list: ...
def get_launch_args(opt: ChromiumOptions) -> list:
"""从ChromiumOptions获取命令行启动参数
:param opt: ChromiumOptions
:return: 启动参数列表
"""
...
def set_prefs(opt: ChromiumOptions) -> None: ...
def set_prefs(opt: ChromiumOptions) -> None:
"""处理启动配置中的prefs项目前只能对已存在文件夹配置
:param opt: ChromiumOptions
:return: None
"""
...
def set_flags(opt: ChromiumOptions) -> None: ...
def set_flags(opt: ChromiumOptions) -> None:
"""处理启动配置中的flags项
:param opt: ChromiumOptions
:return: None
"""
...
def test_connect(ip: str, port: Union[int, str], timeout: float = 30) -> bool: ...
def test_connect(ip: str, port: Union[int, str], timeout: float = 30) -> bool:
"""测试浏览器是否可用
:param ip: 浏览器ip
:param port: 浏览器端口
:param timeout: 超时时间
:return: None
"""
...
def get_chrome_path(ini_path: str) -> Union[str, None]: ...
def get_chrome_path(ini_path: str) -> Union[str, None]:
"""从ini文件或系统变量中获取chrome可执行文件的路径
:param ini_path: ini文件路径
:return: 文件路径
"""
...

View File

@ -12,10 +12,6 @@ from tldextract import extract
def cookie_to_dict(cookie):
"""把Cookie对象转为dict格式
:param cookie: Cookie对象字符串或字典
:return: cookie字典
"""
if isinstance(cookie, Cookie):
cookie_dict = cookie.__dict__.copy()
cookie_dict.pop('rfc2109', None)
@ -44,10 +40,6 @@ def cookie_to_dict(cookie):
def cookies_to_tuple(cookies):
"""把cookies转为tuple格式
:param cookies: cookies信息可为CookieJar, list, tuple, str, dict
:return: 返回tuple形式的cookies
"""
if isinstance(cookies, (list, tuple, CookieJar)):
cookies = tuple(cookie_to_dict(cookie) for cookie in cookies)
@ -74,11 +66,6 @@ def cookies_to_tuple(cookies):
def set_session_cookies(session, cookies):
"""设置Session对象的cookies
:param session: Session对象
:param cookies: cookies信息
:return: None
"""
for cookie in cookies_to_tuple(cookies):
if cookie['value'] is None:
cookie['value'] = ''
@ -94,11 +81,6 @@ def set_session_cookies(session, cookies):
def set_browser_cookies(browser, cookies):
"""设置cookies值
:param browser: 页面对象
:param cookies: cookies信息
:return: None
"""
c = []
for cookie in cookies_to_tuple(cookies):
if 'domain' not in cookie and 'url' not in cookie:
@ -108,11 +90,6 @@ def set_browser_cookies(browser, cookies):
def set_tab_cookies(page, cookies):
"""设置cookies值
:param page: 页面对象
:param cookies: cookies信息
:return: None
"""
for cookie in cookies_to_tuple(cookies):
cookie = format_cookie(cookie)
@ -154,11 +131,6 @@ def set_tab_cookies(page, cookies):
def is_cookie_in_driver(page, cookie):
"""查询cookie是否在浏览器内
:param page: BasePage对象
:param cookie: dict格式cookie
:return: bool
"""
if 'domain' in cookie:
for c in page.cookies(all_domains=True):
if cookie['name'] == c['name'] and cookie['value'] == c['value'] and cookie['domain'] == c.get('domain',
@ -172,10 +144,6 @@ def is_cookie_in_driver(page, cookie):
def format_cookie(cookie):
"""设置cookie为可用格式
:param cookie: dict格式cookie
:return: 格式化后的cookie字典
"""
if 'expiry' in cookie:
cookie['expires'] = int(cookie['expiry'])
cookie.pop('expiry')
@ -235,15 +203,12 @@ def format_cookie(cookie):
class CookiesList(list):
def as_dict(self):
"""以dict格式返回只包含name和value字段"""
return {c['name']: c['value'] for c in self}
def as_str(self):
"""以str格式返回只包含name和value字段"""
return '; '.join([f'{c["name"]}={c["value"]}' for c in self])
def as_json(self):
"""以json格式返回"""
from json import dumps
return dumps(self)

View File

@ -15,32 +15,80 @@ from .._base.browser import Chromium
from .._pages.chromium_base import ChromiumBase
def cookie_to_dict(cookie: Union[Cookie, str, dict]) -> dict: ...
def cookie_to_dict(cookie: Union[Cookie, str, dict]) -> dict:
"""把Cookie对象转为dict格式
:param cookie: Cookie对象字符串或字典
:return: cookie字典
"""
...
def cookies_to_tuple(cookies: Union[RequestsCookieJar, list, tuple, str, dict, Cookie]) -> tuple: ...
def cookies_to_tuple(cookies: Union[RequestsCookieJar, list, tuple, str, dict, Cookie]) -> tuple:
"""把cookies转为tuple格式
:param cookies: cookies信息可为CookieJar, list, tuple, str, dict
:return: 返回tuple形式的cookies
"""
...
def set_session_cookies(session: Session, cookies: Union[RequestsCookieJar, list, tuple, str, dict]) -> None: ...
def set_session_cookies(session: Session,
cookies: Union[RequestsCookieJar, list, tuple, str, dict]) -> None:
"""设置Session对象的cookies
:param session: Session对象
:param cookies: cookies信息
:return: None
"""
...
def set_browser_cookies(browser: Chromium, cookies: Union[RequestsCookieJar, list, tuple, str, dict]) -> None: ...
def set_browser_cookies(browser: Chromium,
cookies: Union[RequestsCookieJar, list, tuple, str, dict]) -> None:
"""设置cookies值
:param browser: 页面对象
:param cookies: cookies信息
:return: None
"""
...
def set_tab_cookies(page: ChromiumBase, cookies: Union[RequestsCookieJar, list, tuple, str, dict]) -> None: ...
def set_tab_cookies(page: ChromiumBase,
cookies: Union[RequestsCookieJar, list, tuple, str, dict]) -> None:
"""设置cookies值
:param page: 页面对象
:param cookies: cookies信息
:return: None
"""
...
def is_cookie_in_driver(page: ChromiumBase, cookie: dict) -> bool: ...
def is_cookie_in_driver(page: ChromiumBase, cookie: dict) -> bool:
"""查询cookie是否在浏览器内
:param page: BasePage对象
:param cookie: dict格式cookie
:return: bool
"""
...
def format_cookie(cookie: dict) -> dict: ...
def format_cookie(cookie: dict) -> dict:
"""设置cookie为可用格式
:param cookie: dict格式cookie
:return: 格式化后的cookie字典
"""
...
class CookiesList(list):
def as_dict(self) -> dict: ...
def as_dict(self) -> dict:
"""以dict格式返回只包含name和value字段"""
...
def as_str(self) -> str: ...
def as_str(self) -> str:
"""以str格式返回只包含name和value字段"""
...
def as_json(self) -> str: ...
def as_json(self) -> str:
"""以json格式返回"""
...
def __next__(self) -> dict: ...

View File

@ -12,9 +12,9 @@ from .._elements.none_element import NoneElement
class SessionElementsList(list):
def __init__(self, page=None, *args):
def __init__(self, owner=None, *args):
super().__init__(*args)
self._page = page
self._owner = owner
@property
def get(self):
@ -56,17 +56,6 @@ class ChromiumElementsList(SessionElementsList):
def search_one(self, index=1, displayed=None, checked=None, selected=None, enabled=None, clickable=None,
have_rect=None, have_text=None):
"""或关系筛选元素,获取一个结果
:param index: 元素序号从1开始
:param displayed: 是否显示boolNone为忽略该项
:param checked: 是否被选中boolNone为忽略该项
:param selected: 是否被选择boolNone为忽略该项
:param enabled: 是否可用boolNone为忽略该项
:param clickable: 是否可点击boolNone为忽略该项
:param have_rect: 是否拥有大小和位置boolNone为忽略该项
:param have_text: 是否含有文本boolNone为忽略该项
:return: 筛选结果
"""
return _search_one(self, index=index, displayed=displayed, checked=checked, selected=selected,
enabled=enabled, clickable=clickable, have_rect=have_rect, have_text=have_text)
@ -77,29 +66,13 @@ class SessionFilterOne(object):
self._index = 1
def __call__(self, index=1):
"""返回结果中第几个元素
:param index: 元素序号从1开始
:return: 对象自身
"""
self._index = index
return self
def attr(self, name, value, equal=True):
"""以是否拥有某个attribute值为条件筛选元素
:param name: 属性名称
:param value: 属性值
:param equal: True表示匹配name值为value值的元素False表示匹配name值不为value值的
:return: 筛选结果
"""
return self._get_attr(name, value, 'attr', equal=equal)
def text(self, text, fuzzy=True, contain=True):
"""以是否含有指定文本为条件筛选元素
:param text: 用于匹配的文本
:param fuzzy: 是否模糊匹配
:param contain: 是否包含该字符串False表示不包含
:return: 筛选结果
"""
num = 0
if contain:
for i in self._list:
@ -115,16 +88,10 @@ class SessionFilterOne(object):
num += 1
if self._index == num:
return i
return NoneElement(self._list._page, 'text()',
return NoneElement(self._list._owner, 'text()',
args={'text': text, 'fuzzy': fuzzy, 'contain': contain, 'index': self._index})
def _get_attr(self, name, value, method, equal=True):
"""返回通过某个方法可获得某个值的元素
:param name: 属性名称
:param value: 属性值
:param method: 方法名称
:return: 筛选结果
"""
num = 0
if equal:
for i in self._list:
@ -138,7 +105,7 @@ class SessionFilterOne(object):
num += 1
if self._index == num:
return i
return NoneElement(self._list._page, f'{method}()',
return NoneElement(self._list._owner, f'{method}()',
args={'name': name, 'value': value, 'equal': equal, 'index': self._index})
@ -158,28 +125,15 @@ class SessionFilter(SessionFilterOne):
@property
def get(self):
"""返回用于获取元素属性的对象"""
return self._list.get
def text(self, text, fuzzy=True, contain=True):
"""以是否含有指定文本为条件筛选元素
:param text: 用于匹配的文本
:param fuzzy: 是否模糊匹配
:param contain: 是否包含该字符串False表示不包含
:return: 筛选结果
"""
self._list = _text_all(self._list, SessionElementsList(page=self._list._page),
self._list = _text_all(self._list, SessionElementsList(owner=self._list._owner),
text=text, fuzzy=fuzzy, contain=contain)
return self
def _get_attr(self, name, value, method, equal=True):
"""返回通过某个方法可获得某个值的元素
:param name: 属性名称
:param value: 属性值
:param method: 方法名称
:return: 筛选结果
"""
self._list = _get_attr_all(self._list, SessionElementsList(page=self._list._page),
self._list = _get_attr_all(self._list, SessionElementsList(owner=self._list._owner),
name=name, value=value, method=method, equal=equal)
return self
@ -187,71 +141,30 @@ class SessionFilter(SessionFilterOne):
class ChromiumFilterOne(SessionFilterOne):
def displayed(self, equal=True):
"""以是否显示为条件筛选元素
:param equal: 是否匹配显示的元素False匹配不显示的
:return: 筛选结果
"""
return self._any_state('is_displayed', equal=equal)
def checked(self, equal=True):
"""以是否被选中为条件筛选元素
:param equal: 是否匹配被选中的元素False匹配不被选中的
:return: 筛选结果
"""
return self._any_state('is_checked', equal=equal)
def selected(self, equal=True):
"""以是否被选择为条件筛选元素,用于<select>元素项目
:param equal: 是否匹配被选择的元素False匹配不被选择的
:return: 筛选结果
"""
return self._any_state('is_selected', equal=equal)
def enabled(self, equal=True):
"""以是否可用为条件筛选元素
:param equal: 是否匹配可用的元素False表示匹配disabled状态的
:return: 筛选结果
"""
return self._any_state('is_enabled', equal=equal)
def clickable(self, equal=True):
"""以是否可点击为条件筛选元素
:param equal: 是否匹配可点击的元素False表示匹配不是可点击的
:return: 筛选结果
"""
return self._any_state('is_clickable', equal=equal)
def have_rect(self, equal=True):
"""以是否有大小为条件筛选元素
:param equal: 是否匹配有大小的元素False表示匹配没有大小的
:return: 筛选结果
"""
return self._any_state('has_rect', equal=equal)
def style(self, name, value, equal=True):
"""以是否拥有某个style值为条件筛选元素
:param name: 属性名称
:param value: 属性值
:param equal: True表示匹配name值为value值的元素False表示匹配name值不为value值的
:return: 筛选结果
"""
return self._get_attr(name, value, 'style', equal=equal)
def property(self, name, value, equal=True):
"""以是否拥有某个property值为条件筛选元素
:param name: 属性名称
:param value: 属性值
:param equal: True表示匹配name值为value值的元素False表示匹配name值不为value值的
:return: 筛选结果
"""
return self._get_attr(name, value, 'property', equal=equal)
def _any_state(self, name, equal=True):
"""
:param name: 状态名称
:param equal: 是否是指定状态False表示否定状态
:return: 选中的元素
"""
num = 0
if equal:
for i in self._list:
@ -265,7 +178,7 @@ class ChromiumFilterOne(SessionFilterOne):
num += 1
if self._index == num:
return i
return NoneElement(self._list._page, f'{name}()', args={'equal': equal, 'index': self._index})
return NoneElement(self._list._owner, f'{name}()', args={'equal': equal, 'index': self._index})
class ChromiumFilter(ChromiumFilterOne):
@ -284,69 +197,30 @@ class ChromiumFilter(ChromiumFilterOne):
@property
def get(self):
"""返回用于获取元素属性的对象"""
return self._list.get
def search_one(self, index=1, displayed=None, checked=None, selected=None, enabled=None, clickable=None,
have_rect=None, have_text=None):
"""或关系筛选元素,获取一个结果
:param index: 元素序号从1开始
:param displayed: 是否显示boolNone为忽略该项
:param checked: 是否被选中boolNone为忽略该项
:param selected: 是否被选择boolNone为忽略该项
:param enabled: 是否可用boolNone为忽略该项
:param clickable: 是否可点击boolNone为忽略该项
:param have_rect: 是否拥有大小和位置boolNone为忽略该项
:param have_text: 是否含有文本boolNone为忽略该项
:return: 筛选结果
"""
return _search_one(self._list, index=index, displayed=displayed, checked=checked, selected=selected,
enabled=enabled, clickable=clickable, have_rect=have_rect, have_text=have_text)
def search(self, displayed=None, checked=None, selected=None, enabled=None, clickable=None,
have_rect=None, have_text=None):
"""或关系筛选元素
:param displayed: 是否显示boolNone为忽略该项
:param checked: 是否被选中boolNone为忽略该项
:param selected: 是否被选择boolNone为忽略该项
:param enabled: 是否可用boolNone为忽略该项
:param clickable: 是否可点击boolNone为忽略该项
:param have_rect: 是否拥有大小和位置boolNone为忽略该项
:param have_text: 是否含有文本boolNone为忽略该项
:return: 筛选结果
"""
return _search(self._list, displayed=displayed, checked=checked, selected=selected, enabled=enabled,
clickable=clickable, have_rect=have_rect, have_text=have_text)
def text(self, text, fuzzy=True, contain=True):
"""以是否含有指定文本为条件筛选元素
:param text: 用于匹配的文本
:param fuzzy: 是否模糊匹配
:param contain: 是否包含该字符串False表示不包含
:return: 筛选结果
"""
self._list = _text_all(self._list, ChromiumElementsList(page=self._list._page),
self._list = _text_all(self._list, ChromiumElementsList(owner=self._list._owner),
text=text, fuzzy=fuzzy, contain=contain)
return self
def _get_attr(self, name, value, method, equal=True):
"""返回通过某个方法可获得某个值的元素
:param name: 属性名称
:param value: 属性值
:param method: 方法名称
:return: 筛选结果
"""
self._list = _get_attr_all(self._list, ChromiumElementsList(page=self._list._page),
self._list = _get_attr_all(self._list, ChromiumElementsList(owner=self._list._owner),
name=name, value=value, method=method, equal=equal)
return self
def _any_state(self, name, equal=True):
"""
:param name: 状态名称
:param equal: 是否是指定状态False表示否定状态
:return: 选中的列表
"""
r = ChromiumElementsList(page=self._list._page)
r = ChromiumElementsList(owner=self._list._owner)
if equal:
for i in self._list:
if not isinstance(i, str) and getattr(i.states, name):
@ -364,30 +238,16 @@ class Getter(object):
self._list = _list
def links(self):
"""返回所有元素的link属性组成的列表"""
return [e.link for e in self._list if not isinstance(e, str)]
def texts(self):
"""返回所有元素的text属性组成的列表"""
return [e if isinstance(e, str) else e.text for e in self._list]
def attrs(self, name):
"""返回所有元素指定的attr属性组成的列表
:param name: 属性名称
:return: 属性文本组成的列表
"""
return [e.attr(name) for e in self._list if not isinstance(e, str)]
def get_eles(locators, owner, any_one=False, first_ele=True, timeout=10):
"""传入多个定位符获取多个ele
:param locators: 定位符组成的列表
:param owner: 页面或元素对象
:param any_one: 是否找到任何一个即返回
:param first_ele: 每个定位符是否只获取第一个元素
:param timeout: 超时时间
:return: 多个定位符组成的dict
"""
res = {loc: False for loc in locators}
end_time = perf_counter() + timeout
while perf_counter() <= end_time:
@ -405,12 +265,6 @@ def get_eles(locators, owner, any_one=False, first_ele=True, timeout=10):
def get_frame(owner, loc_ind_ele, timeout=None):
"""获取页面中一个frame对象
:param owner: 要在其中查找元素的对象
:param loc_ind_ele: 定位符iframe序号ChromiumFrame对象序号从1开始可传入负数获取倒数第几个
:param timeout: 查找元素超时时间
:return: ChromiumFrame对象
"""
if isinstance(loc_ind_ele, str):
if not is_loc(loc_ind_ele):
xpath = f'xpath://*[(name()="iframe" or name()="frame") and ' \
@ -492,7 +346,7 @@ def _search(_list, displayed=None, checked=None, selected=None, enabled=None, cl
:param have_text: 是否含有文本boolNone为忽略该项
:return: 筛选结果
"""
r = ChromiumElementsList(page=_list._page)
r = ChromiumElementsList(owner=_list._owner)
for i in _list:
if not isinstance(i, str) and (
(displayed is not None and (displayed is True and i.states.is_displayed)
@ -547,7 +401,7 @@ def _search_one(_list, index=1, displayed=None, checked=None, selected=None, ena
if num == index:
return i
return NoneElement(_list._page, method='filter()', args={'displayed': displayed,
return NoneElement(_list._owner, method='filter()', args={'displayed': displayed,
'checked': checked, 'selected': selected,
'enabled': enabled, 'clickable': clickable,
'have_rect': have_rect, 'have_text': have_text})

View File

@ -10,45 +10,52 @@ from typing import Union, List, Optional, Iterable
from .._base.base import BaseParser
from .._elements.chromium_element import ChromiumElement
from .._elements.session_element import SessionElement
from .._pages.chromium_base import ChromiumBase
from .._pages.chromium_frame import ChromiumFrame
def get_eles(locators: Union[List[str], tuple],
owner: BaseParser,
any_one: bool = False,
first_ele: bool = True,
timeout: float = 10) -> dict: ...
def get_frame(owner: BaseParser,
loc_ind_ele: Union[str, int, tuple, ChromiumFrame, ChromiumElement],
timeout: float = None) -> ChromiumFrame: ...
from .._pages.session_page import SessionPage
class SessionElementsList(list):
_page = ...
_owner: SessionPage = ...
def __init__(self, page=None, *args): ...
def __init__(self,
owner: SessionPage = None,
*args): ...
@property
def get(self) -> Getter: ...
def get(self) -> Getter:
"""返回用于属性的对象"""
...
@property
def filter(self) -> SessionFilter: ...
def filter(self) -> SessionFilter:
"""返回用于筛选多个元素的对象"""
...
@property
def filter_one(self) -> SessionFilterOne: ...
def filter_one(self) -> SessionFilterOne:
"""用于筛选单个元素的对象"""
...
def __next__(self) -> SessionElement: ...
class ChromiumElementsList(SessionElementsList):
_owner: ChromiumBase = ...
def __init__(self,
owner: ChromiumBase = None,
*args): ...
@property
def filter(self) -> ChromiumFilter: ...
def filter(self) -> ChromiumFilter:
"""返回用于筛选多个元素的对象"""
...
@property
def filter_one(self) -> ChromiumFilterOne: ...
def filter_one(self) -> ChromiumFilterOne:
"""用于筛选单个元素的对象"""
...
def search(self,
displayed: Optional[bool] = None,
@ -57,7 +64,18 @@ class ChromiumElementsList(SessionElementsList):
enabled: Optional[bool] = None,
clickable: Optional[bool] = None,
have_rect: Optional[bool] = None,
have_text: Optional[bool] = None) -> ChromiumFilter: ...
have_text: Optional[bool] = None) -> ChromiumFilter:
"""或关系筛选元素
:param displayed: 是否显示boolNone为忽略该项
:param checked: 是否被选中boolNone为忽略该项
:param selected: 是否被选择boolNone为忽略该项
:param enabled: 是否可用boolNone为忽略该项
:param clickable: 是否可点击boolNone为忽略该项
:param have_rect: 是否拥有大小和位置boolNone为忽略该项
:param have_text: 是否含有文本boolNone为忽略该项
:return: 筛选结果
"""
...
def search_one(self,
index: int = 1,
@ -67,7 +85,19 @@ class ChromiumElementsList(SessionElementsList):
enabled: Optional[bool] = None,
clickable: Optional[bool] = None,
have_rect: Optional[bool] = None,
have_text: Optional[bool] = None) -> ChromiumElement: ...
have_text: Optional[bool] = None) -> ChromiumElement:
"""或关系筛选元素,获取一个结果
:param index: 元素序号从1开始
:param displayed: 是否显示boolNone为忽略该项
:param checked: 是否被选中boolNone为忽略该项
:param selected: 是否被选择boolNone为忽略该项
:param enabled: 是否可用boolNone为忽略该项
:param clickable: 是否可点击boolNone为忽略该项
:param have_rect: 是否拥有大小和位置boolNone为忽略该项
:param have_text: 是否含有文本boolNone为忽略该项
:return: 筛选结果
"""
...
def __next__(self) -> ChromiumElement: ...
@ -76,19 +106,49 @@ class SessionFilterOne(object):
_list: SessionElementsList = ...
_index: int = ...
def __init__(self, _list: SessionElementsList, index: int = 1): ...
def __init__(self, _list: SessionElementsList):
"""
:param _list: 元素列表对象
"""
...
def __call__(self, index: int = 1) -> SessionFilterOne: ...
def __call__(self, index: int = 1) -> SessionFilterOne:
"""返回结果中第几个元素
:param index: 元素序号从1开始
:return: 对象自身
"""
...
def attr(self, name: str, value: str, equal: bool = True) -> SessionElement: ...
def attr(self, name: str, value: str, equal: bool = True) -> SessionElement:
"""以是否拥有某个attribute值为条件筛选元素
:param name: 属性名称
:param value: 属性值
:param equal: True表示匹配name值为value值的元素False表示匹配name值不为value值的
:return: 筛选结果
"""
...
def text(self, text: str, fuzzy: bool = True, contain: bool = True) -> SessionElement: ...
def text(self, text: str, fuzzy: bool = True, contain: bool = True) -> SessionElement:
"""以是否含有指定文本为条件筛选元素
:param text: 用于匹配的文本
:param fuzzy: 是否模糊匹配
:param contain: 是否包含该字符串False表示不包含
:return: 筛选结果
"""
...
def _get_attr(self,
name: str,
value: str,
method: str,
equal: bool = True) -> SessionElement: ...
equal: bool = True) -> SessionElement:
"""返回通过某个方法可获得某个值的元素
:param name: 属性名称
:param value: 属性值
:param method: 方法名称
:return: 筛选结果
"""
...
class SessionFilter(SessionFilterOne):
@ -102,54 +162,160 @@ class SessionFilter(SessionFilterOne):
def __getitem__(self, item: int) -> SessionElement: ...
@property
def get(self) -> Getter: ...
def get(self) -> Getter:
"""返回用于获取元素属性的对象"""
...
def attr(self, name: str, value: str, equal: bool = True) -> SessionFilter: ...
def attr(self, name: str, value: str, equal: bool = True) -> SessionFilter:
"""以是否拥有某个attribute值为条件筛选元素
:param name: 属性名称
:param value: 属性值
:param equal: True表示匹配name值为value值的元素False表示匹配name值不为value值的
:return: 筛选结果
"""
...
def text(self, text: str, fuzzy: bool = True, contain: bool = True) -> SessionFilter: ...
def text(self, text: str, fuzzy: bool = True, contain: bool = True) -> SessionFilter:
"""以是否含有指定文本为条件筛选元素
:param text: 用于匹配的文本
:param fuzzy: 是否模糊匹配
:param contain: 是否包含该字符串False表示不包含
:return: 筛选结果
"""
...
def _get_attr(self,
name: str,
value: str,
method: str,
equal: bool = True) -> SessionFilter: ...
equal: bool = True) -> SessionFilter:
"""返回通过某个方法可获得某个值的元素
:param name: 属性名称
:param value: 属性值
:param method: 方法名称
:return: 筛选结果
"""
...
class ChromiumFilterOne(SessionFilterOne):
_list: ChromiumElementsList = ...
def __init__(self, _list: ChromiumElementsList): ...
def __init__(self, _list: ChromiumElementsList):
"""
:param _list: 元素列表对象
"""
...
def __call__(self, index: int = 1) -> ChromiumFilterOne: ...
def __call__(self, index: int = 1) -> ChromiumFilterOne:
"""返回结果中第几个元素
:param index: 元素序号从1开始
:return: 对象自身
"""
...
def displayed(self, equal: bool = True) -> ChromiumElement: ...
def displayed(self, equal: bool = True) -> ChromiumElement:
"""以是否显示为条件筛选元素
:param equal: 是否匹配显示的元素False匹配不显示的
:return: 筛选结果
"""
...
def checked(self, equal: bool = True) -> ChromiumElement: ...
def checked(self, equal: bool = True) -> ChromiumElement:
"""以是否被选中为条件筛选元素
:param equal: 是否匹配被选中的元素False匹配不被选中的
:return: 筛选结果
"""
...
def selected(self, equal: bool = True) -> ChromiumElement: ...
def selected(self, equal: bool = True) -> ChromiumElement:
"""以是否被选择为条件筛选元素,用于<select>元素项目
:param equal: 是否匹配被选择的元素False匹配不被选择的
:return: 筛选结果
"""
...
def enabled(self, equal: bool = True) -> ChromiumElement: ...
def enabled(self, equal: bool = True) -> ChromiumElement:
"""以是否可用为条件筛选元素
:param equal: 是否匹配可用的元素False表示匹配disabled状态的
:return: 筛选结果
"""
...
def clickable(self, equal: bool = True) -> ChromiumElement: ...
def clickable(self, equal: bool = True) -> ChromiumElement:
"""以是否可点击为条件筛选元素
:param equal: 是否匹配可点击的元素False表示匹配不是可点击的
:return: 筛选结果
"""
...
def have_rect(self, equal: bool = True) -> ChromiumElement: ...
def have_rect(self, equal: bool = True) -> ChromiumElement:
"""以是否有大小为条件筛选元素
:param equal: 是否匹配有大小的元素False表示匹配没有大小的
:return: 筛选结果
"""
...
def style(self, name: str, value: str, equal: bool = True) -> ChromiumElement: ...
def style(self, name: str, value: str, equal: bool = True) -> ChromiumElement:
"""以是否拥有某个style值为条件筛选元素
:param name: 属性名称
:param value: 属性值
:param equal: True表示匹配name值为value值的元素False表示匹配name值不为value值的
:return: 筛选结果
"""
...
def property(self,
name: str,
value: str, equal: bool = True) -> ChromiumElement: ...
value: str, equal: bool = True) -> ChromiumElement:
"""以是否拥有某个property值为条件筛选元素
:param name: 属性名称
:param value: 属性值
:param equal: True表示匹配name值为value值的元素False表示匹配name值不为value值的
:return: 筛选结果
"""
...
def attr(self, name: str, value: str, equal: bool = True) -> ChromiumElement: ...
def attr(self, name: str, value: str, equal: bool = True) -> ChromiumElement:
"""以是否拥有某个attribute值为条件筛选元素
:param name: 属性名称
:param value: 属性值
:param equal: True表示匹配name值为value值的元素False表示匹配name值不为value值的
:return: 筛选结果
"""
...
def text(self, text: str, fuzzy: bool = True, contain: bool = True) -> ChromiumElement: ...
def text(self,
text: str,
fuzzy: bool = True,
contain: bool = True) -> ChromiumElement:
"""以是否含有指定文本为条件筛选元素
:param text: 用于匹配的文本
:param fuzzy: 是否模糊匹配
:param contain: 是否包含该字符串False表示不包含
:return: 筛选结果
"""
...
def _get_attr(self,
name: str,
value: str,
method: str, equal: bool = True) -> ChromiumElement: ...
method: str, equal: bool = True) -> ChromiumElement:
"""返回通过某个方法可获得某个值的元素
:param name: 属性名称
:param value: 属性值
:param method: 方法名称
:return: 筛选结果
"""
...
def _any_state(self, name: str, equal: bool = True) -> ChromiumElement: ...
def _any_state(self, name: str, equal: bool = True) -> ChromiumElement:
"""
:param name: 状态名称
:param equal: 是否是指定状态False表示否定状态
:return: 选中的列表
"""
...
class ChromiumFilter(ChromiumFilterOne):
@ -163,38 +329,80 @@ class ChromiumFilter(ChromiumFilterOne):
def __getitem__(self, item: int) -> ChromiumElement: ...
@property
def get(self) -> Getter: ...
def get(self) -> Getter:
"""返回用于获取元素属性的对象"""
...
def displayed(self, equal: bool = True) -> ChromiumFilter: ...
def displayed(self, equal: bool = True) -> ChromiumFilter:
"""以是否显示为条件筛选元素
:param equal: 是否匹配显示的元素False匹配不显示的
:return: 筛选结果
"""
...
def checked(self, equal: bool = True) -> ChromiumFilter: ...
def checked(self, equal: bool = True) -> ChromiumFilter:
"""以是否被选中为条件筛选元素
:param equal: 是否匹配被选中的元素False匹配不被选中的
:return: 筛选结果
"""
...
def selected(self, equal: bool = True) -> ChromiumFilter: ...
def selected(self, equal: bool = True) -> ChromiumFilter:
"""以是否被选择为条件筛选元素,用于<select>元素项目
:param equal: 是否匹配被选择的元素False匹配不被选择的
:return: 筛选结果
"""
...
def enabled(self, equal: bool = True) -> ChromiumFilter: ...
def enabled(self, equal: bool = True) -> ChromiumFilter:
"""以是否可用为条件筛选元素
:param equal: 是否匹配可用的元素False表示匹配disabled状态的
:return: 筛选结果
"""
...
def clickable(self, equal: bool = True) -> ChromiumFilter: ...
def clickable(self, equal: bool = True) -> ChromiumFilter:
"""以是否可点击为条件筛选元素
:param equal: 是否匹配可点击的元素False表示匹配不是可点击的
:return: 筛选结果
"""
...
def have_rect(self, equal: bool = True) -> ChromiumFilter: ...
def have_rect(self, equal: bool = True) -> ChromiumFilter:
"""以是否有大小为条件筛选元素
:param equal: 是否匹配有大小的元素False表示匹配没有大小的
:return: 筛选结果
"""
...
def style(self, name: str, value: str, equal: bool = True) -> ChromiumFilter: ...
def style(self, name: str, value: str, equal: bool = True) -> ChromiumFilter:
"""以是否拥有某个style值为条件筛选元素
:param name: 属性名称
:param value: 属性值
:param equal: True表示匹配name值为value值的元素False表示匹配name值不为value值的
:return: 筛选结果
"""
...
def property(self,
name: str,
value: str, equal: bool = True) -> ChromiumFilter: ...
value: str, equal: bool = True) -> ChromiumFilter:
"""以是否拥有某个property值为条件筛选元素
:param name: 属性名称
:param value: 属性值
:param equal: True表示匹配name值为value值的元素False表示匹配name值不为value值的
:return: 筛选结果
"""
...
def attr(self, name: str, value: str, equal: bool = True) -> ChromiumFilter: ...
def text(self, text: str, fuzzy: bool = True, contain: bool = True) -> ChromiumFilter: ...
def search(self,
displayed: Optional[bool] = None,
checked: Optional[bool] = None,
selected: Optional[bool] = None,
enabled: Optional[bool] = None,
clickable: Optional[bool] = None,
have_rect: Optional[bool] = None,
have_text: Optional[bool] = None) -> ChromiumFilter: ...
def attr(self, name: str, value: str, equal: bool = True) -> ChromiumFilter:
"""以是否拥有某个attribute值为条件筛选元素
:param name: 属性名称
:param value: 属性值
:param equal: True表示匹配name值为value值的元素False表示匹配name值不为value值的
:return: 筛选结果
"""
...
def search_one(self,
index: int = 1,
@ -204,23 +412,118 @@ class ChromiumFilter(ChromiumFilterOne):
enabled: Optional[bool] = None,
clickable: Optional[bool] = None,
have_rect: Optional[bool] = None,
have_text: Optional[bool] = None) -> ChromiumElement: ...
have_text: Optional[bool] = None) -> ChromiumElement:
"""或关系筛选元素,获取一个结果
:param index: 元素序号从1开始
:param displayed: 是否显示boolNone为忽略该项
:param checked: 是否被选中boolNone为忽略该项
:param selected: 是否被选择boolNone为忽略该项
:param enabled: 是否可用boolNone为忽略该项
:param clickable: 是否可点击boolNone为忽略该项
:param have_rect: 是否拥有大小和位置boolNone为忽略该项
:param have_text: 是否含有文本boolNone为忽略该项
:return: 筛选结果
"""
...
def search(self,
displayed: Optional[bool] = None,
checked: Optional[bool] = None,
selected: Optional[bool] = None,
enabled: Optional[bool] = None,
clickable: Optional[bool] = None,
have_rect: Optional[bool] = None,
have_text: Optional[bool] = None) -> ChromiumFilter:
"""或关系筛选元素
:param displayed: 是否显示boolNone为忽略该项
:param checked: 是否被选中boolNone为忽略该项
:param selected: 是否被选择boolNone为忽略该项
:param enabled: 是否可用boolNone为忽略该项
:param clickable: 是否可点击boolNone为忽略该项
:param have_rect: 是否拥有大小和位置boolNone为忽略该项
:param have_text: 是否含有文本boolNone为忽略该项
:return: 筛选结果
"""
...
def text(self, text: str, fuzzy: bool = True, contain: bool = True) -> ChromiumFilter:
"""以是否含有指定文本为条件筛选元素
:param text: 用于匹配的文本
:param fuzzy: 是否模糊匹配
:param contain: 是否包含该字符串False表示不包含
:return: 筛选结果
"""
...
def _get_attr(self,
name: str,
value: str,
method: str, equal: bool = True) -> ChromiumFilter: ...
method: str, equal: bool = True) -> ChromiumFilter:
"""返回通过某个方法可获得某个值的元素
:param name: 属性名称
:param value: 属性值
:param method: 方法名称
:return: 筛选结果
"""
...
def _any_state(self, name: str, equal: bool = True) -> ChromiumFilter: ...
def _any_state(self, name: str, equal: bool = True) -> ChromiumFilter:
"""
:param name: 状态名称
:param equal: 是否是指定状态False表示否定状态
:return: 选中的列表
"""
...
class Getter(object):
_list: SessionElementsList = ...
def __init__(self, _list: SessionElementsList): ...
def __init__(self, _list: SessionElementsList):
"""
:param _list: 元素列表对象
"""
...
def links(self) -> List[str]: ...
def links(self) -> List[str]:
"""返回所有元素的link属性组成的列表"""
...
def texts(self) -> List[str]: ...
def texts(self) -> List[str]:
"""返回所有元素的text属性组成的列表"""
...
def attrs(self, name: str) -> List[str]: ...
def attrs(self, name: str) -> List[str]:
"""返回所有元素指定的attr属性组成的列表
:param name: 属性名称
:return: 属性文本组成的列表
"""
...
def get_eles(locators: Union[List[str], tuple],
owner: BaseParser,
any_one: bool = False,
first_ele: bool = True,
timeout: float = 10) -> dict:
"""传入多个定位符获取多个ele
:param locators: 定位符组成的列表
:param owner: 页面或元素对象
:param any_one: 是否找到任何一个即返回
:param first_ele: 每个定位符是否只获取第一个元素
:param timeout: 超时时间
:return: 多个定位符组成的dict
"""
...
def get_frame(owner: BaseParser,
loc_ind_ele: Union[str, int, tuple, ChromiumFrame, ChromiumElement],
timeout: float = None) -> ChromiumFrame:
"""获取页面中一个frame对象
:param owner: 要在其中查找元素的对象
:param loc_ind_ele: 定位符iframe序号ChromiumFrame对象序号从1开始可传入负数获取倒数第几个
:param timeout: 查找元素超时时间
:return: ChromiumFrame对象
"""
...

View File

@ -12,12 +12,8 @@ from .._functions.web import location_in_viewport
class Actions:
"""用于实现动作链的类"""
def __init__(self, owner):
"""
:param owner: ChromiumBase对象
"""
self.owner = owner
self._dr = owner.driver
self.modifier = 0 # 修饰符Alt=1, Ctrl=2, Meta/Command=4, Shift=8
@ -26,14 +22,6 @@ class Actions:
self._holding = 'left'
def move_to(self, ele_or_loc, offset_x=None, offset_y=None, duration=.5):
"""鼠标移动到元素中点,或页面上的某个绝对坐标。可设置偏移量
当带偏移量时偏移量相对于元素左上角坐标
:param ele_or_loc: 元素对象绝对坐标或文本定位符坐标为tuple(int, int)形式
:param offset_x: 偏移量x
:param offset_y: 偏移量y
:param duration: 拖动用时传入0即瞬间到达
:return: self
"""
is_loc = False
mid_point = offset_x == offset_y is None
if offset_x is None:
@ -73,12 +61,6 @@ class Actions:
return self
def move(self, offset_x=0, offset_y=0, duration=.5):
"""鼠标相对当前位置移动若干位置
:param offset_x: 偏移量x
:param offset_y: 偏移量y
:param duration: 拖动用时传入0即瞬间到达
:return: self
"""
duration = .02 if duration < .02 else duration
num = int(duration * 50)
@ -99,93 +81,48 @@ class Actions:
return self
def click(self, on_ele=None, times=1):
"""点击鼠标左键,可先移动到元素上
:param on_ele: ChromiumElement元素或文本定位符
:param times: 点击次数
:return: self
"""
self._hold(on_ele, 'left', times).wait(.05)._release('left')
return self
def r_click(self, on_ele=None, times=1):
"""点击鼠标右键,可先移动到元素上
:param on_ele: ChromiumElement元素或文本定位符
:param times: 点击次数
:return: self
"""
self._hold(on_ele, 'right', times).wait(.05)._release('right')
return self
def m_click(self, on_ele=None, times=1):
"""点击鼠标中键,可先移动到元素上
:param on_ele: ChromiumElement元素或文本定位符
:param times: 点击次数
:return: self
"""
self._hold(on_ele, 'middle', times).wait(.05)._release('middle')
return self
def hold(self, on_ele=None):
"""按住鼠标左键,可先移动到元素上
:param on_ele: ChromiumElement元素或文本定位符
:return: self
"""
self._hold(on_ele, 'left')
return self
def release(self, on_ele=None):
"""释放鼠标左键,可先移动到元素上
:param on_ele: ChromiumElement元素或文本定位符
:return: self
"""
if on_ele:
self.move_to(on_ele, duration=.2)
self._release('left')
return self
def r_hold(self, on_ele=None):
"""按住鼠标右键,可先移动到元素上
:param on_ele: ChromiumElement元素或文本定位符
:return: self
"""
self._hold(on_ele, 'right')
return self
def r_release(self, on_ele=None):
"""释放鼠标右键,可先移动到元素上
:param on_ele: ChromiumElement元素或文本定位符
:return: self
"""
if on_ele:
self.move_to(on_ele, duration=.2)
self._release('right')
return self
def m_hold(self, on_ele=None):
"""按住鼠标中键,可先移动到元素上
:param on_ele: ChromiumElement元素或文本定位符
:return: self
"""
self._hold(on_ele, 'middle')
return self
def m_release(self, on_ele=None):
"""释放鼠标中键,可先移动到元素上
:param on_ele: ChromiumElement元素或文本定位符
:return: self
"""
if on_ele:
self.move_to(on_ele, duration=.2)
self._release('middle')
return self
def _hold(self, on_ele=None, button='left', count=1):
"""按下鼠标按键
:param on_ele: ChromiumElement元素或文本定位符
:param button: 要按下的按键
:param count: 点击次数
:return: self
"""
if on_ele:
self.move_to(on_ele, duration=.2)
self._dr.run('Input.dispatchMouseEvent', type='mousePressed', button=button, clickCount=count,
@ -194,22 +131,12 @@ class Actions:
return self
def _release(self, button):
"""释放鼠标按键
:param button: 要释放的按键
:return: self
"""
self._dr.run('Input.dispatchMouseEvent', type='mouseReleased', button=button, clickCount=1,
x=self.curr_x, y=self.curr_y, modifiers=self.modifier)
self._holding = 'left'
return self
def scroll(self, delta_y=0, delta_x=0, on_ele=None):
"""滚动鼠标滚轮,可先移动到元素上
:param delta_y: 滚轮变化值y
:param delta_x: 滚轮变化值x
:param on_ele: ChromiumElement元素
:return: self
"""
if on_ele:
self.move_to(on_ele, duration=.2)
self._dr.run('Input.dispatchMouseEvent', type='mouseWheel', x=self.curr_x, y=self.curr_y,
@ -217,38 +144,18 @@ class Actions:
return self
def up(self, pixel):
"""鼠标向上移动若干像素
:param pixel: 鼠标移动的像素值
:return: self
"""
return self.move(0, -pixel)
def down(self, pixel):
"""鼠标向下移动若干像素
:param pixel: 鼠标移动的像素值
:return: self
"""
return self.move(0, pixel)
def left(self, pixel):
"""鼠标向左移动若干像素
:param pixel: 鼠标移动的像素值
:return: self
"""
return self.move(-pixel, 0)
def right(self, pixel):
"""鼠标向右移动若干像素
:param pixel: 鼠标移动的像素值
:return: self
"""
return self.move(pixel, 0)
def key_down(self, key):
"""按下键盘上的按键,
:param key: 使用Keys获取的按键'DEL'形式按键名称
:return: self
"""
key = getattr(Keys, key.upper(), key)
if key in ('\ue009', '\ue008', '\ue00a', '\ue03d'): # 如果上修饰符,添加到变量
self.modifier |= modifierBit.get(key, 0)
@ -261,10 +168,6 @@ class Actions:
return self
def key_up(self, key):
"""提起键盘上的按键
:param key: 按键特殊字符见Keys
:return: self
"""
key = getattr(Keys, key.upper(), key)
if key in ('\ue009', '\ue008', '\ue00a', '\ue03d'): # 如果上修饰符,添加到变量
self.modifier ^= modifierBit.get(key, 0)
@ -277,10 +180,6 @@ class Actions:
return self
def type(self, keys):
"""用模拟键盘按键方式输入文本,可输入字符串,也可输入组合键
:param keys: 要按下的按键特殊字符和多个文本可用list或tuple传入
:return: self
"""
modifiers = []
if not isinstance(keys, (str, tuple, list)):
keys = str(keys)
@ -304,25 +203,15 @@ class Actions:
return self
def input(self, text):
"""输入文本也可输入组合键组合键用tuple形式输入
:param text: 文本值或按键组合
:return: self
"""
input_text_or_keys(self.owner, text)
return self
def wait(self, second, scope=None):
"""等待若干秒,如传入两个参数,等待时间为这两个数间的一个随机数
:param second: 秒数
:param scope: 随机数范围
:return: None
"""
self.owner.wait(second=second, scope=scope)
return self
def location_to_client(page, lx, ly):
"""绝对坐标转换为视口坐标"""
scroll_x = page._run_js('return document.documentElement.scrollLeft;')
scroll_y = page._run_js('return document.documentElement.scrollTop;')
return lx - scroll_x, ly - scroll_y

View File

@ -43,63 +43,207 @@ KEYS = Literal['NULL', 'CANCEL', 'HELP', 'BACKSPACE', 'meta',
class Actions:
"""用于实现动作链的类"""
owner: ChromiumBase = ...
_dr: Driver = ...
modifier: int = ...
curr_x: float = ...
curr_y: float = ...
_holding: str = ...
def __init__(self, owner: ChromiumBase):
self.owner: ChromiumBase = ...
self._dr: Driver = ...
self.modifier: int = ...
self.curr_x: int = ...
self.curr_y: int = ...
self._holding: str = ...
"""
:param owner: ChromiumBase对象
"""
...
def move_to(self, ele_or_loc: Union[ChromiumElement, Tuple[float, float], str],
offset_x: float = 0, offset_y: float = 0, duration: float = .5) -> Actions: ...
offset_x: float = 0, offset_y: float = 0, duration: float = .5) -> Actions:
"""鼠标移动到元素中点,或页面上的某个绝对坐标。可设置偏移量
当带偏移量时偏移量相对于元素左上角坐标
:param ele_or_loc: 元素对象绝对坐标或文本定位符坐标为tuple(int, int)形式
:param offset_x: 偏移量x
:param offset_y: 偏移量y
:param duration: 拖动用时传入0即瞬间到达
:return: self
"""
...
def move(self, offset_x: float = 0, offset_y: float = 0, duration: float = .5) -> Actions: ...
def move(self, offset_x: float = 0, offset_y: float = 0, duration: float = .5) -> Actions:
"""鼠标相对当前位置移动若干位置
:param offset_x: 偏移量x
:param offset_y: 偏移量y
:param duration: 拖动用时传入0即瞬间到达
:return: self
"""
...
def click(self, on_ele: Union[ChromiumElement, str] = None, times: int = 1) -> Actions: ...
def click(self, on_ele: Union[ChromiumElement, str] = None, times: int = 1) -> Actions:
"""点击鼠标左键,可先移动到元素上
:param on_ele: ChromiumElement元素或文本定位符
:param times: 点击次数
:return: self
"""
...
def r_click(self, on_ele: Union[ChromiumElement, str] = None, times: int = 1) -> Actions: ...
def r_click(self, on_ele: Union[ChromiumElement, str] = None, times: int = 1) -> Actions:
"""点击鼠标右键,可先移动到元素上
:param on_ele: ChromiumElement元素或文本定位符
:param times: 点击次数
:return: self
"""
...
def m_click(self, on_ele: Union[ChromiumElement, str] = None, times: int = 1) -> Actions: ...
def m_click(self, on_ele: Union[ChromiumElement, str] = None, times: int = 1) -> Actions:
"""点击鼠标中键,可先移动到元素上
:param on_ele: ChromiumElement元素或文本定位符
:param times: 点击次数
:return: self
"""
...
def hold(self, on_ele: Union[ChromiumElement, str] = None) -> Actions: ...
def hold(self, on_ele: Union[ChromiumElement, str] = None) -> Actions:
"""按住鼠标左键,可先移动到元素上
:param on_ele: ChromiumElement元素或文本定位符
:return: self
"""
...
def release(self, on_ele: Union[ChromiumElement, str] = None) -> Actions: ...
def release(self, on_ele: Union[ChromiumElement, str] = None) -> Actions:
"""释放鼠标左键,可先移动到元素上
:param on_ele: ChromiumElement元素或文本定位符
:return: self
"""
...
def r_hold(self, on_ele: Union[ChromiumElement, str] = None) -> Actions: ...
def r_hold(self, on_ele: Union[ChromiumElement, str] = None) -> Actions:
"""按住鼠标右键,可先移动到元素上
:param on_ele: ChromiumElement元素或文本定位符
:return: self
"""
...
def r_release(self, on_ele: Union[ChromiumElement, str] = None) -> Actions: ...
def r_release(self, on_ele: Union[ChromiumElement, str] = None) -> Actions:
"""释放鼠标右键,可先移动到元素上
:param on_ele: ChromiumElement元素或文本定位符
:return: self
"""
...
def m_hold(self, on_ele: Union[ChromiumElement, str] = None) -> Actions: ...
def m_hold(self, on_ele: Union[ChromiumElement, str] = None) -> Actions:
"""按住鼠标中键,可先移动到元素上
:param on_ele: ChromiumElement元素或文本定位符
:return: self
"""
...
def m_release(self, on_ele: Union[ChromiumElement, str] = None) -> Actions: ...
def m_release(self, on_ele: Union[ChromiumElement, str] = None) -> Actions:
"""释放鼠标中键,可先移动到元素上
:param on_ele: ChromiumElement元素或文本定位符
:return: self
"""
...
def _hold(self, on_ele: Union[ChromiumElement, str] = None, button: str = 'left',
count: int = 1) -> Actions: ...
def _hold(self,
on_ele: Union[ChromiumElement, str] = None,
button: str = 'left',
count: int = 1) -> Actions:
"""按下鼠标按键
:param on_ele: ChromiumElement元素或文本定位符
:param button: 要按下的按键
:param count: 点击次数
:return: self
"""
...
def _release(self, button: str) -> Actions: ...
def _release(self, button: str) -> Actions:
"""释放鼠标按键
:param button: 要释放的按键
:return: self
"""
...
def scroll(self, delta_y: int = 0, delta_x: int = 0,
on_ele: Union[ChromiumElement, str] = None) -> Actions: ...
on_ele: Union[ChromiumElement, str] = None) -> Actions:
"""滚动鼠标滚轮,可先移动到元素上
:param delta_y: 滚轮变化值y
:param delta_x: 滚轮变化值x
:param on_ele: ChromiumElement元素
:return: self
"""
...
def up(self, pixel: int) -> Actions: ...
def up(self, pixel: int) -> Actions:
"""鼠标向上移动若干像素
:param pixel: 鼠标移动的像素值
:return: self
"""
...
def down(self, pixel: int) -> Actions: ...
def down(self, pixel: int) -> Actions:
"""鼠标向下移动若干像素
:param pixel: 鼠标移动的像素值
:return: self
"""
...
def left(self, pixel: int) -> Actions: ...
def left(self, pixel: int) -> Actions:
"""鼠标向左移动若干像素
:param pixel: 鼠标移动的像素值
:return: self
"""
...
def right(self, pixel: int) -> Actions: ...
def right(self, pixel: int) -> Actions:
"""鼠标向右移动若干像素
:param pixel: 鼠标移动的像素值
:return: self
"""
...
def key_down(self, key: Union[KEYS, str]) -> Actions: ...
def key_down(self, key: Union[KEYS, str]) -> Actions:
"""按下键盘上的按键,
:param key: 使用Keys获取的按键'DEL'形式按键名称
:return: self
"""
...
def key_up(self, key: Union[KEYS, str]) -> Actions: ...
def key_up(self, key: Union[KEYS, str]) -> Actions:
"""提起键盘上的按键
:param key: 按键特殊字符见Keys
:return: self
"""
...
def type(self, keys: Union[KEYS, str, list, tuple]) -> Actions: ...
def type(self, keys: Union[KEYS, str, list, tuple]) -> Actions:
"""用模拟键盘按键方式输入文本,可输入字符串,也可输入组合键
:param keys: 要按下的按键特殊字符和多个文本可用list或tuple传入
:return: self
"""
...
def input(self, text: Any) -> Actions: ...
def input(self, text: Any) -> Actions:
"""输入文本也可输入组合键组合键用tuple形式输入
:param text: 文本值或按键组合
:return: self
"""
...
def wait(self, second: float, scope: float = None) -> Actions: ...
def wait(self, second: float, scope: float = None) -> Actions:
"""等待若干秒,如传入两个参数,等待时间为这两个数间的一个随机数
:param second: 秒数
:param scope: 随机数范围
:return: None
"""
...
def location_to_client(page, lx: int, ly: int) -> tuple: ...
def location_to_client(page: ChromiumBase, lx: int, ly: int) -> tuple:
"""绝对坐标转换为视口坐标
:param page: 页面对象
:param lx: 绝对坐标x
:param ly: 绝对坐标y
:return: 视口坐标元组
"""
...

View File

@ -26,14 +26,9 @@ class Screencast(object):
@property
def set_mode(self):
"""返回用于设置录屏幕式的对象"""
return ScreencastMode(self)
def start(self, save_path=None):
"""开始录屏
:param save_path: 录屏保存位置
:return: None
"""
self.set_save_path(save_path)
if self._path is None:
raise ValueError('save_path必须设置。')
@ -83,10 +78,6 @@ class Screencast(object):
self._owner._run_js(js)
def stop(self, video_name=None):
"""停止录屏
:param video_name: 视频文件名为None时以当前时间名命
:return: 文件路径
"""
if video_name and not video_name.endswith('mp4'):
video_name = f'{video_name}.mp4'
name = f'{time()}.mp4' if not video_name else video_name
@ -128,7 +119,7 @@ class Screencast(object):
imgInfo = img.shape
size = (imgInfo[1], imgInfo[0])
videoWrite = VideoWriter(path, VideoWriter_fourcc(*"mp4v"), 5, size)
videoWrite = VideoWriter(path, VideoWriter_fourcc(*"H264"), 5, size)
for i in pic_list:
img = imread(str(i))
@ -139,10 +130,6 @@ class Screencast(object):
return f'{self._path}{sep}{name}'
def set_save_path(self, save_path=None):
"""设置保存路径
:param save_path: 保存路径
:return: None
"""
if save_path:
save_path = Path(save_path)
if save_path.exists() and save_path.is_file():
@ -151,7 +138,6 @@ class Screencast(object):
self._path = save_path
def _run(self):
"""非节俭模式运行方法"""
self._running = True
path = self._tmp_path or self._path
while self._enable:
@ -160,7 +146,6 @@ class Screencast(object):
self._running = False
def _onScreencastFrame(self, **kwargs):
"""节俭模式运行方法"""
path = self._tmp_path or self._path
with open(f'{path}{sep}{kwargs["metadata"]["timestamp"]}.jpg', 'wb') as f:
f.write(b64decode(kwargs['data']))
@ -172,21 +157,16 @@ class ScreencastMode(object):
self._screencast = screencast
def video_mode(self):
"""持续视频模式,生成的视频没有声音"""
self._screencast._mode = 'video'
def frugal_video_mode(self):
"""设置节俭视频模式,页面有变化时才录制,生成的视频没有声音"""
self._screencast._mode = 'frugal_video'
def js_video_mode(self):
"""设置使用js录制视频模式可生成有声音的视频但需要手动启动"""
self._screencast._mode = 'js_video'
def frugal_imgs_mode(self):
"""设置节俭视频模式,页面有变化时才截图"""
self._screencast._mode = 'frugal_imgs'
def imgs_mode(self):
"""设置图片模式,持续对页面进行截图"""
self._screencast._mode = 'imgs'

View File

@ -6,44 +6,84 @@
@License : BSD 3-Clause.
"""
from pathlib import Path
from typing import Union
from typing import Union, Optional
from .._pages.chromium_base import ChromiumBase
class Screencast(object):
_owner: ChromiumBase = ...
_path: Optional[Path] = ...
_tmp_path: Optional[Path] = ...
_running: bool = ...
_enable: bool = ...
_mode: str = ...
def __init__(self, owner: ChromiumBase):
self._owner: ChromiumBase = ...
self._path: Path = ...
self._tmp_path: Path = ...
self._running: bool = ...
self._enable: bool = ...
self._mode: str = ...
"""
:param owner: 页面对象
"""
@property
def set_mode(self) -> ScreencastMode: ...
def set_mode(self) -> ScreencastMode:
"""返回用于设置录屏幕式的对象"""
...
def start(self, save_path: Union[str, Path] = None) -> None: ...
def start(self, save_path: Union[str, Path] = None) -> None:
"""开始录屏
:param save_path: 录屏保存位置
:return: None
"""
...
def stop(self, video_name: str = None) -> str: ...
def stop(self, video_name: str = None) -> str:
"""停止录屏
:param video_name: 视频文件名为None时以当前时间名命
:return: 文件路径
"""
...
def set_save_path(self, save_path: Union[str, Path] = None) -> None: ...
def set_save_path(self, save_path: Union[str, Path] = None) -> None:
"""设置保存路径
:param save_path: 保存路径
:return: None
"""
...
def _run(self) -> None: ...
def _run(self) -> None:
"""非节俭模式运行方法"""
...
def _onScreencastFrame(self, **kwargs) -> None: ...
def _onScreencastFrame(self, **kwargs) -> None:
"""节俭模式运行方法"""
...
class ScreencastMode(object):
_screencast: Screencast = ...
def __init__(self, screencast: Screencast):
self._screencast: Screencast = ...
"""
:param screencast: Screencast对象
"""
...
def video_mode(self) -> None: ...
def video_mode(self) -> None:
"""持续视频模式,生成的视频没有声音"""
...
def frugal_video_mode(self) -> None: ...
def frugal_video_mode(self) -> None:
"""设置节俭视频模式,页面有变化时才录制,生成的视频没有声音"""
...
def js_video_mode(self) -> None: ...
def js_video_mode(self) -> None:
"""设置使用js录制视频模式可生成有声音的视频但需要手动启动"""
...
def frugal_imgs_mode(self) -> None: ...
def frugal_imgs_mode(self) -> None:
"""设置节俭视频模式,页面有变化时才截图"""
...
def imgs_mode(self) -> None: ...
def imgs_mode(self) -> None:
"""设置图片模式,持续对页面进行截图"""
...

View File

@ -23,9 +23,9 @@ class ElementStates(object):
@property
def is_displayed(self):
return not (self._ele.style('visibility') == 'hidden' or
self._ele._run_js('return this.offsetParent === null;')
or self._ele.style('display') == 'none' or self._ele.property('hidden'))
return not (self._ele.style('visibility') == 'hidden'
or self._ele.style('display') == 'none'
or self._ele.property('hidden'))
@property
def is_enabled(self):