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

View File

@ -36,144 +36,368 @@ class ChromiumOptions(object):
_is_headless: bool = ... _is_headless: bool = ...
_ua_set: 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 @property
def download_path(self) -> str: ... def download_path(self) -> str:
"""默认下载路径文件路径"""
...
@property @property
def browser_path(self) -> str: ... def browser_path(self) -> str:
"""浏览器启动文件路径"""
...
@property @property
def user_data_path(self) -> str: ... def user_data_path(self) -> str:
"""返回用户数据文件夹路径"""
...
@property @property
def tmp_path(self) -> Optional[str]: ... def tmp_path(self) -> Optional[str]:
"""返回临时文件夹路径"""
...
@property @property
def user(self) -> str: ... def user(self) -> str:
"""返回用户配置文件夹名称"""
...
@property @property
def load_mode(self) -> str: ... def load_mode(self) -> str:
"""返回页面加载策略,'normal', 'eager', 'none'"""
...
@property @property
def timeouts(self) -> dict: ... def timeouts(self) -> dict:
"""返回timeouts设置"""
...
@property @property
def proxy(self) -> str: ... def proxy(self) -> str:
"""返回代理设置"""
...
@property @property
def address(self) -> str: ... def address(self) -> str:
"""返回浏览器地址ip:port"""
...
@property @property
def arguments(self) -> list: ... def arguments(self) -> list:
"""返回浏览器命令行设置列表"""
...
@property @property
def extensions(self) -> list: ... def extensions(self) -> list:
"""以list形式返回要加载的插件路径"""
...
@property @property
def preferences(self) -> dict: ... def preferences(self) -> dict:
"""返回用户首选项配置"""
...
@property @property
def flags(self) -> dict: ... def flags(self) -> dict:
"""返回实验项配置"""
...
@property @property
def system_user_path(self) -> bool: ... def system_user_path(self) -> bool:
"""返回是否使用系统安装的浏览器所使用的用户数据文件夹"""
...
@property @property
def is_existing_only(self) -> bool: ... def is_existing_only(self) -> bool:
"""返回是否只接管现有浏览器方式"""
...
@property @property
def is_auto_port(self) -> Union[bool, Tuple[int, int]]: ... def is_auto_port(self) -> Union[bool, Tuple[int, int]]:
"""返回是否使用自动端口和用户文件如指定范围则返回范围tuple"""
...
@property @property
def retry_times(self) -> int: ... def retry_times(self) -> int:
"""返回连接失败时的重试次数"""
...
@property @property
def retry_interval(self) -> float: ... def retry_interval(self) -> float:
"""返回连接失败时的重试间隔(秒)"""
...
@property @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, def set_timeouts(self,
base: float = None, base: float = None,
page_load: 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, 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, address: str = None, download_path: Union[str, Path] = None, user_data_path: Union[str, Path] = None,
cache_path: Union[str, Path] = None) -> ChromiumOptions: ... 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, def auto_port(self,
on_off: bool = True, 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): def __init__(self, path=None):
"""初始化,读取配置文件,如没有设置临时文件夹,则设置并新建
:param path: ini文件的路径为None则找项目文件夹下的找不到则读取模块文件夹下的
"""
if path is False: if path is False:
self.ini_path = None self.ini_path = None
else: else:
@ -79,18 +76,9 @@ class OptionsManager(object):
self.set_item('others', 'retry_interval', '2') self.set_item('others', 'retry_interval', '2')
def __getattr__(self, item): def __getattr__(self, item):
"""以dict形似返回获取大项信息
:param item: 项名
:return: None
"""
return self.get_option(item) return self.get_option(item)
def get_value(self, section, item): def get_value(self, section, item):
"""获取配置的值
:param section: 段名
:param item: 项名
:return: 项值
"""
try: try:
return eval(self._conf.get(section, item)) return eval(self._conf.get(section, item))
except (SyntaxError, NameError): except (SyntaxError, NameError):
@ -99,10 +87,6 @@ class OptionsManager(object):
return None return None
def get_option(self, section): def get_option(self, section):
"""把section内容以字典方式返回
:param section: 段名
:return: 段内容生成的字典
"""
items = self._conf.items(section) items = self._conf.items(section)
option = dict() option = dict()
@ -115,30 +99,15 @@ class OptionsManager(object):
return option return option
def set_item(self, section, item, value): def set_item(self, section, item, value):
"""设置配置值
:param section: 段名
:param item: 项名
:param value: 项值
:return: None
"""
self._conf.set(section, item, str(value)) self._conf.set(section, item, str(value))
self.__setattr__(f'_{section}', None) self.__setattr__(f'_{section}', None)
return self return self
def remove_item(self, section, item): def remove_item(self, section, item):
"""删除配置值
:param section: 段名
:param item: 项名
:return: None
"""
self._conf.remove_option(section, item) self._conf.remove_option(section, item)
return self return self
def save(self, path=None): def save(self, path=None):
"""保存配置文件
:param path: ini文件的路径传入 'default' 保存到默认ini文件
:return: 保存路径
"""
default_path = (Path(__file__).parent / 'configs.ini').absolute() default_path = (Path(__file__).parent / 'configs.ini').absolute()
if path == 'default': if path == 'default':
path = default_path path = default_path
@ -163,11 +132,9 @@ class OptionsManager(object):
return path return path
def save_to_default(self): def save_to_default(self):
"""保存当前配置到默认ini文件"""
return self.save('default') return self.save('default')
def show(self): def show(self):
"""打印所有设置信息"""
for i in self._conf.sections(): for i in self._conf.sections():
print(f'[{i}]') print(f'[{i}]')
pprint(self.get_option(i)) pprint(self.get_option(i))

View File

@ -15,20 +15,62 @@ class OptionsManager(object):
file_exists: bool = ... file_exists: bool = ...
_conf: RawConfigParser = ... _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): class SessionOptions(object):
"""requests的Session对象配置类"""
def __init__(self, read_file=True, ini_path=None): def __init__(self, read_file=True, ini_path=None):
"""
:param read_file: 是否从文件读取配置
:param ini_path: ini文件路径
"""
self.ini_path = None self.ini_path = None
self._download_path = '.' self._download_path = '.'
self._timeout = 10 self._timeout = 10
@ -93,62 +88,39 @@ class SessionOptions(object):
# ===========须独立处理的项开始============ # ===========须独立处理的项开始============
@property @property
def download_path(self): def download_path(self):
"""返回默认下载路径属性信息"""
return self._download_path return self._download_path
def set_download_path(self, path): def set_download_path(self, path):
"""设置默认下载路径
:param path: 下载路径
:return: 返回当前对象
"""
self._download_path = '.' if path is None else str(path) self._download_path = '.' if path is None else str(path)
return self return self
@property @property
def timeout(self): def timeout(self):
"""返回timeout属性信息"""
return self._timeout return self._timeout
def set_timeout(self, second): def set_timeout(self, second):
"""设置超时信息
:param second: 秒数
:return: 返回当前对象
"""
self._timeout = second self._timeout = second
return self return self
@property @property
def proxies(self): def proxies(self):
"""返回proxies设置信息"""
if self._proxies is None: if self._proxies is None:
self._proxies = {} self._proxies = {}
return self._proxies return self._proxies
def set_proxies(self, http=None, https=None): def set_proxies(self, http=None, https=None):
"""设置proxies参数
:param http: http代理地址
:param https: https代理地址
:return: 返回当前对象
"""
self._sets('proxies', {'http': http, 'https': https}) self._sets('proxies', {'http': http, 'https': https})
return self return self
@property @property
def retry_times(self): def retry_times(self):
"""返回连接失败时的重试次数"""
return self._retry_times return self._retry_times
@property @property
def retry_interval(self): def retry_interval(self):
"""返回连接失败时的重试间隔(秒)"""
return self._retry_interval return self._retry_interval
def set_retry(self, times=None, interval=None): def set_retry(self, times=None, interval=None):
"""设置连接失败时的重试操作
:param times: 重试次数
:param interval: 重试间隔
:return: 当前对象
"""
if times is not None: if times is not None:
self._retry_times = times self._retry_times = times
if interval is not None: if interval is not None:
@ -159,16 +131,11 @@ class SessionOptions(object):
@property @property
def headers(self): def headers(self):
"""返回headers设置信息"""
if self._headers is None: if self._headers is None:
self._headers = {} self._headers = {}
return self._headers return self._headers
def set_headers(self, headers): def set_headers(self, headers):
"""设置headers参数
:param headers: 参数值传入None可在ini文件标记删除
:return: 返回当前对象
"""
if headers is None: if headers is None:
self._headers = None self._headers = None
self._del_set.add('headers') self._del_set.add('headers')
@ -178,11 +145,6 @@ class SessionOptions(object):
return self return self
def set_a_header(self, name, value): def set_a_header(self, name, value):
"""设置headers中一个项
:param name: 设置名称
:param value: 设置值
:return: 返回当前对象
"""
if self._headers is None: if self._headers is None:
self._headers = {} self._headers = {}
@ -190,10 +152,6 @@ class SessionOptions(object):
return self return self
def remove_a_header(self, name): def remove_a_header(self, name):
"""从headers中删除一个设置
:param name: 要删除的设置
:return: 返回当前对象
"""
if self._headers is None: if self._headers is None:
return self return self
@ -202,156 +160,99 @@ class SessionOptions(object):
return self return self
def clear_headers(self): def clear_headers(self):
"""清空已设置的header参数"""
self._headers = None self._headers = None
self._del_set.add('headers') self._del_set.add('headers')
@property @property
def cookies(self): def cookies(self):
"""以list形式返回cookies"""
if self._cookies is None: if self._cookies is None:
self._cookies = [] self._cookies = []
return self._cookies return self._cookies
def set_cookies(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)) cookies = cookies if cookies is None else list(cookies_to_tuple(cookies))
self._sets('cookies', cookies) self._sets('cookies', cookies)
return self return self
@property @property
def auth(self): def auth(self):
"""返回认证设置信息"""
return self._auth return self._auth
def set_auth(self, auth): def set_auth(self, auth):
"""设置认证元组或对象
:param auth: 认证元组或对象
:return: 返回当前对象
"""
self._sets('auth', auth) self._sets('auth', auth)
return self return self
@property @property
def hooks(self): def hooks(self):
"""返回回调方法"""
if self._hooks is None: if self._hooks is None:
self._hooks = {} self._hooks = {}
return self._hooks return self._hooks
def set_hooks(self, hooks): def set_hooks(self, hooks):
"""设置回调方法
:param hooks: 回调方法
:return: 返回当前对象
"""
self._hooks = hooks self._hooks = hooks
return self return self
@property @property
def params(self): def params(self):
"""返回连接参数设置信息"""
if self._params is None: if self._params is None:
self._params = {} self._params = {}
return self._params return self._params
def set_params(self, params): def set_params(self, params):
"""设置查询参数字典
:param params: 查询参数字典
:return: 返回当前对象
"""
self._sets('params', params) self._sets('params', params)
return self return self
@property @property
def verify(self): def verify(self):
"""返回是否验证SSL证书设置"""
return self._verify return self._verify
def set_verify(self, on_off): def set_verify(self, on_off):
"""设置是否验证SSL证书
:param on_off: 是否验证 SSL 证书
:return: 返回当前对象
"""
self._sets('verify', on_off) self._sets('verify', on_off)
return self return self
@property @property
def cert(self): def cert(self):
"""返回SSL证书设置信息"""
return self._cert return self._cert
def set_cert(self, cert): def set_cert(self, cert):
"""SSL客户端证书文件的路径(.pem格式),或(cert, key)元组
:param cert: 证书路径或元组
:return: 返回当前对象
"""
self._sets('cert', cert) self._sets('cert', cert)
return self return self
@property @property
def adapters(self): def adapters(self):
"""返回适配器设置信息"""
if self._adapters is None: if self._adapters is None:
self._adapters = [] self._adapters = []
return self._adapters return self._adapters
def add_adapter(self, url, adapter): def add_adapter(self, url, adapter):
"""添加适配器
:param url: 适配器对应url
:param adapter: 适配器对象
:return: 返回当前对象
"""
self._adapters.append((url, adapter)) self._adapters.append((url, adapter))
return self return self
@property @property
def stream(self): def stream(self):
"""返回是否使用流式响应内容设置信息"""
return self._stream return self._stream
def set_stream(self, on_off): def set_stream(self, on_off):
"""设置是否使用流式响应内容
:param on_off: 是否使用流式响应内容
:return: 返回当前对象
"""
self._sets('stream', on_off) self._sets('stream', on_off)
return self return self
@property @property
def trust_env(self): def trust_env(self):
"""返回是否信任环境设置信息"""
return self._trust_env return self._trust_env
def set_trust_env(self, on_off): def set_trust_env(self, on_off):
"""设置是否信任环境
:param on_off: 是否信任环境
:return: 返回当前对象
"""
self._sets('trust_env', on_off) self._sets('trust_env', on_off)
return self return self
@property @property
def max_redirects(self): def max_redirects(self):
"""返回最大重定向次数"""
return self._max_redirects return self._max_redirects
def set_max_redirects(self, times): def set_max_redirects(self, times):
"""设置最大重定向次数
:param times: 最大重定向次数
:return: 返回当前对象
"""
self._sets('max_redirects', times) self._sets('max_redirects', times)
return self return self
def _sets(self, arg, val): def _sets(self, arg, val):
"""给属性赋值或标记删除
:param arg: 属性名称
:param val: 参数值
:return: None
"""
if val is None: if val is None:
self.__setattr__(f'_{arg}', None) self.__setattr__(f'_{arg}', None)
self._del_set.add(arg) self._del_set.add(arg)
@ -361,10 +262,6 @@ class SessionOptions(object):
self._del_set.remove(arg) self._del_set.remove(arg)
def save(self, path=None): def save(self, path=None):
"""保存设置到文件
:param path: ini文件的路径传入 'default' 保存到默认ini文件
:return: 保存文件的绝对路径
"""
if path == 'default': if path == 'default':
path = (Path(__file__).parent / 'configs.ini').absolute() path = (Path(__file__).parent / 'configs.ini').absolute()
@ -412,15 +309,12 @@ class SessionOptions(object):
return path return path
def save_to_default(self): def save_to_default(self):
"""保存当前配置到默认ini文件"""
return self.save('default') return self.save('default')
def as_dict(self): def as_dict(self):
"""以字典形式返回本对象"""
return session_options_to_dict(self) return session_options_to_dict(self)
def make_session(self): def make_session(self):
"""根据内在的配置生成Session对象headers从对象中分离"""
s = Session() s = Session()
h = CaseInsensitiveDict(self.headers) if self.headers else CaseInsensitiveDict() h = CaseInsensitiveDict(self.headers) if self.headers else CaseInsensitiveDict()
@ -438,11 +332,6 @@ class SessionOptions(object):
return s, h return s, h
def from_session(self, session, headers=None): 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._headers = CaseInsensitiveDict(copy(session.headers).update(headers)) if headers else session.headers
self._cookies = session.cookies self._cookies = session.cookies
self._auth = session.auth self._auth = session.auth
@ -463,10 +352,6 @@ class SessionOptions(object):
def session_options_to_dict(options): def session_options_to_dict(options):
"""把session配置对象转换为字典
:param options: session配置对象或字典
:return: 配置字典
"""
if options in (False, None): if options in (False, None):
return SessionOptions(read_file=False).as_dict() 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 import Session
from requests.adapters import HTTPAdapter from requests.adapters import HTTPAdapter
from requests.auth import HTTPBasicAuth from requests.auth import HTTPBasicAuth
from requests.cookies import RequestsCookieJar
from requests.structures import CaseInsensitiveDict from requests.structures import CaseInsensitiveDict
class SessionOptions(object): class SessionOptions(object):
def __init__(self, read_file: [bool, None] = True, ini_path: Union[str, Path] = None): """requests的Session对象配置类"""
self.ini_path: str = ...
self._download_path: str = ... ini_path: Optional[str] = ...
self._headers: dict = ... _download_path: str = ...
self._cookies: list = ... _headers: Union[dict, CaseInsensitiveDict, None] = ...
self._auth: tuple = ... _cookies: Union[list, RequestsCookieJar, None] = ...
self._proxies: dict = ... _auth: Optional[tuple] = ...
self._hooks: dict = ... _proxies: Optional[dict] = ...
self._params: dict = ... _hooks: Optional[dict] = ...
self._verify: bool = ... _params: Union[dict, None] = ...
self._cert: Union[str, tuple] = ... _verify: Optional[bool] = ...
self._adapters: list = ... _cert: Union[str, tuple, None] = ...
self._stream: bool = ... _adapters: Optional[list] = ...
self._trust_env: bool = ... _stream: Optional[bool] = ...
self._max_redirects: int = ... _trust_env: Optional[bool] = ...
self._timeout: float = ... _max_redirects: Optional[int] = ...
self._del_set: set = ... _timeout: float = ...
self._retry_times: int = ... _del_set: set = ...
self._retry_interval: float = ... _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 @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 @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 @property
def headers(self) -> dict: ... def proxies(self) -> dict:
"""返回proxies设置信息"""
...
def set_headers(self, headers: Union[dict, str, None]) -> SessionOptions: ... def set_proxies(self, http: Union[str, None], https: Union[str, None] = None) -> SessionOptions:
"""设置proxies参数
def set_a_header(self, name: str, value: str) -> SessionOptions: ... :param http: http代理地址
:param https: https代理地址
def remove_a_header(self, name: str) -> SessionOptions: ... :return: 返回当前对象
"""
def clear_headers(self) -> SessionOptions: ... ...
@property @property
def cookies(self) -> list: ... def retry_times(self) -> int:
"""返回连接失败时的重试次数"""
def set_cookies(self, cookies: Union[Cookie, CookieJar, list, tuple, str, dict, None]) -> SessionOptions: ... ...
@property @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 @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 @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 @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 @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 @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 @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 @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 @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 @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 @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 @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: else:
self.owner.actions.type(vals) self.owner.actions.type(vals)
return self
def clear(self, by_js=False): def clear(self, by_js=False):
if by_js: if by_js:
self._run_js("this.value='';") self._run_js("this.value='';")
@ -574,6 +576,7 @@ class ChromiumElement(DrissionElement):
self._input_focus() self._input_focus()
self.input(('\ue009', 'a', '\ue017'), clear=False) self.input(('\ue009', 'a', '\ue017'), clear=False)
return self
def _input_focus(self): def _input_focus(self):
try: try:
@ -586,15 +589,18 @@ class ChromiumElement(DrissionElement):
self.owner._run_cdp('DOM.focus', backendNodeId=self._backend_id) self.owner._run_cdp('DOM.focus', backendNodeId=self._backend_id)
except Exception: except Exception:
self._run_js('this.focus();') self._run_js('this.focus();')
return self
def hover(self, offset_x=None, offset_y=None): 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) 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): def drag(self, offset_x=0, offset_y=0, duration=.5):
curr_x, curr_y = self.rect.midpoint curr_x, curr_y = self.rect.midpoint
offset_x += curr_x offset_x += curr_x
offset_y += curr_y offset_y += curr_y
self.drag_to((offset_x, offset_y), duration) self.drag_to((offset_x, offset_y), duration)
return self
def drag_to(self, ele_or_loc, duration=.5): def drag_to(self, ele_or_loc, duration=.5):
if isinstance(ele_or_loc, ChromiumElement): if isinstance(ele_or_loc, ChromiumElement):
@ -602,6 +608,7 @@ class ChromiumElement(DrissionElement):
elif not isinstance(ele_or_loc, (list, tuple)): elif not isinstance(ele_or_loc, (list, tuple)):
raise TypeError('需要ChromiumElement对象或坐标。') raise TypeError('需要ChromiumElement对象或坐标。')
self.owner.actions.hold(self).move_to(ele_or_loc, duration=duration).release() 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): def _get_obj_id(self, node_id=None, backend_id=None):
if node_id: if node_id:
@ -675,6 +682,7 @@ class ChromiumElement(DrissionElement):
files = files.split('\n') files = files.split('\n')
files = [str(Path(i).absolute()) for i in files] files = [str(Path(i).absolute()) for i in files]
self.owner._run_cdp('DOM.setFileInputFiles', files=files, backendNodeId=self._backend_id) self.owner._run_cdp('DOM.setFileInputFiles', files=files, backendNodeId=self._backend_id)
return self
class ShadowRoot(BaseElement): 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间隔) """输入文本或组合键也可用于输入文件路径到input元素路径间用\n间隔)
:param vals: 文本值或按键组合 :param vals: 文本值或按键组合
:param clear: 输入前是否清空文本框 :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模拟输入删除 :param by_js: 是否用js方式清空为False则用全选+del模拟输入删除
:return: None :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值时悬停在元素中点 """鼠标悬停可接受偏移量偏移量相对于元素左上角坐标。不传入offset_x和offset_y值时悬停在元素中点
:param offset_x: 相对元素左上角坐标的x轴偏移量 :param offset_x: 相对元素左上角坐标的x轴偏移量
:param offset_y: 相对元素左上角坐标的y轴偏移量 :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_x: x变化值
:param offset_y: y变化值 :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) """拖拽当前元素,目标为另一个元素或坐标元组(x, y)
:param ele_or_loc: 另一个元素或坐标元组坐标为元素中点的坐标 :param ele_or_loc: 另一个元素或坐标元组坐标为元素中点的坐标
:param duration: 拖动用时传入0即瞬间到达 :param duration: 拖动用时传入0即瞬间到达

View File

@ -11,11 +11,6 @@ from ..errors import ElementNotFoundError
class NoneElement(object): class NoneElement(object):
def __init__(self, page=None, method=None, args=None): 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时不自动抛出由调用者处理 if method and Settings.raise_when_ele_not_found: # 无传入method时不自动抛出由调用者处理
raise ElementNotFoundError(None, method=method, arguments=args) raise ElementNotFoundError(None, method=method, arguments=args)
@ -49,11 +44,10 @@ class NoneElement(object):
raise ElementNotFoundError(None, self.method, self.args) raise ElementNotFoundError(None, self.method, self.args)
def __eq__(self, other): def __eq__(self, other):
if other is None: return other is None
return True
def __bool__(self): def __bool__(self):
return False return False
def __repr__(self): 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): def connect_browser(option):
"""连接或启动浏览器
:param option: ChromiumOptions对象
:return: 返回是否接管的浏览器
"""
address = option.address.replace('localhost', '127.0.0.1').lstrip('http://').lstrip('https://') address = option.address.replace('localhost', '127.0.0.1').lstrip('http://').lstrip('https://')
browser_path = option.browser_path browser_path = option.browser_path
@ -67,10 +63,6 @@ def connect_browser(option):
def get_launch_args(opt): def get_launch_args(opt):
"""从ChromiumOptions获取命令行启动参数
:param opt: ChromiumOptions
:return: 启动参数列表
"""
# ----------处理arguments----------- # ----------处理arguments-----------
result = set() result = set()
user_path = False user_path = False
@ -107,10 +99,6 @@ def get_launch_args(opt):
def set_prefs(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): if not opt.user_data_path or (not opt.preferences and not opt._prefs_to_del):
return return
prefs = opt.preferences prefs = opt.preferences
@ -149,10 +137,6 @@ def set_prefs(opt):
def set_flags(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): if not opt.user_data_path or (not opt.clear_file_flags and not opt.flags):
return return
@ -185,12 +169,6 @@ def set_flags(opt):
def test_connect(ip, port, timeout=30): def test_connect(ip, port, timeout=30):
"""测试浏览器是否可用
:param ip: 浏览器ip
:param port: 浏览器端口
:param timeout: 超时时间
:return: None
"""
end_time = perf_counter() + timeout end_time = perf_counter() + timeout
s = Session() s = Session()
s.trust_env = False 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): def get_chrome_path(ini_path):
"""从ini文件或系统变量中获取chrome可执行文件的路径"""
# -----------从ini文件中获取-------------- # -----------从ini文件中获取--------------
if ini_path and Path(ini_path).exists(): if ini_path and Path(ini_path).exists():
path = OptionsManager(ini_path).chromium_options.get('browser_path', None) 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 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): def cookie_to_dict(cookie):
"""把Cookie对象转为dict格式
:param cookie: Cookie对象字符串或字典
:return: cookie字典
"""
if isinstance(cookie, Cookie): if isinstance(cookie, Cookie):
cookie_dict = cookie.__dict__.copy() cookie_dict = cookie.__dict__.copy()
cookie_dict.pop('rfc2109', None) cookie_dict.pop('rfc2109', None)
@ -44,10 +40,6 @@ def cookie_to_dict(cookie):
def cookies_to_tuple(cookies): def cookies_to_tuple(cookies):
"""把cookies转为tuple格式
:param cookies: cookies信息可为CookieJar, list, tuple, str, dict
:return: 返回tuple形式的cookies
"""
if isinstance(cookies, (list, tuple, CookieJar)): if isinstance(cookies, (list, tuple, CookieJar)):
cookies = tuple(cookie_to_dict(cookie) for cookie in cookies) 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): def set_session_cookies(session, cookies):
"""设置Session对象的cookies
:param session: Session对象
:param cookies: cookies信息
:return: None
"""
for cookie in cookies_to_tuple(cookies): for cookie in cookies_to_tuple(cookies):
if cookie['value'] is None: if cookie['value'] is None:
cookie['value'] = '' cookie['value'] = ''
@ -94,11 +81,6 @@ def set_session_cookies(session, cookies):
def set_browser_cookies(browser, cookies): def set_browser_cookies(browser, cookies):
"""设置cookies值
:param browser: 页面对象
:param cookies: cookies信息
:return: None
"""
c = [] c = []
for cookie in cookies_to_tuple(cookies): for cookie in cookies_to_tuple(cookies):
if 'domain' not in cookie and 'url' not in cookie: 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): def set_tab_cookies(page, cookies):
"""设置cookies值
:param page: 页面对象
:param cookies: cookies信息
:return: None
"""
for cookie in cookies_to_tuple(cookies): for cookie in cookies_to_tuple(cookies):
cookie = format_cookie(cookie) cookie = format_cookie(cookie)
@ -154,11 +131,6 @@ def set_tab_cookies(page, cookies):
def is_cookie_in_driver(page, cookie): def is_cookie_in_driver(page, cookie):
"""查询cookie是否在浏览器内
:param page: BasePage对象
:param cookie: dict格式cookie
:return: bool
"""
if 'domain' in cookie: if 'domain' in cookie:
for c in page.cookies(all_domains=True): for c in page.cookies(all_domains=True):
if cookie['name'] == c['name'] and cookie['value'] == c['value'] and cookie['domain'] == c.get('domain', 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): def format_cookie(cookie):
"""设置cookie为可用格式
:param cookie: dict格式cookie
:return: 格式化后的cookie字典
"""
if 'expiry' in cookie: if 'expiry' in cookie:
cookie['expires'] = int(cookie['expiry']) cookie['expires'] = int(cookie['expiry'])
cookie.pop('expiry') cookie.pop('expiry')
@ -235,15 +203,12 @@ def format_cookie(cookie):
class CookiesList(list): class CookiesList(list):
def as_dict(self): def as_dict(self):
"""以dict格式返回只包含name和value字段"""
return {c['name']: c['value'] for c in self} return {c['name']: c['value'] for c in self}
def as_str(self): def as_str(self):
"""以str格式返回只包含name和value字段"""
return '; '.join([f'{c["name"]}={c["value"]}' for c in self]) return '; '.join([f'{c["name"]}={c["value"]}' for c in self])
def as_json(self): def as_json(self):
"""以json格式返回"""
from json import dumps from json import dumps
return dumps(self) return dumps(self)

View File

@ -15,32 +15,80 @@ from .._base.browser import Chromium
from .._pages.chromium_base import ChromiumBase 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): 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: ... def __next__(self) -> dict: ...

View File

@ -12,9 +12,9 @@ from .._elements.none_element import NoneElement
class SessionElementsList(list): class SessionElementsList(list):
def __init__(self, page=None, *args): def __init__(self, owner=None, *args):
super().__init__(*args) super().__init__(*args)
self._page = page self._owner = owner
@property @property
def get(self): 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, def search_one(self, index=1, displayed=None, checked=None, selected=None, enabled=None, clickable=None,
have_rect=None, have_text=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, return _search_one(self, index=index, displayed=displayed, checked=checked, selected=selected,
enabled=enabled, clickable=clickable, have_rect=have_rect, have_text=have_text) enabled=enabled, clickable=clickable, have_rect=have_rect, have_text=have_text)
@ -77,29 +66,13 @@ class SessionFilterOne(object):
self._index = 1 self._index = 1
def __call__(self, index=1): def __call__(self, index=1):
"""返回结果中第几个元素
:param index: 元素序号从1开始
:return: 对象自身
"""
self._index = index self._index = index
return self return self
def attr(self, name, value, equal=True): 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) return self._get_attr(name, value, 'attr', equal=equal)
def text(self, text, fuzzy=True, contain=True): def text(self, text, fuzzy=True, contain=True):
"""以是否含有指定文本为条件筛选元素
:param text: 用于匹配的文本
:param fuzzy: 是否模糊匹配
:param contain: 是否包含该字符串False表示不包含
:return: 筛选结果
"""
num = 0 num = 0
if contain: if contain:
for i in self._list: for i in self._list:
@ -115,16 +88,10 @@ class SessionFilterOne(object):
num += 1 num += 1
if self._index == num: if self._index == num:
return i return i
return NoneElement(self._list._page, 'text()', return NoneElement(self._list._owner, 'text()',
args={'text': text, 'fuzzy': fuzzy, 'contain': contain, 'index': self._index}) args={'text': text, 'fuzzy': fuzzy, 'contain': contain, 'index': self._index})
def _get_attr(self, name, value, method, equal=True): def _get_attr(self, name, value, method, equal=True):
"""返回通过某个方法可获得某个值的元素
:param name: 属性名称
:param value: 属性值
:param method: 方法名称
:return: 筛选结果
"""
num = 0 num = 0
if equal: if equal:
for i in self._list: for i in self._list:
@ -138,7 +105,7 @@ class SessionFilterOne(object):
num += 1 num += 1
if self._index == num: if self._index == num:
return i 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}) args={'name': name, 'value': value, 'equal': equal, 'index': self._index})
@ -158,28 +125,15 @@ class SessionFilter(SessionFilterOne):
@property @property
def get(self): def get(self):
"""返回用于获取元素属性的对象"""
return self._list.get return self._list.get
def text(self, text, fuzzy=True, contain=True): def text(self, text, fuzzy=True, contain=True):
"""以是否含有指定文本为条件筛选元素 self._list = _text_all(self._list, SessionElementsList(owner=self._list._owner),
:param text: 用于匹配的文本
:param fuzzy: 是否模糊匹配
:param contain: 是否包含该字符串False表示不包含
:return: 筛选结果
"""
self._list = _text_all(self._list, SessionElementsList(page=self._list._page),
text=text, fuzzy=fuzzy, contain=contain) text=text, fuzzy=fuzzy, contain=contain)
return self return self
def _get_attr(self, name, value, method, equal=True): def _get_attr(self, name, value, method, equal=True):
"""返回通过某个方法可获得某个值的元素 self._list = _get_attr_all(self._list, SessionElementsList(owner=self._list._owner),
:param name: 属性名称
:param value: 属性值
:param method: 方法名称
:return: 筛选结果
"""
self._list = _get_attr_all(self._list, SessionElementsList(page=self._list._page),
name=name, value=value, method=method, equal=equal) name=name, value=value, method=method, equal=equal)
return self return self
@ -187,71 +141,30 @@ class SessionFilter(SessionFilterOne):
class ChromiumFilterOne(SessionFilterOne): class ChromiumFilterOne(SessionFilterOne):
def displayed(self, equal=True): def displayed(self, equal=True):
"""以是否显示为条件筛选元素
:param equal: 是否匹配显示的元素False匹配不显示的
:return: 筛选结果
"""
return self._any_state('is_displayed', equal=equal) return self._any_state('is_displayed', equal=equal)
def checked(self, equal=True): def checked(self, equal=True):
"""以是否被选中为条件筛选元素
:param equal: 是否匹配被选中的元素False匹配不被选中的
:return: 筛选结果
"""
return self._any_state('is_checked', equal=equal) return self._any_state('is_checked', equal=equal)
def selected(self, equal=True): def selected(self, equal=True):
"""以是否被选择为条件筛选元素,用于<select>元素项目
:param equal: 是否匹配被选择的元素False匹配不被选择的
:return: 筛选结果
"""
return self._any_state('is_selected', equal=equal) return self._any_state('is_selected', equal=equal)
def enabled(self, equal=True): def enabled(self, equal=True):
"""以是否可用为条件筛选元素
:param equal: 是否匹配可用的元素False表示匹配disabled状态的
:return: 筛选结果
"""
return self._any_state('is_enabled', equal=equal) return self._any_state('is_enabled', equal=equal)
def clickable(self, equal=True): def clickable(self, equal=True):
"""以是否可点击为条件筛选元素
:param equal: 是否匹配可点击的元素False表示匹配不是可点击的
:return: 筛选结果
"""
return self._any_state('is_clickable', equal=equal) return self._any_state('is_clickable', equal=equal)
def have_rect(self, equal=True): def have_rect(self, equal=True):
"""以是否有大小为条件筛选元素
:param equal: 是否匹配有大小的元素False表示匹配没有大小的
:return: 筛选结果
"""
return self._any_state('has_rect', equal=equal) return self._any_state('has_rect', equal=equal)
def style(self, name, value, equal=True): 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) return self._get_attr(name, value, 'style', equal=equal)
def property(self, name, value, equal=True): 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) return self._get_attr(name, value, 'property', equal=equal)
def _any_state(self, name, equal=True): def _any_state(self, name, equal=True):
"""
:param name: 状态名称
:param equal: 是否是指定状态False表示否定状态
:return: 选中的元素
"""
num = 0 num = 0
if equal: if equal:
for i in self._list: for i in self._list:
@ -265,7 +178,7 @@ class ChromiumFilterOne(SessionFilterOne):
num += 1 num += 1
if self._index == num: if self._index == num:
return i 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): class ChromiumFilter(ChromiumFilterOne):
@ -284,69 +197,30 @@ class ChromiumFilter(ChromiumFilterOne):
@property @property
def get(self): def get(self):
"""返回用于获取元素属性的对象"""
return self._list.get return self._list.get
def search_one(self, index=1, displayed=None, checked=None, selected=None, enabled=None, clickable=None, def search_one(self, index=1, displayed=None, checked=None, selected=None, enabled=None, clickable=None,
have_rect=None, have_text=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, 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) 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, def search(self, displayed=None, checked=None, selected=None, enabled=None, clickable=None,
have_rect=None, have_text=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, return _search(self._list, displayed=displayed, checked=checked, selected=selected, enabled=enabled,
clickable=clickable, have_rect=have_rect, have_text=have_text) clickable=clickable, have_rect=have_rect, have_text=have_text)
def text(self, text, fuzzy=True, contain=True): def text(self, text, fuzzy=True, contain=True):
"""以是否含有指定文本为条件筛选元素 self._list = _text_all(self._list, ChromiumElementsList(owner=self._list._owner),
:param text: 用于匹配的文本
:param fuzzy: 是否模糊匹配
:param contain: 是否包含该字符串False表示不包含
:return: 筛选结果
"""
self._list = _text_all(self._list, ChromiumElementsList(page=self._list._page),
text=text, fuzzy=fuzzy, contain=contain) text=text, fuzzy=fuzzy, contain=contain)
return self return self
def _get_attr(self, name, value, method, equal=True): def _get_attr(self, name, value, method, equal=True):
"""返回通过某个方法可获得某个值的元素 self._list = _get_attr_all(self._list, ChromiumElementsList(owner=self._list._owner),
:param name: 属性名称
:param value: 属性值
:param method: 方法名称
:return: 筛选结果
"""
self._list = _get_attr_all(self._list, ChromiumElementsList(page=self._list._page),
name=name, value=value, method=method, equal=equal) name=name, value=value, method=method, equal=equal)
return self return self
def _any_state(self, name, equal=True): def _any_state(self, name, equal=True):
""" r = ChromiumElementsList(owner=self._list._owner)
:param name: 状态名称
:param equal: 是否是指定状态False表示否定状态
:return: 选中的列表
"""
r = ChromiumElementsList(page=self._list._page)
if equal: if equal:
for i in self._list: for i in self._list:
if not isinstance(i, str) and getattr(i.states, name): if not isinstance(i, str) and getattr(i.states, name):
@ -364,30 +238,16 @@ class Getter(object):
self._list = _list self._list = _list
def links(self): def links(self):
"""返回所有元素的link属性组成的列表"""
return [e.link for e in self._list if not isinstance(e, str)] return [e.link for e in self._list if not isinstance(e, str)]
def texts(self): def texts(self):
"""返回所有元素的text属性组成的列表"""
return [e if isinstance(e, str) else e.text for e in self._list] return [e if isinstance(e, str) else e.text for e in self._list]
def attrs(self, name): def attrs(self, name):
"""返回所有元素指定的attr属性组成的列表
:param name: 属性名称
:return: 属性文本组成的列表
"""
return [e.attr(name) for e in self._list if not isinstance(e, str)] 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): 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} res = {loc: False for loc in locators}
end_time = perf_counter() + timeout end_time = perf_counter() + timeout
while perf_counter() <= end_time: 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): 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 isinstance(loc_ind_ele, str):
if not is_loc(loc_ind_ele): if not is_loc(loc_ind_ele):
xpath = f'xpath://*[(name()="iframe" or name()="frame") and ' \ 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为忽略该项 :param have_text: 是否含有文本boolNone为忽略该项
:return: 筛选结果 :return: 筛选结果
""" """
r = ChromiumElementsList(page=_list._page) r = ChromiumElementsList(owner=_list._owner)
for i in _list: for i in _list:
if not isinstance(i, str) and ( if not isinstance(i, str) and (
(displayed is not None and (displayed is True and i.states.is_displayed) (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: if num == index:
return i return i
return NoneElement(_list._page, method='filter()', args={'displayed': displayed, return NoneElement(_list._owner, method='filter()', args={'displayed': displayed,
'checked': checked, 'selected': selected, 'checked': checked, 'selected': selected,
'enabled': enabled, 'clickable': clickable, 'enabled': enabled, 'clickable': clickable,
'have_rect': have_rect, 'have_text': have_text}) '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 .._base.base import BaseParser
from .._elements.chromium_element import ChromiumElement from .._elements.chromium_element import ChromiumElement
from .._elements.session_element import SessionElement from .._elements.session_element import SessionElement
from .._pages.chromium_base import ChromiumBase
from .._pages.chromium_frame import ChromiumFrame from .._pages.chromium_frame import ChromiumFrame
from .._pages.session_page import SessionPage
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: ...
class SessionElementsList(list): class SessionElementsList(list):
_page = ... _owner: SessionPage = ...
def __init__(self, page=None, *args): ... def __init__(self,
owner: SessionPage = None,
*args): ...
@property @property
def get(self) -> Getter: ... def get(self) -> Getter:
"""返回用于属性的对象"""
...
@property @property
def filter(self) -> SessionFilter: ... def filter(self) -> SessionFilter:
"""返回用于筛选多个元素的对象"""
...
@property @property
def filter_one(self) -> SessionFilterOne: ... def filter_one(self) -> SessionFilterOne:
"""用于筛选单个元素的对象"""
...
def __next__(self) -> SessionElement: ... def __next__(self) -> SessionElement: ...
class ChromiumElementsList(SessionElementsList): class ChromiumElementsList(SessionElementsList):
_owner: ChromiumBase = ...
def __init__(self,
owner: ChromiumBase = None,
*args): ...
@property @property
def filter(self) -> ChromiumFilter: ... def filter(self) -> ChromiumFilter:
"""返回用于筛选多个元素的对象"""
...
@property @property
def filter_one(self) -> ChromiumFilterOne: ... def filter_one(self) -> ChromiumFilterOne:
"""用于筛选单个元素的对象"""
...
def search(self, def search(self,
displayed: Optional[bool] = None, displayed: Optional[bool] = None,
@ -57,7 +64,18 @@ class ChromiumElementsList(SessionElementsList):
enabled: Optional[bool] = None, enabled: Optional[bool] = None,
clickable: Optional[bool] = None, clickable: Optional[bool] = None,
have_rect: 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, def search_one(self,
index: int = 1, index: int = 1,
@ -67,7 +85,19 @@ class ChromiumElementsList(SessionElementsList):
enabled: Optional[bool] = None, enabled: Optional[bool] = None,
clickable: Optional[bool] = None, clickable: Optional[bool] = None,
have_rect: 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: ... def __next__(self) -> ChromiumElement: ...
@ -76,19 +106,49 @@ class SessionFilterOne(object):
_list: SessionElementsList = ... _list: SessionElementsList = ...
_index: int = ... _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, def _get_attr(self,
name: str, name: str,
value: str, value: str,
method: str, method: str,
equal: bool = True) -> SessionElement: ... equal: bool = True) -> SessionElement:
"""返回通过某个方法可获得某个值的元素
:param name: 属性名称
:param value: 属性值
:param method: 方法名称
:return: 筛选结果
"""
...
class SessionFilter(SessionFilterOne): class SessionFilter(SessionFilterOne):
@ -102,54 +162,160 @@ class SessionFilter(SessionFilterOne):
def __getitem__(self, item: int) -> SessionElement: ... def __getitem__(self, item: int) -> SessionElement: ...
@property @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, def _get_attr(self,
name: str, name: str,
value: str, value: str,
method: str, method: str,
equal: bool = True) -> SessionFilter: ... equal: bool = True) -> SessionFilter:
"""返回通过某个方法可获得某个值的元素
:param name: 属性名称
:param value: 属性值
:param method: 方法名称
:return: 筛选结果
"""
...
class ChromiumFilterOne(SessionFilterOne): class ChromiumFilterOne(SessionFilterOne):
_list: ChromiumElementsList = ... _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, def property(self,
name: str, 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, def _get_attr(self,
name: str, name: str,
value: 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): class ChromiumFilter(ChromiumFilterOne):
@ -163,38 +329,80 @@ class ChromiumFilter(ChromiumFilterOne):
def __getitem__(self, item: int) -> ChromiumElement: ... def __getitem__(self, item: int) -> ChromiumElement: ...
@property @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, def property(self,
name: str, 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 attr(self, name: str, value: str, equal: bool = True) -> ChromiumFilter:
"""以是否拥有某个attribute值为条件筛选元素
def text(self, text: str, fuzzy: bool = True, contain: bool = True) -> ChromiumFilter: ... :param name: 属性名称
:param value: 属性值
def search(self, :param equal: True表示匹配name值为value值的元素False表示匹配name值不为value值的
displayed: Optional[bool] = None, :return: 筛选结果
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 search_one(self, def search_one(self,
index: int = 1, index: int = 1,
@ -204,23 +412,118 @@ class ChromiumFilter(ChromiumFilterOne):
enabled: Optional[bool] = None, enabled: Optional[bool] = None,
clickable: Optional[bool] = None, clickable: Optional[bool] = None,
have_rect: 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, def _get_attr(self,
name: str, name: str,
value: 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): class Getter(object):
_list: SessionElementsList = ... _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: class Actions:
"""用于实现动作链的类"""
def __init__(self, owner): def __init__(self, owner):
"""
:param owner: ChromiumBase对象
"""
self.owner = owner self.owner = owner
self._dr = owner.driver self._dr = owner.driver
self.modifier = 0 # 修饰符Alt=1, Ctrl=2, Meta/Command=4, Shift=8 self.modifier = 0 # 修饰符Alt=1, Ctrl=2, Meta/Command=4, Shift=8
@ -26,14 +22,6 @@ class Actions:
self._holding = 'left' self._holding = 'left'
def move_to(self, ele_or_loc, offset_x=None, offset_y=None, duration=.5): 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 is_loc = False
mid_point = offset_x == offset_y is None mid_point = offset_x == offset_y is None
if offset_x is None: if offset_x is None:
@ -73,12 +61,6 @@ class Actions:
return self return self
def move(self, offset_x=0, offset_y=0, duration=.5): 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 duration = .02 if duration < .02 else duration
num = int(duration * 50) num = int(duration * 50)
@ -99,93 +81,48 @@ class Actions:
return self return self
def click(self, on_ele=None, times=1): 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') self._hold(on_ele, 'left', times).wait(.05)._release('left')
return self return self
def r_click(self, on_ele=None, times=1): 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') self._hold(on_ele, 'right', times).wait(.05)._release('right')
return self return self
def m_click(self, on_ele=None, times=1): 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') self._hold(on_ele, 'middle', times).wait(.05)._release('middle')
return self return self
def hold(self, on_ele=None): def hold(self, on_ele=None):
"""按住鼠标左键,可先移动到元素上
:param on_ele: ChromiumElement元素或文本定位符
:return: self
"""
self._hold(on_ele, 'left') self._hold(on_ele, 'left')
return self return self
def release(self, on_ele=None): def release(self, on_ele=None):
"""释放鼠标左键,可先移动到元素上
:param on_ele: ChromiumElement元素或文本定位符
:return: self
"""
if on_ele: if on_ele:
self.move_to(on_ele, duration=.2) self.move_to(on_ele, duration=.2)
self._release('left') self._release('left')
return self return self
def r_hold(self, on_ele=None): def r_hold(self, on_ele=None):
"""按住鼠标右键,可先移动到元素上
:param on_ele: ChromiumElement元素或文本定位符
:return: self
"""
self._hold(on_ele, 'right') self._hold(on_ele, 'right')
return self return self
def r_release(self, on_ele=None): def r_release(self, on_ele=None):
"""释放鼠标右键,可先移动到元素上
:param on_ele: ChromiumElement元素或文本定位符
:return: self
"""
if on_ele: if on_ele:
self.move_to(on_ele, duration=.2) self.move_to(on_ele, duration=.2)
self._release('right') self._release('right')
return self return self
def m_hold(self, on_ele=None): def m_hold(self, on_ele=None):
"""按住鼠标中键,可先移动到元素上
:param on_ele: ChromiumElement元素或文本定位符
:return: self
"""
self._hold(on_ele, 'middle') self._hold(on_ele, 'middle')
return self return self
def m_release(self, on_ele=None): def m_release(self, on_ele=None):
"""释放鼠标中键,可先移动到元素上
:param on_ele: ChromiumElement元素或文本定位符
:return: self
"""
if on_ele: if on_ele:
self.move_to(on_ele, duration=.2) self.move_to(on_ele, duration=.2)
self._release('middle') self._release('middle')
return self return self
def _hold(self, on_ele=None, button='left', count=1): def _hold(self, on_ele=None, button='left', count=1):
"""按下鼠标按键
:param on_ele: ChromiumElement元素或文本定位符
:param button: 要按下的按键
:param count: 点击次数
:return: self
"""
if on_ele: if on_ele:
self.move_to(on_ele, duration=.2) self.move_to(on_ele, duration=.2)
self._dr.run('Input.dispatchMouseEvent', type='mousePressed', button=button, clickCount=count, self._dr.run('Input.dispatchMouseEvent', type='mousePressed', button=button, clickCount=count,
@ -194,22 +131,12 @@ class Actions:
return self return self
def _release(self, button): def _release(self, button):
"""释放鼠标按键
:param button: 要释放的按键
:return: self
"""
self._dr.run('Input.dispatchMouseEvent', type='mouseReleased', button=button, clickCount=1, self._dr.run('Input.dispatchMouseEvent', type='mouseReleased', button=button, clickCount=1,
x=self.curr_x, y=self.curr_y, modifiers=self.modifier) x=self.curr_x, y=self.curr_y, modifiers=self.modifier)
self._holding = 'left' self._holding = 'left'
return self return self
def scroll(self, delta_y=0, delta_x=0, on_ele=None): 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: if on_ele:
self.move_to(on_ele, duration=.2) self.move_to(on_ele, duration=.2)
self._dr.run('Input.dispatchMouseEvent', type='mouseWheel', x=self.curr_x, y=self.curr_y, self._dr.run('Input.dispatchMouseEvent', type='mouseWheel', x=self.curr_x, y=self.curr_y,
@ -217,38 +144,18 @@ class Actions:
return self return self
def up(self, pixel): def up(self, pixel):
"""鼠标向上移动若干像素
:param pixel: 鼠标移动的像素值
:return: self
"""
return self.move(0, -pixel) return self.move(0, -pixel)
def down(self, pixel): def down(self, pixel):
"""鼠标向下移动若干像素
:param pixel: 鼠标移动的像素值
:return: self
"""
return self.move(0, pixel) return self.move(0, pixel)
def left(self, pixel): def left(self, pixel):
"""鼠标向左移动若干像素
:param pixel: 鼠标移动的像素值
:return: self
"""
return self.move(-pixel, 0) return self.move(-pixel, 0)
def right(self, pixel): def right(self, pixel):
"""鼠标向右移动若干像素
:param pixel: 鼠标移动的像素值
:return: self
"""
return self.move(pixel, 0) return self.move(pixel, 0)
def key_down(self, key): def key_down(self, key):
"""按下键盘上的按键,
:param key: 使用Keys获取的按键'DEL'形式按键名称
:return: self
"""
key = getattr(Keys, key.upper(), key) key = getattr(Keys, key.upper(), key)
if key in ('\ue009', '\ue008', '\ue00a', '\ue03d'): # 如果上修饰符,添加到变量 if key in ('\ue009', '\ue008', '\ue00a', '\ue03d'): # 如果上修饰符,添加到变量
self.modifier |= modifierBit.get(key, 0) self.modifier |= modifierBit.get(key, 0)
@ -261,10 +168,6 @@ class Actions:
return self return self
def key_up(self, key): def key_up(self, key):
"""提起键盘上的按键
:param key: 按键特殊字符见Keys
:return: self
"""
key = getattr(Keys, key.upper(), key) key = getattr(Keys, key.upper(), key)
if key in ('\ue009', '\ue008', '\ue00a', '\ue03d'): # 如果上修饰符,添加到变量 if key in ('\ue009', '\ue008', '\ue00a', '\ue03d'): # 如果上修饰符,添加到变量
self.modifier ^= modifierBit.get(key, 0) self.modifier ^= modifierBit.get(key, 0)
@ -277,10 +180,6 @@ class Actions:
return self return self
def type(self, keys): def type(self, keys):
"""用模拟键盘按键方式输入文本,可输入字符串,也可输入组合键
:param keys: 要按下的按键特殊字符和多个文本可用list或tuple传入
:return: self
"""
modifiers = [] modifiers = []
if not isinstance(keys, (str, tuple, list)): if not isinstance(keys, (str, tuple, list)):
keys = str(keys) keys = str(keys)
@ -304,25 +203,15 @@ class Actions:
return self return self
def input(self, text): def input(self, text):
"""输入文本也可输入组合键组合键用tuple形式输入
:param text: 文本值或按键组合
:return: self
"""
input_text_or_keys(self.owner, text) input_text_or_keys(self.owner, text)
return self return self
def wait(self, second, scope=None): def wait(self, second, scope=None):
"""等待若干秒,如传入两个参数,等待时间为这两个数间的一个随机数
:param second: 秒数
:param scope: 随机数范围
:return: None
"""
self.owner.wait(second=second, scope=scope) self.owner.wait(second=second, scope=scope)
return self return self
def location_to_client(page, lx, ly): def location_to_client(page, lx, ly):
"""绝对坐标转换为视口坐标"""
scroll_x = page._run_js('return document.documentElement.scrollLeft;') scroll_x = page._run_js('return document.documentElement.scrollLeft;')
scroll_y = page._run_js('return document.documentElement.scrollTop;') scroll_y = page._run_js('return document.documentElement.scrollTop;')
return lx - scroll_x, ly - scroll_y return lx - scroll_x, ly - scroll_y

View File

@ -43,63 +43,207 @@ KEYS = Literal['NULL', 'CANCEL', 'HELP', 'BACKSPACE', 'meta',
class Actions: class Actions:
"""用于实现动作链的类"""
owner: ChromiumBase = ...
_dr: Driver = ...
modifier: int = ...
curr_x: float = ...
curr_y: float = ...
_holding: str = ...
def __init__(self, owner: ChromiumBase): def __init__(self, owner: ChromiumBase):
self.owner: ChromiumBase = ... """
self._dr: Driver = ... :param owner: ChromiumBase对象
self.modifier: int = ... """
self.curr_x: int = ... ...
self.curr_y: int = ...
self._holding: str = ...
def move_to(self, ele_or_loc: Union[ChromiumElement, Tuple[float, float], str], 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', def _hold(self,
count: int = 1) -> Actions: ... 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, 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 @property
def set_mode(self): def set_mode(self):
"""返回用于设置录屏幕式的对象"""
return ScreencastMode(self) return ScreencastMode(self)
def start(self, save_path=None): def start(self, save_path=None):
"""开始录屏
:param save_path: 录屏保存位置
:return: None
"""
self.set_save_path(save_path) self.set_save_path(save_path)
if self._path is None: if self._path is None:
raise ValueError('save_path必须设置。') raise ValueError('save_path必须设置。')
@ -83,10 +78,6 @@ class Screencast(object):
self._owner._run_js(js) self._owner._run_js(js)
def stop(self, video_name=None): def stop(self, video_name=None):
"""停止录屏
:param video_name: 视频文件名为None时以当前时间名命
:return: 文件路径
"""
if video_name and not video_name.endswith('mp4'): if video_name and not video_name.endswith('mp4'):
video_name = f'{video_name}.mp4' video_name = f'{video_name}.mp4'
name = f'{time()}.mp4' if not video_name else video_name name = f'{time()}.mp4' if not video_name else video_name
@ -128,7 +119,7 @@ class Screencast(object):
imgInfo = img.shape imgInfo = img.shape
size = (imgInfo[1], imgInfo[0]) 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: for i in pic_list:
img = imread(str(i)) img = imread(str(i))
@ -139,10 +130,6 @@ class Screencast(object):
return f'{self._path}{sep}{name}' return f'{self._path}{sep}{name}'
def set_save_path(self, save_path=None): def set_save_path(self, save_path=None):
"""设置保存路径
:param save_path: 保存路径
:return: None
"""
if save_path: if save_path:
save_path = Path(save_path) save_path = Path(save_path)
if save_path.exists() and save_path.is_file(): if save_path.exists() and save_path.is_file():
@ -151,7 +138,6 @@ class Screencast(object):
self._path = save_path self._path = save_path
def _run(self): def _run(self):
"""非节俭模式运行方法"""
self._running = True self._running = True
path = self._tmp_path or self._path path = self._tmp_path or self._path
while self._enable: while self._enable:
@ -160,7 +146,6 @@ class Screencast(object):
self._running = False self._running = False
def _onScreencastFrame(self, **kwargs): def _onScreencastFrame(self, **kwargs):
"""节俭模式运行方法"""
path = self._tmp_path or self._path path = self._tmp_path or self._path
with open(f'{path}{sep}{kwargs["metadata"]["timestamp"]}.jpg', 'wb') as f: with open(f'{path}{sep}{kwargs["metadata"]["timestamp"]}.jpg', 'wb') as f:
f.write(b64decode(kwargs['data'])) f.write(b64decode(kwargs['data']))
@ -172,21 +157,16 @@ class ScreencastMode(object):
self._screencast = screencast self._screencast = screencast
def video_mode(self): def video_mode(self):
"""持续视频模式,生成的视频没有声音"""
self._screencast._mode = 'video' self._screencast._mode = 'video'
def frugal_video_mode(self): def frugal_video_mode(self):
"""设置节俭视频模式,页面有变化时才录制,生成的视频没有声音"""
self._screencast._mode = 'frugal_video' self._screencast._mode = 'frugal_video'
def js_video_mode(self): def js_video_mode(self):
"""设置使用js录制视频模式可生成有声音的视频但需要手动启动"""
self._screencast._mode = 'js_video' self._screencast._mode = 'js_video'
def frugal_imgs_mode(self): def frugal_imgs_mode(self):
"""设置节俭视频模式,页面有变化时才截图"""
self._screencast._mode = 'frugal_imgs' self._screencast._mode = 'frugal_imgs'
def imgs_mode(self): def imgs_mode(self):
"""设置图片模式,持续对页面进行截图"""
self._screencast._mode = 'imgs' self._screencast._mode = 'imgs'

View File

@ -6,44 +6,84 @@
@License : BSD 3-Clause. @License : BSD 3-Clause.
""" """
from pathlib import Path from pathlib import Path
from typing import Union from typing import Union, Optional
from .._pages.chromium_base import ChromiumBase from .._pages.chromium_base import ChromiumBase
class Screencast(object): class Screencast(object):
_owner: ChromiumBase = ...
_path: Optional[Path] = ...
_tmp_path: Optional[Path] = ...
_running: bool = ...
_enable: bool = ...
_mode: str = ...
def __init__(self, owner: ChromiumBase): def __init__(self, owner: ChromiumBase):
self._owner: ChromiumBase = ... """
self._path: Path = ... :param owner: 页面对象
self._tmp_path: Path = ... """
self._running: bool = ...
self._enable: bool = ...
self._mode: str = ...
@property @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): class ScreencastMode(object):
_screencast: Screencast = ...
def __init__(self, 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 @property
def is_displayed(self): def is_displayed(self):
return not (self._ele.style('visibility') == 'hidden' or return not (self._ele.style('visibility') == 'hidden'
self._ele._run_js('return this.offsetParent === null;') or self._ele.style('display') == 'none'
or self._ele.style('display') == 'none' or self._ele.property('hidden')) or self._ele.property('hidden'))
@property @property
def is_enabled(self): def is_enabled(self):