继续修改备注

This commit is contained in:
g1879 2024-08-15 14:39:16 +08:00
parent a484aa0c45
commit 8a6e225e02
25 changed files with 2519 additions and 1859 deletions

View File

@ -981,7 +981,7 @@ def find_by_xpath(ele, xpath, index, timeout, relative=True):
res = ele.owner._run_cdp('Runtime.getProperties', objectId=res['result']['objectId'],
ownProperties=True)['result'][:-1]
if index is None:
r = ChromiumElementsList(page=ele.owner)
r = ChromiumElementsList(owner=ele.owner)
for i in res:
if i['value']['type'] == 'object':
r.append(make_chromium_eles(ele.owner, _ids=i['value']['objectId'], is_obj_id=True))
@ -1010,7 +1010,7 @@ def find_by_xpath(ele, xpath, index, timeout, relative=True):
if result:
return result
return NoneElement(ele.owner) if index is not None else ChromiumElementsList(page=ele.owner)
return NoneElement(ele.owner) if index is not None else ChromiumElementsList(owner=ele.owner)
def find_by_css(ele, selector, index, timeout):
@ -1049,7 +1049,7 @@ def find_by_css(ele, selector, index, timeout):
if result:
return result
return NoneElement(ele.owner) if index is not None else ChromiumElementsList(page=ele.owner)
return NoneElement(ele.owner) if index is not None else ChromiumElementsList(owner=ele.owner)
def make_chromium_eles(page, _ids, index=1, is_obj_id=True, ele_only=False):
@ -1073,7 +1073,7 @@ def make_chromium_eles(page, _ids, index=1, is_obj_id=True, ele_only=False):
return get_node_func(page, obj_id, ele_only)
else: # 获取全部
nodes = ChromiumElementsList(page=page)
nodes = ChromiumElementsList(owner=page)
for obj_id in _ids:
# if obj_id == 0:
# continue

View File

@ -266,7 +266,7 @@ def make_session_ele(html_or_ele, loc=None, index=1, method=None):
# 把lxml元素对象包装成SessionElement对象并按需要返回一个或全部
if index is None:
r = SessionElementsList(page=page)
r = SessionElementsList(owner=page)
for e in eles:
if e != '\n':
r.append(SessionElement(e, page) if isinstance(e, HtmlElement) else e)

View File

@ -42,10 +42,6 @@ class ChromiumBase(BasePage):
"""标签页、Frame、Page基类"""
def __init__(self, browser, target_id=None):
"""
:param browser: Chromium
:param target_id: 要控制的target id不指定默认为激活的标签页
"""
super().__init__()
self._browser = browser
self._is_loading = None
@ -72,14 +68,13 @@ class ChromiumBase(BasePage):
self._d_set_runtime_settings()
self._connect_browser(target_id)
def __call__(self, locator, index=1, timeout=None):
return self.ele(locator, index, timeout)
def _d_set_runtime_settings(self):
pass
def _connect_browser(self, target_id=None):
"""连接浏览器,在第一次时运行
:param target_id: 要控制的target id不指定默认为激活的标签页
:return: None
"""
self._is_reading = False
if not target_id:
@ -109,10 +104,6 @@ class ChromiumBase(BasePage):
self._ready_state = 'complete'
def _driver_init(self, target_id):
"""新建页面、页面刷新后要进行的cdp参数初始化
:param target_id: 要跳转到的target id
:return: None
"""
self._is_loading = True
self._driver = self.browser._get_driver(target_id, self)
@ -139,10 +130,6 @@ class ChromiumBase(BasePage):
self._driver.set_callback('Page.frameDetached', self._onFrameDetached)
def _get_document(self, timeout=10):
"""获取页面文档
:param timeout: 超时时间
:return: 是否获取成功
"""
if self._is_reading:
return
self._is_reading = True
@ -185,7 +172,6 @@ class ChromiumBase(BasePage):
self.browser._frames[kwargs['frameId']] = self.tab_id
def _onFrameStartedLoading(self, **kwargs):
"""页面开始加载时执行"""
self.browser._frames[kwargs['frameId']] = self.tab_id
if kwargs['frameId'] == self._frame_id:
self._doc_got = False
@ -198,14 +184,12 @@ class ChromiumBase(BasePage):
t.start()
def _onFrameNavigated(self, **kwargs):
"""页面跳转时执行"""
if kwargs['frame']['id'] == self._frame_id:
self._doc_got = False
self._ready_state = 'loading'
self._is_loading = True
def _onDomContentEventFired(self, **kwargs):
"""在页面刷新、变化后重新读取页面内容"""
if self._load_mode == 'eager':
self._run_cdp('Page.stopLoading')
if self._get_document(self._load_end_time - perf_counter() - .1):
@ -213,13 +197,11 @@ class ChromiumBase(BasePage):
self._ready_state = 'interactive'
def _onLoadEventFired(self, **kwargs):
"""在页面刷新、变化后重新读取页面内容"""
if self._doc_got is False and self._get_document(self._load_end_time - perf_counter() - .1):
self._doc_got = True
self._ready_state = 'complete'
def _onFrameStoppedLoading(self, **kwargs):
"""页面加载完成后执行"""
self.browser._frames[kwargs['frameId']] = self.tab_id
if kwargs['frameId'] == self._frame_id:
if self._doc_got is False:
@ -227,7 +209,6 @@ class ChromiumBase(BasePage):
self._ready_state = 'complete'
def _onFileChooserOpened(self, **kwargs):
"""文件选择框打开时执行"""
if self._upload_list:
if 'backendNodeId' not in kwargs:
raise TypeError('该输入框无法接管,请改用对<input>元素输入路径的方法设置。')
@ -238,18 +219,7 @@ class ChromiumBase(BasePage):
self._run_cdp('Page.setInterceptFileChooserDialog', enabled=False)
self._upload_list = None
def __call__(self, locator, index=1, timeout=None):
"""在内部查找元素
ele = page('@id=ele_id')
:param locator: 元素的定位信息可以是loc元组或查询字符串
:param index: 获取第几个元素从1开始可传入负数获取倒数第几个
:param timeout: 超时时间
:return: ChromiumElement对象
"""
return self.ele(locator, index, timeout)
def _wait_to_stop(self):
"""eager策略超时时使页面停止加载"""
end_time = perf_counter() + self.timeouts.page_load
while perf_counter() < end_time:
sleep(.1)
@ -259,28 +229,24 @@ class ChromiumBase(BasePage):
# ----------挂件----------
@property
def wait(self):
"""返回用于等待的对象"""
if self._wait is None:
self._wait = BaseWaiter(self)
return self._wait
@property
def set(self):
"""返回用于设置的对象"""
if self._set is None:
self._set = ChromiumBaseSetter(self)
return self._set
@property
def screencast(self):
"""返回用于录屏的对象"""
if self._screencast is None:
self._screencast = Screencast(self)
return self._screencast
@property
def actions(self):
"""返回用于执行动作链的对象"""
if self._actions is None:
self._actions = Actions(self)
self.wait.doc_loaded()
@ -288,21 +254,18 @@ class ChromiumBase(BasePage):
@property
def listen(self):
"""返回用于聆听数据包的对象"""
if self._listener is None:
self._listener = Listener(self)
return self._listener
@property
def states(self):
"""返回用于获取状态信息的对象"""
if self._states is None:
self._states = PageStates(self)
return self._states
@property
def scroll(self):
"""返回用于滚动滚动条的对象"""
self.wait.doc_loaded()
if self._scroll is None:
self._scroll = PageScroller(self)
@ -310,7 +273,6 @@ class ChromiumBase(BasePage):
@property
def rect(self):
"""返回获取窗口坐标和大小的对象"""
# self.wait.doc_loaded()
if self._rect is None:
self._rect = TabRect(self)
@ -318,19 +280,16 @@ class ChromiumBase(BasePage):
@property
def console(self):
"""返回获取控制台信息的对象"""
if self._console is None:
self._console = Console(self)
return self._console
@property
def timeout(self):
"""返回timeout设置"""
return self._timeouts.base
@property
def timeouts(self):
"""返回timeouts设置"""
return self._timeouts
# ----------挂件结束----------
@ -341,35 +300,29 @@ class ChromiumBase(BasePage):
@property
def driver(self):
"""返回用于控制浏览器的Driver对象"""
if self._driver is None:
raise RuntimeError('浏览器已关闭或链接已断开。')
return self._driver
@property
def title(self):
"""返回当前页面title"""
return self._run_cdp_loaded('Target.getTargetInfo', targetId=self._target_id)['targetInfo']['title']
@property
def url(self):
"""返回当前页面url"""
return self._run_cdp_loaded('Target.getTargetInfo', targetId=self._target_id)['targetInfo']['url']
@property
def _browser_url(self):
"""用于被MixTab覆盖"""
return self.url
@property
def html(self):
"""返回当前页面html文本"""
self.wait.doc_loaded()
return self._run_cdp('DOM.getOuterHTML', objectId=self._root_id)['outerHTML']
@property
def json(self):
"""当返回内容是json格式时返回对应的字典非json格式时返回None"""
try:
return loads(self('t:pre', timeout=.5).text)
except JSONDecodeError:
@ -377,37 +330,30 @@ class ChromiumBase(BasePage):
@property
def tab_id(self):
"""返回当前标签页id"""
return self._target_id
@property
def _target_id(self):
"""返回当前标签页id"""
return self.driver.id if self.driver.is_running else ''
@property
def active_ele(self):
"""返回当前焦点所在元素"""
return self._run_js_loaded('return document.activeElement;')
@property
def load_mode(self):
"""返回页面加载策略有3种'none''normal''eager'"""
return self._load_mode
@property
def user_agent(self):
"""返回user agent"""
return self._run_cdp('Runtime.evaluate', expression='navigator.userAgent;')['result']['value']
@property
def upload_list(self):
"""返回等待上传文件列表"""
return self._upload_list
@property
def _js_ready_state(self):
"""返回js获取的ready state信息"""
try:
return self._run_cdp('Runtime.evaluate', expression='document.readyState;', _timeout=3)['result']['value']
except ContextLostError:
@ -416,114 +362,47 @@ class ChromiumBase(BasePage):
return 'timeout'
def run_cdp(self, cmd, **cmd_args):
"""执行Chrome DevTools Protocol语句
:param cmd: 协议项目
:param cmd_args: 参数
:return: 执行的结果
"""
r = self.driver.run(cmd, **cmd_args)
return r if __ERROR__ not in r else raise_error(r, user=True)
def run_cdp_loaded(self, cmd, **cmd_args):
"""执行Chrome DevTools Protocol语句执行前等待页面加载完毕
:param cmd: 协议项目
:param cmd_args: 参数
:return: 执行的结果
"""
self.wait.doc_loaded()
r = self.driver.run(cmd, **cmd_args)
return r if __ERROR__ not in r else raise_error(r, user=True)
def _run_cdp(self, cmd, **cmd_args):
"""执行Chrome DevTools Protocol语句
:param cmd: 协议项目
:param cmd_args: 参数
:return: 执行的结果
"""
ignore = cmd_args.pop('_ignore', None)
r = self.driver.run(cmd, **cmd_args)
return r if __ERROR__ not in r else raise_error(r, ignore)
def _run_cdp_loaded(self, cmd, **cmd_args):
"""执行Chrome DevTools Protocol语句执行前等待页面加载完毕
:param cmd: 协议项目
:param cmd_args: 参数
:return: 执行的结果
"""
self.wait.doc_loaded()
return self._run_cdp(cmd, **cmd_args)
def run_js(self, script, *args, as_expr=False, timeout=None):
"""运行javascript代码
:param script: js文本或js文件路径
:param args: 参数按顺序在js文本中对应arguments[0]arguments[1]...
:param as_expr: 是否作为表达式运行为True时args无效
:param timeout: js超时时间为None则使用页面timeouts.script设置
:return: 运行的结果
"""
return self._run_js(script, *args, as_expr=as_expr, timeout=timeout)
def run_js_loaded(self, script, *args, as_expr=False, timeout=None):
"""运行javascript代码执行前等待页面加载完毕
:param script: js文本或js文件路径
:param args: 参数按顺序在js文本中对应arguments[0]arguments[1]...
:param as_expr: 是否作为表达式运行为True时args无效
:param timeout: js超时时间为None则使用页面timeouts.script属性值
:return: 运行的结果
"""
self.wait.doc_loaded()
return self._run_js(script, *args, as_expr=as_expr, timeout=timeout)
def _run_js(self, script, *args, as_expr=False, timeout=None):
"""运行javascript代码
:param script: js文本或js文件路径
:param args: 参数按顺序在js文本中对应arguments[0]arguments[1]...
:param as_expr: 是否作为表达式运行为True时args无效
:param timeout: js超时时间为None则使用页面timeouts.script设置
:return: 运行的结果
"""
return run_js(self, script, as_expr, self.timeouts.script if timeout is None else timeout, args)
def _run_js_loaded(self, script, *args, as_expr=False, timeout=None):
"""运行javascript代码执行前等待页面加载完毕
:param script: js文本或js文件路径
:param args: 参数按顺序在js文本中对应arguments[0]arguments[1]...
:param as_expr: 是否作为表达式运行为True时args无效
:param timeout: js超时时间为None则使用页面timeouts.script属性值
:return: 运行的结果
"""
self.wait.doc_loaded()
return run_js(self, script, as_expr, self.timeouts.script if timeout is None else timeout, args)
def run_async_js(self, script, *args, as_expr=False):
"""以异步方式执行js代码或js文件路径
:param script: js文本
:param args: 参数按顺序在js文本中对应arguments[0]arguments[1]...
:param as_expr: 是否作为表达式运行为True时args无效
:return: None
"""
run_js(self, script, as_expr, 0, args)
def get(self, url, show_errmsg=False, retry=None, interval=None, timeout=None):
"""访问url
:param url: 目标url
:param show_errmsg: 是否显示和抛出异常
:param retry: 重试次数为None时使用页面对象retry_times属性值
:param interval: 重试间隔为None时使用页面对象retry_interval属性值
:param timeout: 连接超时时间为None时使用页面对象timeouts.page_load属性值
:return: 目标url是否可用
"""
retry, interval, is_file = self._before_connect(url, retry, interval)
self._url_available = self._d_connect(self._url, times=retry, interval=interval,
show_errmsg=show_errmsg, timeout=timeout)
return self._url_available
def cookies(self, all_domains=False, all_info=False):
"""返回cookies信息
:param all_domains: 是否返回所有域的cookies
:param all_info: 是否返回所有信息为False时只返回namevaluedomain
:return: cookies信息
"""
txt = 'Storage' if all_domains else 'Network'
cookies = self._run_cdp_loaded(f'{txt}.getCookies')['cookies']
@ -535,51 +414,21 @@ class ChromiumBase(BasePage):
return CookiesList(r)
def ele(self, locator, index=1, timeout=None):
"""获取一个符合条件的元素对象
:param locator: 定位符或元素对象
:param index: 获取第几个元素从1开始可传入负数获取倒数第几个
:param timeout: 查找超时时间默认与页面等待时间一致
:return: ChromiumElement对象
"""
return self._ele(locator, timeout=timeout, index=index, method='ele()')
def eles(self, locator, timeout=None):
"""获取所有符合条件的元素对象
:param locator: 定位符或元素对象
:param timeout: 查找超时时间默认与页面等待时间一致
:return: ChromiumElement对象组成的列表
"""
return self._ele(locator, timeout=timeout, index=None)
def s_ele(self, locator=None, index=1, timeout=None):
"""查找一个符合条件的元素以SessionElement形式返回处理复杂页面时效率很高
:param locator: 元素的定位信息可以是loc元组或查询字符串
:param index: 获取第几个从1开始可传入负数获取倒数第几个
:param timeout: 查找元素超时时间默认与页面等待时间一致
:return: SessionElement对象或属性文本
"""
return (NoneElement(self, method='s_ele()', args={'locator': locator, 'index': index})
if locator and not self.wait.eles_loaded(locator, timeout=timeout)
else make_session_ele(self, locator, index=index, method='s_ele()'))
def s_eles(self, locator, timeout=None):
"""查找所有符合条件的元素以SessionElement列表形式返回
:param locator: 元素的定位信息可以是loc元组或查询字符串
:param timeout: 查找元素超时时间默认与页面等待时间一致
:return: SessionElement对象组成的列表
"""
return (make_session_ele(self, locator, index=None)
if self.wait.eles_loaded(locator, timeout=timeout) else SessionElementsList())
def _find_elements(self, locator, timeout=None, index=1, relative=False, raise_err=None):
"""执行元素查找
:param locator: 定位符或元素对象
:param timeout: 查找超时时间
:param index: 第几个结果从1开始可传入负数获取倒数第几个为None返回所有
:param relative: MixTab用的表示是否相对定位的参数
:param raise_err: 找不到元素是是否抛出异常为None时根据全局设置
:return: ChromiumElement对象或元素对象组成的列表
"""
if isinstance(locator, (str, tuple)):
loc = get_loc(locator)[1]
elif locator._type in ('ChromiumElement', 'ChromiumFrame'):
@ -645,33 +494,17 @@ class ChromiumBase(BasePage):
return r
def refresh(self, ignore_cache=False):
"""刷新当前页面
:param ignore_cache: 是否忽略缓存
:return: None
"""
self._is_loading = True
self._run_cdp('Page.reload', ignoreCache=ignore_cache)
self.wait.load_start()
def forward(self, steps=1):
"""在浏览历史中前进若干步
:param steps: 前进步数
:return: None
"""
self._forward_or_back(steps)
def back(self, steps=1):
"""在浏览历史中后退若干步
:param steps: 后退步数
:return: None
"""
self._forward_or_back(-steps)
def _forward_or_back(self, steps):
"""执行浏览器前进或后退会跳过url相同的历史记录
:param steps: 步数
:return: None
"""
if steps == 0:
return
@ -694,7 +527,6 @@ class ChromiumBase(BasePage):
self._run_cdp('Page.navigateToHistoryEntry', entryId=nid)
def stop_loading(self):
"""页面停止加载"""
try:
self._run_cdp('Page.stopLoading')
end_time = perf_counter() + 5
@ -706,10 +538,6 @@ class ChromiumBase(BasePage):
self._ready_state = 'complete'
def remove_ele(self, loc_or_ele):
"""从页面上删除一个元素
:param loc_or_ele: 元素对象或定位符
:return: None
"""
if not loc_or_ele:
return
ele = self._ele(loc_or_ele, raise_err=False)
@ -717,12 +545,6 @@ class ChromiumBase(BasePage):
self._run_cdp('DOM.removeNode', nodeId=ele._node_id, _ignore=ElementLostError)
def add_ele(self, html_or_info, insert_to=None, before=None):
"""新建一个元素
:param html_or_info: 新元素的html文本或信息信息格式为(tag, {attr1: value, ...})
:param insert_to: 插入到哪个元素中可接收元素对象和定位符为None且为html添加到body不为html不插入
:param before: 在哪个子节点前面插入可接收对象和定位符为None插入到父元素末尾
:return: 元素对象
"""
if isinstance(html_or_info, str):
insert_to = self.ele(insert_to) if insert_to else self.ele('t:body')
args = [html_or_info, insert_to]
@ -774,69 +596,33 @@ class ChromiumBase(BasePage):
return ele
def get_frame(self, loc_ind_ele, timeout=None):
"""获取页面中一个frame对象
:param loc_ind_ele: 定位符iframe序号ChromiumFrame对象序号从1开始可传入负数获取倒数第几个
:param timeout: 查找元素超时时间
:return: ChromiumFrame对象
"""
return get_frame(self, loc_ind_ele=loc_ind_ele, timeout=timeout)
def get_frames(self, locator=None, timeout=None):
"""获取所有符合条件的frame对象
:param locator: 定位符为None时返回所有
:param timeout: 查找超时时间
:return: ChromiumFrame对象组成的列表
"""
locator = locator or 'xpath://*[name()="iframe" or name()="frame"]'
frames = self._ele(locator, timeout=timeout, index=None, raise_err=False)
return [i for i in frames if i._type == 'ChromiumFrame']
def session_storage(self, item=None):
"""返回sessionStorage信息不设置item则获取全部
:param item: 要获取的项不设置则返回全部
:return: sessionStorage一个或所有项内容
"""
js = f'sessionStorage.getItem("{item}")' if item else 'sessionStorage'
return self._run_js_loaded(js, as_expr=True)
def local_storage(self, item=None):
"""返回localStorage信息不设置item则获取全部
:param item: 要获取的项目不设置则返回全部
:return: localStorage一个或所有项内容
"""
js = f'localStorage.getItem("{item}")' if item else 'localStorage'
return self._run_js_loaded(js, as_expr=True)
def get_screenshot(self, path=None, name=None, as_bytes=None, as_base64=None,
full_page=False, left_top=None, right_bottom=None):
"""对页面进行截图可对整个网页、可见网页、指定范围截图。对可视范围外截图需要90以上版本浏览器支持
:param path: 保存路径
:param name: 完整文件名后缀可选 'jpg','jpeg','png','webp'
:param as_bytes: 是否以字节形式返回图片可选 'jpg','jpeg','png','webp'生效时path参数和as_base64参数无效
:param as_base64: 是否以base64字符串形式返回图片可选 'jpg','jpeg','png','webp'生效时path参数无效
:param full_page: 是否整页截图为True截取整个网页为False截取可视窗口
:param left_top: 截取范围左上角坐标
:param right_bottom: 截取范围右下角角坐标
:return: 图片完整路径或字节文本
"""
return self._get_screenshot(path=path, name=name, as_bytes=as_bytes, as_base64=as_base64,
full_page=full_page, left_top=left_top, right_bottom=right_bottom)
def add_init_js(self, script):
"""添加初始化脚本,在页面加载任何脚本前执行
:param script: js文本
:return: 添加的脚本的id
"""
js_id = self._run_cdp('Page.addScriptToEvaluateOnNewDocument', source=script,
includeCommandLineAPI=True)['identifier']
self._init_jss.append(js_id)
return js_id
def remove_init_js(self, script_id=None):
"""删除初始化脚本js_id传入None时删除所有
:param script_id: 脚本的id
:return: None
"""
if script_id is None:
for js_id in self._init_jss:
self._run_cdp('Page.removeScriptToEvaluateOnNewDocument', identifier=js_id)
@ -847,13 +633,6 @@ class ChromiumBase(BasePage):
self._init_jss.remove(script_id)
def clear_cache(self, session_storage=True, local_storage=True, cache=True, cookies=True):
"""清除缓存,可选要清除的项
:param session_storage: 是否清除sessionStorage
:param local_storage: 是否清除localStorage
:param cache: 是否清除cache
:param cookies: 是否清除cookies
:return: None
"""
if session_storage or local_storage:
self._run_cdp_loaded('DOMStorage.enable')
i = self._run_cdp('Storage.getStorageKeyForFrame', frameId=self._frame_id)['storageKey']
@ -870,16 +649,11 @@ class ChromiumBase(BasePage):
self._run_cdp_loaded('Network.clearBrowserCookies')
def disconnect(self):
"""断开与页面的连接,不关闭页面"""
if self._driver:
self._driver.stop()
self.browser._all_drivers.get(self._driver.id, set()).discard(self._driver)
def reconnect(self, wait=0):
"""断开与页面原来的页面,重新建立连接
:param wait: 断开后等待若干秒再连接
:return: None
"""
t_id = self._target_id
self.disconnect()
sleep(wait)
@ -889,13 +663,6 @@ class ChromiumBase(BasePage):
self._get_document()
def handle_alert(self, accept=True, send=None, timeout=None, next_one=False):
"""处理提示框,可以自动等待提示框出现
:param accept: True表示确认False表示取消为None不会按按钮但依然返回文本值
:param send: 处理prompt提示框时可输入文本
:param timeout: 等待提示框出现的超时时间为None则使用self.timeout属性的值
:param next_one: 是否处理下一个出现的提示框为True时timeout参数无效
:return: 提示框内容文本未等到提示框则返回False
"""
r = self._handle_alert(accept=accept, send=send, timeout=timeout, next_one=next_one)
if not isinstance(accept, bool):
return r
@ -904,13 +671,6 @@ class ChromiumBase(BasePage):
return r
def _handle_alert(self, accept=True, send=None, timeout=None, next_one=False):
"""处理提示框,可以自动等待提示框出现
:param accept: True表示确认False表示取消其它值不会按按钮但依然返回文本值
:param send: 处理prompt提示框时可输入文本
:param timeout: 等待提示框出现的超时时间为None则使用self.timeout属性的值
:param next_one: 是否处理下一个出现的提示框为True时timeout参数无效
:return: 提示框内容文本未等到提示框则返回False
"""
if next_one:
self._alert.handle_next = accept
self._alert.next_text = send
@ -934,7 +694,6 @@ class ChromiumBase(BasePage):
return res_text
def _on_alert_open(self, **kwargs):
"""alert出现时触发的方法"""
self._alert.activated = True
self._alert.text = kwargs['message']
self._alert.type = kwargs['type']
@ -952,7 +711,6 @@ class ChromiumBase(BasePage):
self._alert.handle_next = None
def _on_alert_close(self, **kwargs):
"""alert关闭时触发的方法"""
self._alert.activated = False
self._alert.text = None
self._alert.type = None
@ -962,10 +720,6 @@ class ChromiumBase(BasePage):
self._has_alert = False
def _wait_loaded(self, timeout=None):
"""等待页面加载完成,超时触发停止加载
:param timeout: 超时时间
:return: 是否成功超时返回False
"""
timeout = timeout if timeout is not None else self.timeouts.page_load
end_time = perf_counter() + timeout
while perf_counter() < end_time:
@ -984,14 +738,6 @@ class ChromiumBase(BasePage):
return False
def _d_connect(self, to_url, times=0, interval=1, show_errmsg=False, timeout=None):
"""尝试连接,重试若干次
:param to_url: 要访问的url
:param times: 重试次数
:param interval: 重试间隔
:param show_errmsg: 是否抛出异常
:param timeout: 连接超时时间
:return: 是否成功返回None表示不确定
"""
err = None
self._is_loading = True
timeout = timeout if timeout is not None else self.timeouts.page_load
@ -1041,17 +787,6 @@ class ChromiumBase(BasePage):
def _get_screenshot(self, path=None, name=None, as_bytes=None, as_base64=None,
full_page=False, left_top=None, right_bottom=None, ele=None):
"""对页面进行截图可对整个网页、可见网页、指定范围截图。对可视范围外截图需要90以上版本浏览器支持
:param path: 保存路径
:param name: 完整文件名后缀可选 'jpg','jpeg','png','webp'
:param as_bytes: 是否以字节形式返回图片可选 'jpg','jpeg','png','webp'生效时path参数和as_base64参数无效
:param as_base64: 是否以base64字符串形式返回图片可选 'jpg','jpeg','png','webp'生效时path参数无效
:param full_page: 是否整页截图为True截取整个网页为False截取可视窗口
:param left_top: 截取范围左上角坐标
:param right_bottom: 截取范围右下角角坐标
:param ele: 为异域iframe内元素截图设置
:return: 图片完整路径或字节文本
"""
if as_bytes:
if as_bytes is True:
pic_type = 'png'
@ -1132,11 +867,6 @@ class Timeout(object):
"""用于保存d模式timeout信息的类"""
def __init__(self, base=None, page_load=None, script=None):
"""
:param base: 默认超时时间
:param page_load: 页面加载超时时间
:param script: js超时时间
"""
self.base = 10 if base is None else base
self.page_load = 30 if page_load is None else page_load
self.script = 30 if script is None else script

View File

@ -17,7 +17,6 @@ from .._elements.session_element import SessionElement
from .._functions.cookies import CookiesList
from .._functions.elements import SessionElementsList, ChromiumElementsList
from .._pages.chromium_frame import ChromiumFrame
from .._pages.chromium_page import ChromiumPage
from .._units.actions import Actions
from .._units.console import Console
from .._units.listener import Listener
@ -32,287 +31,624 @@ PIC_TYPE = Literal['jpg', 'jpeg', 'png', 'webp', True]
class ChromiumBase(BasePage):
_tab: Union[ChromiumTab, MixTab, ChromiumFrame] = ...
_browser: Chromium = ...
_driver: Optional[Driver] = ...
_frame_id: str = ...
_is_reading: bool = ...
_is_timeout: bool = ...
_timeouts: Timeout = ...
_first_run: bool = ...
_is_loading: Optional[bool] = ...
_load_mode: str = ...
_scroll: Optional[Scroller] = ...
_url: str = ...
_root_id: Optional[str] = ...
_upload_list: Optional[list] = ...
_wait: Optional[BaseWaiter] = ...
_set: Optional[ChromiumBaseSetter] = ...
_screencast: Optional[Screencast] = ...
_actions: Optional[Actions] = ...
_listener: Optional[Listener] = ...
_states: Optional[PageStates] = ...
_alert: Alert = ...
_has_alert: bool = ...
_doc_got: bool = ...
_load_end_time: float = ...
_init_jss: list = ...
_ready_state: Optional[str] = ...
_rect: Optional[TabRect] = ...
_console: Optional[Console] = ...
_type: str = ...
def __init__(self,
browser: Chromium,
tab_id: str = None):
self._tab: Union[ChromiumTab, MixTab, ChromiumFrame] = ...
self._browser: Chromium = ...
self._driver: Driver = ...
self._frame_id: str = ...
self._is_reading: bool = ...
self._is_timeout: bool = ...
self._timeouts: Timeout = ...
self._first_run: bool = ...
self._is_loading: bool = ...
self._load_mode: str = ...
self._scroll: Scroller = ...
self._url: str = ...
self._root_id: str = ...
self._upload_list: list = ...
self._wait: BaseWaiter = ...
self._set: ChromiumBaseSetter = ...
self._screencast: Screencast = ...
self._actions: Actions = ...
self._listener: Listener = ...
self._states: PageStates = ...
self._alert: Alert = ...
self._has_alert: bool = ...
self._doc_got: bool = ...
self._load_end_time: float = ...
self._init_jss: list = ...
self._ready_state: Optional[str] = ...
self._rect: TabRect = ...
self._console: Console = ...
self._type: str = ...
"""
:param browser: Chromium
:param target_id: 要控制的target id不指定默认为激活的标签页
"""
...
def _connect_browser(self, target_id: str = None) -> None: ...
def __call__(self,
locator: Union[Tuple[str, str], str, ChromiumElement],
index: int = 1,
timeout: float = None) -> ChromiumElement:
"""在内部查找元素
ele = page('@id=ele_id')
:param locator: 元素的定位信息可以是loc元组或查询字符串
:param index: 获取第几个元素从1开始可传入负数获取倒数第几个
:param timeout: 超时时间
:return: ChromiumElement对象
"""
...
def _driver_init(self, target_id: str) -> None: ...
def _d_set_runtime_settings(self) -> None: ...
def _get_document(self, timeout: float = 10) -> bool: ...
def _connect_browser(self, target_id: str = None) -> None:
"""连接浏览器,在第一次时运行
:param target_id: 要控制的target id不指定默认为激活的标签页
:return: None
"""
...
def _wait_loaded(self, timeout: float = None) -> bool: ...
def _driver_init(self, target_id: str) -> None:
"""新建页面、页面刷新后要进行的cdp参数初始化
:param target_id: 要跳转到的target id
:return: None
"""
...
def _get_document(self, timeout: float = 10) -> bool:
"""获取页面文档
:param timeout: 超时时间
:return: 是否获取成功
"""
...
def _onFrameDetached(self, **kwargs) -> None: ...
def _onFrameAttached(self, **kwargs) -> None: ...
def _onFrameStartedLoading(self, **kwargs): ...
def _onFrameStartedLoading(self, **kwargs):
"""页面开始加载时执行"""
...
def _onFrameNavigated(self, **kwargs): ...
def _onFrameNavigated(self, **kwargs):
"""页面跳转时执行"""
...
def _onDomContentEventFired(self, **kwargs): ...
def _onDomContentEventFired(self, **kwargs):
"""在页面刷新、变化后重新读取页面内容"""
...
def _onLoadEventFired(self, **kwargs): ...
def _onLoadEventFired(self, **kwargs):
"""在页面刷新、变化后重新读取页面内容"""
...
def _onFrameStoppedLoading(self, **kwargs): ...
def _onFrameStoppedLoading(self, **kwargs):
"""页面加载完成后执行"""
...
def _onFileChooserOpened(self, **kwargs): ...
def _onFileChooserOpened(self, **kwargs):
"""文件选择框打开时执行"""
...
def _wait_to_stop(self): ...
# def _d_set_start_options(self, address) -> None: ...
def _d_set_runtime_settings(self) -> None: ...
def __call__(self,
locator: Union[Tuple[str, str], str, ChromiumElement],
index: int = 1,
timeout: float = None) -> ChromiumElement: ...
def _wait_to_stop(self):
"""eager策略超时时使页面停止加载"""
...
@property
def _js_ready_state(self) -> str: ...
def wait(self) -> BaseWaiter:
"""返回用于等待的对象"""
...
@property
def browser(self) -> Chromium: ...
def set(self) -> ChromiumBaseSetter:
"""返回用于设置的对象"""
...
@property
def title(self) -> str: ...
def screencast(self) -> Screencast:
"""返回用于录屏的对象"""
...
@property
def driver(self) -> Driver: ...
def actions(self) -> Actions:
"""返回用于执行动作链的对象"""
...
@property
def url(self) -> str: ...
def listen(self) -> Listener:
"""返回用于聆听数据包的对象"""
...
@property
def _browser_url(self) -> str: ...
def states(self) -> PageStates:
"""返回用于获取状态信息的对象"""
...
@property
def html(self) -> str: ...
def scroll(self) -> PageScroller:
"""返回用于滚动滚动条的对象"""
...
@property
def json(self) -> Union[dict, None]: ...
def rect(self) -> TabRect:
"""返回获取窗口坐标和大小的对象"""
...
@property
def _target_id(self) -> str: ...
def console(self) -> Console:
"""返回获取控制台信息的对象"""
...
@property
def tab_id(self) -> str: ...
def timeout(self) -> float:
"""返回timeout设置"""
...
@property
def active_ele(self) -> ChromiumElement: ...
def timeouts(self) -> Timeout:
"""返回timeouts设置"""
...
@property
def load_mode(self) -> str: ...
def browser(self) -> Chromium:
"""返回浏览器对象"""
...
@property
def user_agent(self) -> str: ...
def driver(self) -> Driver:
"""返回用于控制浏览器的Driver对象"""
...
@property
def scroll(self) -> PageScroller: ...
def title(self) -> str:
"""返回当前页面title"""
...
@property
def rect(self) -> TabRect: ...
def url(self) -> str:
"""返回当前页面url"""
...
@property
def console(self) -> Console: ...
def _browser_url(self) -> str:
"""用于被MixTab覆盖"""
...
@property
def timeout(self) -> float: ...
def html(self) -> str:
"""返回当前页面html文本"""
...
@property
def timeouts(self) -> Timeout: ...
def json(self) -> Union[dict, None]:
"""当返回内容是json格式时返回对应的字典非json格式时返回None"""
...
@property
def upload_list(self) -> list: ...
def tab_id(self) -> str:
"""返回当前标签页id"""
...
@property
def wait(self) -> BaseWaiter: ...
def _target_id(self) -> str:
"""返回当前标签页id"""
...
@property
def set(self) -> ChromiumBaseSetter: ...
def active_ele(self) -> ChromiumElement:
"""返回当前焦点所在元素"""
...
@property
def screencast(self) -> Screencast: ...
def load_mode(self) -> Literal['none', 'normal', 'eager']:
"""返回页面加载策略有3种'none''normal''eager'"""
...
@property
def actions(self) -> Actions: ...
def user_agent(self) -> str:
"""返回user agent"""
...
@property
def listen(self) -> Listener: ...
def upload_list(self) -> list:
"""返回等待上传文件列表"""
...
@property
def states(self) -> PageStates: ...
def _js_ready_state(self) -> str:
"""返回js获取的ready state信息"""
...
def run_js(self, script: Union[str, Path], *args, as_expr: bool = False, timeout: float = None) -> Any: ...
def run_cdp(self, cmd: str, **cmd_args) -> dict:
"""执行Chrome DevTools Protocol语句
:param cmd: 协议项目
:param cmd_args: 参数
:return: 执行的结果
"""
...
def run_js_loaded(self, script: Union[str, Path], *args, as_expr: bool = False, timeout: float = None) -> Any: ...
def run_cdp_loaded(self, cmd: str, **cmd_args) -> dict:
"""执行Chrome DevTools Protocol语句执行前等待页面加载完毕
:param cmd: 协议项目
:param cmd_args: 参数
:return: 执行的结果
"""
...
def _run_js(self, script: Union[str, Path], *args, as_expr: bool = False, timeout: float = None) -> Any: ...
def _run_cdp(self, cmd: str, **cmd_args) -> dict:
"""执行Chrome DevTools Protocol语句
:param cmd: 协议项目
:param cmd_args: 参数
:return: 执行的结果
"""
...
def _run_js_loaded(self, script: Union[str, Path], *args, as_expr: bool = False, timeout: float = None) -> Any: ...
def _run_cdp_loaded(self, cmd: str, **cmd_args) -> dict:
"""执行Chrome DevTools Protocol语句执行前等待页面加载完毕
:param cmd: 协议项目
:param cmd_args: 参数
:return: 执行的结果
"""
...
def run_async_js(self, script: Union[str, Path], *args, as_expr: bool = False) -> None: ...
def run_js(self, script: Union[str, Path], *args, as_expr: bool = False, timeout: float = None) -> Any:
"""运行javascript代码
:param script: js文本或js文件路径
:param args: 参数按顺序在js文本中对应arguments[0]arguments[1]...
:param as_expr: 是否作为表达式运行为True时args无效
:param timeout: js超时时间为None则使用页面timeouts.script设置
:return: 运行的结果
"""
...
def run_js_loaded(self, script: Union[str, Path], *args, as_expr: bool = False, timeout: float = None) -> Any:
"""运行javascript代码执行前等待页面加载完毕
:param script: js文本或js文件路径
:param args: 参数按顺序在js文本中对应arguments[0]arguments[1]...
:param as_expr: 是否作为表达式运行为True时args无效
:param timeout: js超时时间为None则使用页面timeouts.script属性值
:return: 运行的结果
"""
...
def _run_js(self, script: Union[str, Path], *args, as_expr: bool = False, timeout: float = None) -> Any:
"""运行javascript代码
:param script: js文本或js文件路径
:param args: 参数按顺序在js文本中对应arguments[0]arguments[1]...
:param as_expr: 是否作为表达式运行为True时args无效
:param timeout: js超时时间为None则使用页面timeouts.script设置
:return: 运行的结果
"""
...
def _run_js_loaded(self, script: Union[str, Path], *args, as_expr: bool = False, timeout: float = None) -> Any:
"""运行javascript代码执行前等待页面加载完毕
:param script: js文本或js文件路径
:param args: 参数按顺序在js文本中对应arguments[0]arguments[1]...
:param as_expr: 是否作为表达式运行为True时args无效
:param timeout: js超时时间为None则使用页面timeouts.script属性值
:return: 运行的结果
"""
...
def run_async_js(self, script: Union[str, Path], *args, as_expr: bool = False) -> None:
"""以异步方式执行js代码或js文件路径
:param script: js文本
:param args: 参数按顺序在js文本中对应arguments[0]arguments[1]...
:param as_expr: 是否作为表达式运行为True时args无效
:return: None
"""
...
def get(self, url: str, show_errmsg: bool = False, retry: int = None,
interval: float = None, timeout: float = None) -> Union[None, bool]: ...
interval: float = None, timeout: float = None) -> Union[None, bool]:
"""访问url
:param url: 目标url
:param show_errmsg: 是否显示和抛出异常
:param retry: 重试次数为None时使用页面对象retry_times属性值
:param interval: 重试间隔为None时使用页面对象retry_interval属性值
:param timeout: 连接超时时间为None时使用页面对象timeouts.page_load属性值
:return: 目标url是否可用
"""
...
def cookies(self, all_domains: bool = False, all_info: bool = False) -> CookiesList: ...
def cookies(self, all_domains: bool = False, all_info: bool = False) -> CookiesList:
"""返回cookies信息
:param all_domains: 是否返回所有域的cookies
:param all_info: 是否返回所有信息为False时只返回namevaluedomain
:return: cookies信息
"""
...
def ele(self,
locator: Union[Tuple[str, str], str, ChromiumElement, ChromiumFrame],
index: int = 1,
timeout: float = None) -> ChromiumElement: ...
timeout: float = None) -> ChromiumElement:
"""获取一个符合条件的元素对象
:param locator: 定位符或元素对象
:param index: 获取第几个元素从1开始可传入负数获取倒数第几个
:param timeout: 查找超时时间默认与页面等待时间一致
:return: ChromiumElement对象
"""
...
def eles(self,
locator: Union[Tuple[str, str], str],
timeout: float = None) -> ChromiumElementsList: ...
timeout: float = None) -> ChromiumElementsList:
"""获取所有符合条件的元素对象
:param locator: 定位符或元素对象
:param timeout: 查找超时时间默认与页面等待时间一致
:return: ChromiumElement对象组成的列表
"""
...
def s_ele(self,
locator: Union[Tuple[str, str], str] = None,
index: int = 1,
timeout: float = None) -> SessionElement: ...
timeout: float = None) -> SessionElement:
"""查找一个符合条件的元素以SessionElement形式返回处理复杂页面时效率很高
:param locator: 元素的定位信息可以是loc元组或查询字符串
:param index: 获取第几个从1开始可传入负数获取倒数第几个
:param timeout: 查找元素超时时间默认与页面等待时间一致
:return: SessionElement对象或属性文本
"""
...
def s_eles(self,
locator: Union[Tuple[str, str], str],
timeout: float = None) -> SessionElementsList: ...
timeout: float = None) -> SessionElementsList:
"""查找所有符合条件的元素以SessionElement列表形式返回
:param locator: 元素的定位信息可以是loc元组或查询字符串
:param timeout: 查找元素超时时间默认与页面等待时间一致
:return: SessionElement对象组成的列表
"""
...
def _find_elements(self,
locator: Union[Tuple[str, str], str, ChromiumElement, ChromiumFrame],
timeout: float = None,
index: Optional[int] = 1,
relative: bool = False,
raise_err: bool = None) -> Union[ChromiumElement, ChromiumFrame, ChromiumElementsList]: ...
raise_err: bool = None) -> Union[ChromiumElement, ChromiumFrame, ChromiumElementsList]:
"""执行元素查找
:param locator: 定位符或元素对象
:param timeout: 查找超时时间
:param index: 第几个结果从1开始可传入负数获取倒数第几个为None返回所有
:param relative: MixTab用的表示是否相对定位的参数
:param raise_err: 找不到元素是是否抛出异常为None时根据全局设置
:return: ChromiumElement对象或元素对象组成的列表
"""
...
def refresh(self, ignore_cache: bool = False) -> None: ...
def refresh(self, ignore_cache: bool = False) -> None:
"""刷新当前页面
:param ignore_cache: 是否忽略缓存
:return: None
"""
...
def forward(self, steps: int = 1) -> None: ...
def forward(self, steps: int = 1) -> None:
"""在浏览历史中前进若干步
:param steps: 前进步数
:return: None
"""
...
def back(self, steps: int = 1) -> None: ...
def back(self, steps: int = 1) -> None:
"""在浏览历史中后退若干步
:param steps: 后退步数
:return: None
"""
...
def _forward_or_back(self, steps: int) -> None: ...
def _forward_or_back(self, steps: int) -> None:
"""执行浏览器前进或后退会跳过url相同的历史记录
:param steps: 步数
:return: None
"""
...
def stop_loading(self) -> None: ...
def stop_loading(self) -> None:
"""页面停止加载"""
...
def remove_ele(self, loc_or_ele: Union[ChromiumElement, ChromiumFrame, str, Tuple[str, str]]) -> None: ...
def remove_ele(self, loc_or_ele: Union[ChromiumElement, ChromiumFrame, str, Tuple[str, str]]) -> None:
"""从页面上删除一个元素
:param loc_or_ele: 元素对象或定位符
:return: None
"""
...
def add_ele(self,
html_or_info: Union[str, Tuple[str, dict]],
insert_to: Union[ChromiumElement, str, Tuple[str, str], None] = None,
before: Union[ChromiumElement, str, Tuple[str, str], None] = None) -> ChromiumElement: ...
before: Union[ChromiumElement, str, Tuple[str, str], None] = None) -> ChromiumElement:
"""新建一个元素
:param html_or_info: 新元素的html文本或信息信息格式为(tag, {attr1: value, ...})
:param insert_to: 插入到哪个元素中可接收元素对象和定位符为None且为html添加到body不为html不插入
:param before: 在哪个子节点前面插入可接收对象和定位符为None插入到父元素末尾
:return: 元素对象
"""
...
def get_frame(self,
loc_ind_ele: Union[str, int, tuple, ChromiumFrame, ChromiumElement],
timeout: float = None) -> ChromiumFrame: ...
timeout: float = None) -> ChromiumFrame:
"""获取页面中一个frame对象
:param loc_ind_ele: 定位符iframe序号ChromiumFrame对象序号从1开始可传入负数获取倒数第几个
:param timeout: 查找元素超时时间
:return: ChromiumFrame对象
"""
...
def get_frames(self, locator: Union[str, tuple] = None, timeout: float = None) -> List[ChromiumFrame]: ...
def get_frames(self, locator: Union[str, tuple] = None, timeout: float = None) -> List[ChromiumFrame]:
"""获取所有符合条件的frame对象
:param locator: 定位符为None时返回所有
:param timeout: 查找超时时间
:return: ChromiumFrame对象组成的列表
"""
...
def run_cdp(self, cmd: str, **cmd_args) -> dict: ...
def session_storage(self, item: str = None) -> Union[str, dict, None]:
"""返回sessionStorage信息不设置item则获取全部
:param item: 要获取的项不设置则返回全部
:return: sessionStorage一个或所有项内容
"""
...
def run_cdp_loaded(self, cmd: str, **cmd_args) -> dict: ...
def _run_cdp(self, cmd: str, **cmd_args) -> dict: ...
def _run_cdp_loaded(self, cmd: str, **cmd_args) -> dict: ...
def session_storage(self, item: str = None) -> Union[str, dict, None]: ...
def local_storage(self, item: str = None) -> Union[str, dict, None]: ...
def add_init_js(self, script: str) -> str: ...
def remove_init_js(self, script_id: str = None) -> None: ...
def local_storage(self, item: str = None) -> Union[str, dict, None]:
"""返回localStorage信息不设置item则获取全部
:param item: 要获取的项目不设置则返回全部
:return: localStorage一个或所有项内容
"""
...
def get_screenshot(self, path: [str, Path] = None, name: str = None, as_bytes: PIC_TYPE = None,
as_base64: PIC_TYPE = None, full_page: bool = False, left_top: Tuple[int, int] = None,
right_bottom: Tuple[int, int] = None) -> Union[str, bytes]: ...
right_bottom: Tuple[int, int] = None) -> Union[str, bytes]:
"""对页面进行截图可对整个网页、可见网页、指定范围截图。对可视范围外截图需要90以上版本浏览器支持
:param path: 保存路径
:param name: 完整文件名后缀可选 'jpg','jpeg','png','webp'
:param as_bytes: 是否以字节形式返回图片可选 'jpg','jpeg','png','webp'生效时path参数和as_base64参数无效
:param as_base64: 是否以base64字符串形式返回图片可选 'jpg','jpeg','png','webp'生效时path参数无效
:param full_page: 是否整页截图为True截取整个网页为False截取可视窗口
:param left_top: 截取范围左上角坐标
:param right_bottom: 截取范围右下角角坐标
:return: 图片完整路径或字节文本
"""
...
def add_init_js(self, script: str) -> str:
"""添加初始化脚本,在页面加载任何脚本前执行
:param script: js文本
:return: 添加的脚本的id
"""
...
def remove_init_js(self, script_id: str = None) -> None:
"""删除初始化脚本js_id传入None时删除所有
:param script_id: 脚本的id
:return: None
"""
...
def clear_cache(self, session_storage: bool = True, local_storage: bool = True, cache: bool = True,
cookies: bool = True) -> None:
"""清除缓存,可选要清除的项
:param session_storage: 是否清除sessionStorage
:param local_storage: 是否清除localStorage
:param cache: 是否清除cache
:param cookies: 是否清除cookies
:return: None
"""
...
def disconnect(self) -> None:
"""断开与页面的连接,不关闭页面"""
...
def reconnect(self, wait: float = 0) -> None:
"""断开与页面原来的页面,重新建立连接
:param wait: 断开后等待若干秒再连接
:return: None
"""
...
def handle_alert(self, accept: Optional[bool] = True, send: str = None, timeout: float = None,
next_one: bool = False) -> Union[str, False]:
"""处理提示框,可以自动等待提示框出现
:param accept: True表示确认False表示取消为None不会按按钮但依然返回文本值
:param send: 处理prompt提示框时可输入文本
:param timeout: 等待提示框出现的超时时间为None则使用self.timeout属性的值
:param next_one: 是否处理下一个出现的提示框为True时timeout参数无效
:return: 提示框内容文本未等到提示框则返回False
"""
...
def _handle_alert(self, accept: bool = True, send: str = None, timeout: float = None,
next_one: bool = False) -> Union[str, False]:
"""处理提示框,可以自动等待提示框出现
:param accept: True表示确认False表示取消其它值不会按按钮但依然返回文本值
:param send: 处理prompt提示框时可输入文本
:param timeout: 等待提示框出现的超时时间为None则使用self.timeout属性的值
:param next_one: 是否处理下一个出现的提示框为True时timeout参数无效
:return: 提示框内容文本未等到提示框则返回False
"""
...
def _on_alert_open(self, **kwargs):
"""alert出现时触发的方法"""
...
def _on_alert_close(self, **kwargs):
"""alert关闭时触发的方法"""
...
def _wait_loaded(self, timeout: float = None) -> bool:
"""等待页面加载完成,超时触发停止加载
:param timeout: 超时时间
:return: 是否成功超时返回False
"""
...
def _d_connect(self, to_url: str, times: int = 0, interval: float = 1, show_errmsg: bool = False,
timeout: float = None) -> Union[bool, None]:
"""尝试连接,重试若干次
:param to_url: 要访问的url
:param times: 重试次数
:param interval: 重试间隔
:param show_errmsg: 是否抛出异常
:param timeout: 连接超时时间
:return: 是否成功返回None表示不确定
"""
...
def _get_screenshot(self, path: [str, Path] = None, name: str = None, as_bytes: PIC_TYPE = None,
as_base64: PIC_TYPE = None, full_page: bool = False, left_top: Tuple[float, float] = None,
right_bottom: Tuple[float, float] = None, ele: ChromiumElement = None) -> Union[str, bytes]: ...
def clear_cache(self, session_storage: bool = True, local_storage: bool = True, cache: bool = True,
cookies: bool = True) -> None: ...
def disconnect(self) -> None: ...
def reconnect(self, wait: float = 0) -> None: ...
def handle_alert(self, accept: Optional[bool] = True, send: str = None, timeout: float = None,
next_one: bool = False) -> Union[str, False]: ...
def _handle_alert(self, accept: bool = True, send: str = None, timeout: float = None,
next_one: bool = False) -> Union[str, False]: ...
def _on_alert_close(self, **kwargs): ...
def _on_alert_open(self, **kwargs): ...
def _d_connect(self, to_url: str, times: int = 0, interval: float = 1, show_errmsg: bool = False,
timeout: float = None) -> Union[bool, None]: ...
right_bottom: Tuple[float, float] = None, ele: ChromiumElement = None) -> Union[str, bytes]:
"""对页面进行截图可对整个网页、可见网页、指定范围截图。对可视范围外截图需要90以上版本浏览器支持
:param path: 保存路径
:param name: 完整文件名后缀可选 'jpg','jpeg','png','webp'
:param as_bytes: 是否以字节形式返回图片可选 'jpg','jpeg','png','webp'生效时path参数和as_base64参数无效
:param as_base64: 是否以base64字符串形式返回图片可选 'jpg','jpeg','png','webp'生效时path参数无效
:param full_page: 是否整页截图为True截取整个网页为False截取可视窗口
:param left_top: 截取范围左上角坐标
:param right_bottom: 截取范围右下角角坐标
:param ele: 为异域iframe内元素截图设置
:return: 图片完整路径或字节文本
"""
...
class Timeout(object):
base: float = ...
page_load: float = ...
script: float = ...
def __init__(self, base=None, page_load=None, script=None):
self.base: float = ...
self.page_load: float = ...
self.script: float = ...
"""
:param base: 默认超时时间
:param page_load: 页面加载超时时间
:param script: js超时时间
"""
...
@property
def as_dict(self) -> dict: ...
def as_dict(self) -> dict:
"""以dict格式返回timeout设置"""
...
class Alert(object):
def __init__(self):
self.activated: bool = ...
self.text: str = ...
self.type: str = ...
self.defaultPrompt: str = ...
self.response_accept: str = ...
self.response_text: str = ...
self.handle_next: Optional[bool] = ...
self.next_text: str = ...
self.auto: Optional[bool] = ...
def get_mhtml(page: Union[ChromiumPage, ChromiumTab],
path: Union[str, Path] = None,
name: str = None) -> str: ...
def get_pdf(page: Union[ChromiumPage, ChromiumTab],
path: Union[str, Path] = None,
name: str = None, kwargs: dict = None) -> bytes: ...
activated: Optional[bool] = ...
text: Optional[str] = ...
type: Optional[str] = ...
defaultPrompt: Optional[str] = ...
response_accept: Optional[str] = ...
response_text: Optional[str] = ...
handle_next: Optional[bool] = ...
next_text: Optional[str] = ...
auto: Optional[bool] = ...

View File

@ -24,18 +24,19 @@ from .._units.setter import MixPageSetter
class MixPage(SessionPage, ChromiumPage, BasePage):
_mode: str = ...
_set: MixPageSetter = ...
_has_driver: Optional[bool] = ...
_has_session: Optional[bool] = ...
_session_options: Union[SessionOptions, None] = ...
_chromium_options: Union[ChromiumOptions, None] = ...
def __init__(self,
mode: str = 'd',
timeout: float = None,
chromium_options: Union[ChromiumOptions, bool] = None,
session_or_options: Union[Session, SessionOptions, bool] = None) -> None:
self._mode: str = ...
self._set: MixPageSetter = ...
self._has_driver: bool = ...
self._has_session: bool = ...
self._session_options: Union[SessionOptions, None] = ...
self._chromium_options: Union[ChromiumOptions, None] = ...
...
def __call__(self,
locator: Union[Tuple[str, str], str, ChromiumElement, SessionElement],

View File

@ -14,28 +14,12 @@ from ..errors import CanNotClickError, CDPError, NoRectError, AlertExistsError
class Clicker(object):
def __init__(self, ele):
"""
:param ele: ChromiumElement
"""
self._ele = ele
def __call__(self, by_js=False, timeout=1.5, wait_stop=True):
"""点击元素
如果遇到遮挡可选择是否用js点击
:param by_js: 是否用js点击为None时先用模拟点击遇到遮挡改用js为True时直接用js点击为False时只用模拟点击
:param timeout: 模拟点击的超时时间等待元素可见可用进入视口
:param wait_stop: 是否等待元素运动结束再执行点击
:return: 是否点击成功
"""
return self.left(by_js, timeout, wait_stop)
def left(self, by_js=False, timeout=1.5, wait_stop=True):
"""点击元素可选择是否用js点击
:param by_js: 是否用js点击为None时先用模拟点击遇到遮挡改用js为True时直接用js点击为False时只用模拟点击
:param timeout: 模拟点击的超时时间等待元素可见可用进入视口
:param wait_stop: 是否等待元素运动结束再执行点击
:return: 是否点击成功
"""
if self._ele.tag == 'option':
if not self._ele.states.is_selected:
self._ele.parent('t:select').select.by_option(self._ele)
@ -108,15 +92,10 @@ class Clicker(object):
return False
def right(self):
"""右键单击"""
self._ele.owner.scroll.to_see(self._ele)
return self._click(*self._ele.rect.viewport_click_point, button='right')
def middle(self, get_tab=True):
"""中键单击默认返回新出现的tab对象
:param get_tab: 是否返回新tab对象为False则返回None
:return: Tab对象或None
"""
self._ele.owner.scroll.to_see(self._ele)
curr_tid = self._ele.tab.browser.tab_ids[0]
self._click(*self._ele.rect.viewport_click_point, button='middle')
@ -128,13 +107,6 @@ class Clicker(object):
else self._ele.tab.browser.get_tab(tid))
def at(self, offset_x=None, offset_y=None, button='left', count=1):
"""带偏移量点击本元素相对于左上角坐标。不传入x或y值时点击元素中间点
:param offset_x: 相对元素左上角坐标的x轴偏移量
:param offset_y: 相对元素左上角坐标的y轴偏移量
:param button: 点击哪个键可选 left, middle, right, back, forward
:param count: 点击次数
:return: None
"""
self._ele.owner.scroll.to_see(self._ele)
if offset_x is None and offset_y is None:
w, h = self._ele.rect.size
@ -143,22 +115,9 @@ class Clicker(object):
return self._click(*offset_scroll(self._ele, offset_x, offset_y), button=button, count=count)
def multi(self, times=2):
"""多次点击
:param times: 默认双击
:return: None
"""
return self.at(count=times)
def to_download(self, save_path=None, rename=None, suffix=None, new_tab=False, by_js=False, timeout=None):
"""点击触发下载
:param save_path: 保存路径为None保存在原来设置的如未设置保存到当前路径
:param rename: 重命名文件名
:param suffix: 指定文件后缀
:param new_tab: 该下载是否在新tab中触发
:param by_js: 是否用js方式点击逻辑与click()一致
:param timeout: 等待下载触发的超时时间为None则使用页面对象设置
:return: DownloadMission对象
"""
if save_path:
self._ele.tab.set.download_path(save_path)
elif not self._ele.tab._browser._dl_mgr._running:
@ -172,21 +131,11 @@ class Clicker(object):
return obj.wait.download_begin(timeout=timeout)
def to_upload(self, file_paths, by_js=False):
"""触发上传文件选择框并自动填入指定路径
:param file_paths: 文件路径如果上传框支持多文件可传入列表或字符串字符串时多个文件用回车分隔
:param by_js: 是否用js方式点击逻辑与click()一致
:return: None
"""
self._ele.owner.set.upload_files(file_paths)
self.left(by_js=by_js)
self._ele.owner.wait.upload_paths_inputted()
def for_new_tab(self, by_js=False, timeout=3):
"""点击后等待新tab出现并返回其对象
:param by_js: 是否使用js点击逻辑与click()一致
:param timeout: 等待超时时间
:return: 新标签页对象如果没有等到新标签页出现则抛出异常
"""
curr_tid = self._ele.tab.browser.tab_ids[0]
self.left(by_js=by_js)
tid = self._ele.tab.browser.wait.new_tab(timeout=timeout, curr_tab=curr_tid)
@ -196,13 +145,6 @@ class Clicker(object):
else self._ele.tab.browser.get_tab(tid))
def for_url_change(self, text=None, exclude=False, by_js=False, timeout=None):
"""点击并等待tab的url变成包含或不包含指定文本
:param text: 用于识别的文本为None等待当前url变化
:param exclude: 是否排除为True时当url不包含text指定文本时返回Truetext为None时自动设为True
:param by_js: 是否用js点击
:param timeout: 超时时间为None使用页面设置
:return: 是否等待成功
"""
if text is None:
exclude = True
text = self._ele.tab.url
@ -210,13 +152,6 @@ class Clicker(object):
return True if self._ele.tab.wait.url_change(text=text, exclude=exclude, timeout=timeout) else False
def for_title_change(self, text=None, exclude=False, by_js=False, timeout=None):
"""点击并等待tab的title变成包含或不包含指定文本
:param text: 用于识别的文本为None等待当前title变化
:param exclude: 是否排除为True时当title不包含text指定文本时返回Truetext为None时自动设为True
:param by_js: 是否用js点击
:param timeout: 超时时间为None使用页面设置
:return: 是否等待成功
"""
if text is None:
exclude = True
text = self._ele.tab.title
@ -224,13 +159,6 @@ class Clicker(object):
return True if self._ele.tab.wait.title_change(text=text, exclude=exclude, timeout=timeout) else False
def _click(self, view_x, view_y, button='left', count=1):
"""实施点击
:param view_x: 视口x坐标
:param view_y: 视口y坐标
:param button: 'left' 'right' 'middle' 'back' 'forward'
:param count: 点击次数
:return: None
"""
self._ele.owner._run_cdp('Input.dispatchMouseEvent', type='mousePressed', x=view_x,
y=view_y, button=button, clickCount=count, _ignore=AlertExistsError)
self._ele.owner._run_cdp('Input.dispatchMouseEvent', type='mouseReleased', x=view_x,

View File

@ -14,26 +14,66 @@ from .._pages.tabs import MixTab, ChromiumTab
class Clicker(object):
_ele: ChromiumElement = ...
def __init__(self, ele: ChromiumElement):
self._ele: ChromiumElement = ...
"""
:param ele: ChromiumElement
"""
...
def __call__(self, by_js: Union[bool, str, None] = False,
timeout: float = 1.5, wait_stop: bool = True) -> Union[ChromiumElement, False]: ...
timeout: float = 1.5, wait_stop: bool = True) -> Union[ChromiumElement, False]:
"""点击元素
如果遇到遮挡可选择是否用js点击
:param by_js: 是否用js点击为None时先用模拟点击遇到遮挡改用js为True时直接用js点击为False时只用模拟点击
:param timeout: 模拟点击的超时时间等待元素可见可用进入视口
:param wait_stop: 是否等待元素运动结束再执行点击
:return: 是否点击成功
"""
...
def left(self, by_js: Union[bool, str, None] = False,
timeout: float = 1.5, wait_stop: bool = True) -> Union[ChromiumElement, False]: ...
timeout: float = 1.5, wait_stop: bool = True) -> Union[ChromiumElement, False]:
"""点击元素可选择是否用js点击
:param by_js: 是否用js点击为None时先用模拟点击遇到遮挡改用js为True时直接用js点击为False时只用模拟点击
:param timeout: 模拟点击的超时时间等待元素可见可用进入视口
:param wait_stop: 是否等待元素运动结束再执行点击
:return: 是否点击成功
"""
...
def right(self) -> ChromiumElement: ...
def right(self) -> ChromiumElement:
"""右键单击"""
...
def middle(self, get_tab: bool = True) -> Union[ChromiumTab, MixTab, None]: ...
def middle(self, get_tab: bool = True) -> Union[ChromiumTab, MixTab, None]:
"""中键单击默认返回新出现的tab对象
:param get_tab: 是否返回新tab对象为False则返回None
:return: Tab对象或None
"""
...
def at(self,
offset_x: float = None,
offset_y: float = None,
button: str = 'left',
count: int = 1) -> ChromiumElement: ...
count: int = 1) -> ChromiumElement:
"""带偏移量点击本元素相对于左上角坐标。不传入x或y值时点击元素中间点
:param offset_x: 相对元素左上角坐标的x轴偏移量
:param offset_y: 相对元素左上角坐标的y轴偏移量
:param button: 点击哪个键可选 left, middle, right, back, forward
:param count: 点击次数
:return: None
"""
...
def multi(self, times: int = 2) -> ChromiumElement: ...
def multi(self, times: int = 2) -> ChromiumElement:
"""多次点击
:param times: 默认双击
:return: None
"""
...
def to_download(self,
save_path: Union[str, Path] = None,
@ -41,20 +81,66 @@ class Clicker(object):
suffix: str = None,
new_tab: bool = False,
by_js: bool = False,
timeout: float = None) -> DownloadMission: ...
timeout: float = None) -> DownloadMission:
"""点击触发下载
:param save_path: 保存路径为None保存在原来设置的如未设置保存到当前路径
:param rename: 重命名文件名
:param suffix: 指定文件后缀
:param new_tab: 该下载是否在新tab中触发
:param by_js: 是否用js方式点击逻辑与click()一致
:param timeout: 等待下载触发的超时时间为None则使用页面对象设置
:return: DownloadMission对象
"""
...
def to_upload(self, file_paths: Union[str, Path, list, tuple], by_js: bool = False) -> None: ...
def to_upload(self, file_paths: Union[str, Path, list, tuple], by_js: bool = False) -> None:
"""触发上传文件选择框并自动填入指定路径
:param file_paths: 文件路径如果上传框支持多文件可传入列表或字符串字符串时多个文件用回车分隔
:param by_js: 是否用js方式点击逻辑与click()一致
:return: None
"""
...
def for_new_tab(self, by_js: bool = False, timeout: float = 3) -> Union[ChromiumTab, MixTab]: ...
def for_new_tab(self, by_js: bool = False, timeout: float = 3) -> Union[ChromiumTab, MixTab]:
"""点击后等待新tab出现并返回其对象
:param by_js: 是否使用js点击逻辑与click()一致
:param timeout: 等待超时时间
:return: 新标签页对象如果没有等到新标签页出现则抛出异常
"""
...
def for_url_change(self, text: str = None, exclude: bool = False,
by_js: bool = False, timeout: float = None) -> bool: ...
by_js: bool = False, timeout: float = None) -> bool:
"""点击并等待tab的url变成包含或不包含指定文本
:param text: 用于识别的文本为None等待当前url变化
:param exclude: 是否排除为True时当url不包含text指定文本时返回Truetext为None时自动设为True
:param by_js: 是否用js点击
:param timeout: 超时时间为None使用页面设置
:return: 是否等待成功
"""
...
def for_title_change(self, text: str = None, exclude: bool = False,
by_js: bool = False, timeout: float = None) -> bool: ...
by_js: bool = False, timeout: float = None) -> bool:
"""点击并等待tab的title变成包含或不包含指定文本
:param text: 用于识别的文本为None等待当前title变化
:param exclude: 是否排除为True时当title不包含text指定文本时返回Truetext为None时自动设为True
:param by_js: 是否用js点击
:param timeout: 超时时间为None使用页面设置
:return: 是否等待成功
"""
...
def _click(self,
view_x: float,
view_y: float,
button: str = 'left',
count: int = 1) -> ChromiumElement: ...
count: int = 1) -> ChromiumElement:
"""实施点击
:param view_x: 视口x坐标
:param view_y: 视口y坐标
:param button: 'left' 'right' 'middle' 'back' 'forward'
:param count: 点击次数
:return: None
"""
...

View File

@ -53,7 +53,6 @@ class ConsoleData(object):
self._data = data
def __getattr__(self, item):
"""获取属性"""
return self._data.get(item, None)
def __repr__(self):

View File

@ -10,10 +10,16 @@ class Console(object):
owner: ChromiumBase = ...
_caught: Optional[Queue] = ...
def __init__(self, owner: ChromiumBase) -> None: ...
def __init__(self, owner: ChromiumBase) -> None:
"""
:param owner: 页面对象
"""
...
@property
def messages(self) -> List[ConsoleData]: ...
def messages(self) -> List[ConsoleData]:
"""以list方式返回获取到的信息返回后会清空列表"""
...
def start(self) -> None:
"""开启console监听"""

View File

@ -10,44 +10,21 @@ from .._functions.cookies import set_tab_cookies, set_session_cookies, set_brows
class BrowserCookiesSetter(object):
def __init__(self, owner):
"""
:param owner: Chromium对象
"""
self._owner = owner
def __call__(self, cookies):
"""设置一个或多个cookie
:param cookies: cookies信息
:return: None
"""
set_browser_cookies(self._owner, cookies)
def clear(self):
"""清除cookies"""
self._owner._run_cdp('Storage.clearCookies')
class CookiesSetter(BrowserCookiesSetter):
def __call__(self, cookies):
"""设置一个或多个cookie
:param cookies: cookies信息
:return: None
"""
set_tab_cookies(self._owner, cookies)
def clear(self):
"""清除cookies"""
self._owner._run_cdp('Network.clearBrowserCookies')
def remove(self, name, url=None, domain=None, path=None):
"""删除一个cookie
:param name: cookie的name字段
:param url: cookie的url字段可选
:param domain: cookie的domain字段可选
:param path: cookie的path字段可选
:return: None
"""
d = {'name': name}
if url is not None:
d['url'] = url
@ -61,50 +38,33 @@ class CookiesSetter(BrowserCookiesSetter):
d['path'] = path
self._owner._run_cdp('Network.deleteCookies', **d)
def clear(self):
self._owner._run_cdp('Network.clearBrowserCookies')
class SessionCookiesSetter(object):
def __init__(self, owner):
self._owner = owner
def __call__(self, cookies):
"""设置多个cookie注意不要传入单个
:param cookies: cookies信息
:return: None
"""
set_session_cookies(self._owner.session, cookies)
def remove(self, name):
"""删除一个cookie
:param name: cookie的name字段
:return: None
"""
self._owner.session.cookies.set(name, None)
def clear(self):
"""清除cookies"""
self._owner.session.cookies.clear()
class MixPageCookiesSetter(CookiesSetter, SessionCookiesSetter):
def __call__(self, cookies):
"""设置多个cookie注意不要传入单个
:param cookies: cookies信息
:return: None
"""
if self._owner.mode == 'd' and self._owner._has_driver:
super().__call__(cookies)
elif self._owner.mode == 's' and self._owner._has_session:
super(CookiesSetter, self).__call__(cookies)
def remove(self, name, url=None, domain=None, path=None):
"""删除一个cookie
:param name: cookie的name字段
:param url: cookie的url字段可选d模式时才有效
:param domain: cookie的domain字段可选d模式时才有效
:param path: cookie的path字段可选d模式时才有效
:return: None
"""
if self._owner.mode == 'd' and self._owner._has_driver:
super().remove(name, url, domain, path)
elif self._owner.mode == 's' and self._owner._has_session:
@ -113,7 +73,6 @@ class MixPageCookiesSetter(CookiesSetter, SessionCookiesSetter):
super(CookiesSetter, self).remove(name)
def clear(self):
"""清除cookies"""
if self._owner.mode == 'd' and self._owner._has_driver:
super().clear()
elif self._owner.mode == 's' and self._owner._has_session:

View File

@ -18,42 +18,117 @@ from .._pages.mix_page import MixPage
class BrowserCookiesSetter(object):
_owner: Chromium = ...
def __init__(self, page: Chromium): ...
def __init__(self, owner: Chromium):
"""
:param owner: Chromium对象
"""
...
def __call__(self, cookies: Union[CookieJar, Cookie, list, tuple, str, dict]) -> None: ...
def __call__(self, cookies: Union[CookieJar, Cookie, list, tuple, str, dict]) -> None:
"""设置一个或多个cookie
:param cookies: cookies信息
:return: None
"""
...
def clear(self) -> None: ...
def clear(self) -> None:
"""清除cookies"""
...
class CookiesSetter(BrowserCookiesSetter):
_owner: ChromiumBase = ...
def __init__(self, page: ChromiumBase): ...
def __init__(self, owner: ChromiumBase):
"""
:param owner: 页面对象
"""
...
def remove(self, name: str, url: str = None, domain: str = None, path: str = None) -> None: ...
def __call__(self, cookies: Union[CookieJar, Cookie, list, tuple, str, dict]) -> None:
"""设置一个或多个cookie
:param cookies: cookies信息
:return: None
"""
...
def clear(self) -> None: ...
def remove(self,
name: str,
url: str = None,
domain: str = None,
path: str = None) -> None:
"""删除一个cookie
:param name: cookie的name字段
:param url: cookie的url字段可选
:param domain: cookie的domain字段可选
:param path: cookie的path字段可选
:return: None
"""
...
def clear(self) -> None:
"""清除cookies"""
...
class SessionCookiesSetter(object):
_owner: SessionPage = ...
def __init__(self, page: SessionPage): ...
def __init__(self, owner: SessionPage):
"""
:param owner: SessionPage对象
"""
...
def __call__(self, cookies: Union[CookieJar, Cookie, list, tuple, str, dict]) -> None: ...
def __call__(self, cookies: Union[CookieJar, Cookie, list, tuple, str, dict]) -> None:
"""设置一个或多个cookie
:param cookies: cookies信息
:return: None
"""
...
def remove(self, name: str) -> None: ...
def remove(self, name: str) -> None:
"""删除一个cookie
:param name: cookie的name字段
:return: None
"""
...
def clear(self) -> None: ...
def clear(self) -> None:
"""清除cookies"""
...
class MixPageCookiesSetter(CookiesSetter, SessionCookiesSetter):
_owner: Union[MixPage, MixTab] = ...
def __init__(self, page: SessionPage): ...
def __init__(self, owner: Union[MixPage, MixTab]):
"""
:param owner: MixPage, MixTab对象
"""
...
def __call__(self, cookies: Union[CookieJar, Cookie, list, tuple, str, dict]) -> None: ...
def __call__(self, cookies: Union[CookieJar, Cookie, list, tuple, str, dict]) -> None:
"""设置一个或多个cookie
:param cookies: cookies信息
:return: None
"""
...
def remove(self, name: str, url: str = None, domain: str = None, path: str = None) -> None: ...
def remove(self,
name: str,
url: str = None,
domain: str = None,
path: str = None) -> None:
"""删除一个cookie
:param name: cookie的name字段
:param url: cookie的url字段可选d模式时才有效
:param domain: cookie的domain字段可选d模式时才有效
:param path: cookie的path字段可选d模式时才有效
:return: None
"""
...
def clear(self) -> None: ...
def clear(self) -> None:
"""清除cookies"""
...

View File

@ -16,9 +16,6 @@ from DataRecorder.tools import get_usable_path
class DownloadManager(object):
def __init__(self, browser):
"""
:param browser: Browser对象
"""
self._browser = browser
t = TabDownloadSettings('browser')
@ -35,15 +32,9 @@ class DownloadManager(object):
@property
def missions(self):
"""返回所有未完成的下载任务"""
return self._missions
def set_path(self, tab, path):
"""设置某个tab的下载路径
:param tab: 页面对象
:param path: 下载路径绝对路径str
:return: None
"""
tid = tab if isinstance(tab, str) else tab.tab_id
TabDownloadSettings(tid).path = path
if not self._running or tid == 'browser':
@ -56,53 +47,23 @@ class DownloadManager(object):
self._running = True
def set_rename(self, tab_id, rename=None, suffix=None):
"""设置某个tab的重命名文件名
:param tab_id: tab id
:param rename: 文件名可不含后缀会自动使用远程文件后缀
:param suffix: 后缀名显式设置后缀名不使用远程文件后缀
:return: None
"""
ts = TabDownloadSettings(tab_id)
ts.rename = rename
ts.suffix = suffix
def set_file_exists(self, tab_id, mode):
"""设置某个tab下载文件重名时执行的策略
:param tab_id: tab id
:param mode: 下载路径
:return: None
"""
TabDownloadSettings(tab_id).when_file_exists = mode
def set_flag(self, tab_id, flag):
"""设置某个tab的重命名文件名
:param tab_id: tab id
:param flag: 等待标志
:return: None
"""
self._flags[tab_id] = flag
def get_flag(self, tab_id):
"""获取tab下载等待标记
:param tab_id: tab id
:return: 任务对象或False
"""
return self._flags.get(tab_id, None)
def get_tab_missions(self, tab_id):
"""获取某个tab正在下载的任务
:param tab_id:
:return: 下载任务组成的列表
"""
return self._tab_missions.get(tab_id, [])
def set_done(self, mission, state, final_path=None):
"""设置任务结束
:param mission: 任务对象
:param state: 任务状态
:param final_path: 最终路径
:return: None
"""
if mission.state not in ('canceled', 'skipped'):
mission.state = state
mission.final_path = final_path
@ -112,10 +73,6 @@ class DownloadManager(object):
mission._is_done = True
def cancel(self, mission):
"""取消任务
:param mission: 任务对象
:return: None
"""
mission.state = 'canceled'
try:
self._browser._run_cdp('Browser.cancelDownload', guid=mission.id)
@ -125,10 +82,6 @@ class DownloadManager(object):
Path(mission.final_path).unlink(True)
def skip(self, mission):
"""跳过任务
:param mission: 任务对象
:return: None
"""
mission.state = 'skipped'
try:
self._browser._run_cdp('Browser.cancelDownload', guid=mission.id)
@ -136,17 +89,11 @@ class DownloadManager(object):
pass
def clear_tab_info(self, tab_id):
"""当tab关闭时清除有关信息
:param tab_id: 标签页id
:return: None
"""
self._tab_missions.pop(tab_id, None)
self._flags.pop(tab_id, None)
TabDownloadSettings.TABS.pop(tab_id, None)
def _onDownloadWillBegin(self, **kwargs):
"""用于获取弹出新标签页触发的下载任务"""
# print(kwargs)
guid = kwargs['guid']
tab_id = self._browser._frames.get(kwargs['frameId'], 'browser')
@ -196,7 +143,6 @@ class DownloadManager(object):
self._flags[tab_id] = m
def _onDownloadProgress(self, **kwargs):
"""下载状态变化时执行"""
if kwargs['guid'] in self._missions:
mission = self._missions[kwargs['guid']]
if kwargs['state'] == 'inProgress':
@ -241,9 +187,6 @@ class TabDownloadSettings(object):
return object.__new__(cls)
def __init__(self, tab_id):
"""
:param tab_id: tab id
"""
if hasattr(self, '_created'):
return
self._created = True
@ -258,15 +201,6 @@ class TabDownloadSettings(object):
class DownloadMission(object):
def __init__(self, mgr, tab_id, _id, path, name, url, save_path):
"""
:param mgr: BrowserDownloadManager对象
:param tab_id: 标签页id
:param _id: 任务id
:param path: 保存路径
:param name: 文件名
:param url: url
:param save_path: 下载路径
"""
self._mgr = mgr
self.url = url
self.tab_id = tab_id
@ -285,25 +219,16 @@ class DownloadMission(object):
@property
def rate(self):
"""以百分比形式返回下载进度"""
return round((self.received_bytes / self.total_bytes) * 100, 2) if self.total_bytes else None
@property
def is_done(self):
"""返回任务是否在运行中"""
return self._is_done
def cancel(self):
"""取消该任务,如任务已完成,删除已下载的文件"""
self._mgr.cancel(self)
def wait(self, show=True, timeout=None, cancel_if_timeout=True):
"""等待任务结束
:param show: 是否显示下载信息
:param timeout: 超时时间为None则无限等待
:param cancel_if_timeout: 超时时是否取消任务
:return: 等待成功返回完整路径否则返回False
"""
if show:
print(f'url{self.url}')
end_time = perf_counter()

View File

@ -9,9 +9,10 @@ from typing import Dict, Optional, Union, Literal
from .._base.browser import Chromium
from .._pages.chromium_base import ChromiumBase
# from .._pages.chromium_page import ChromiumPage
FILE_EXISTS = Literal['skip', 'rename', 'overwrite', 's', 'r', 'o']
class DownloadManager(object):
_browser: Chromium = ...
_missions: Dict[str, DownloadMission] = ...
@ -19,34 +20,107 @@ class DownloadManager(object):
_flags: dict = ...
_running: bool = ...
def __init__(self, browser: Chromium): ...
def __init__(self, browser: Chromium):
"""
:param browser: Browser对象
"""
...
@property
def missions(self) -> Dict[str, DownloadMission]: ...
def missions(self) -> Dict[str, DownloadMission]:
"""返回所有未完成的下载任务"""
...
def set_path(self, tab: Union[str,ChromiumBase], path: str) -> None: ...
def set_path(self, tab: Union[str, ChromiumBase], path: str) -> None:
"""设置某个tab的下载路径
:param tab: 页面对象
:param path: 下载路径绝对路径str
:return: None
"""
...
def set_rename(self, tab_id: str, rename: str = None, suffix: str = None) -> None: ...
def set_rename(self,
tab_id: str,
rename: str = None,
suffix: str = None) -> None:
"""设置某个tab的重命名文件名
:param tab_id: tab id
:param rename: 文件名可不含后缀会自动使用远程文件后缀
:param suffix: 后缀名显式设置后缀名不使用远程文件后缀
:return: None
"""
...
def set_file_exists(self, tab_id: str, mode: FILE_EXISTS) -> None: ...
def set_file_exists(self, tab_id: str, mode: FILE_EXISTS) -> None:
"""设置某个tab下载文件重名时执行的策略
:param tab_id: tab id
:param mode: 下载路径
:return: None
"""
...
def set_flag(self, tab_id: str, flag: Union[bool, DownloadMission, None]) -> None: ...
def set_flag(self, tab_id: str, flag: Union[bool, DownloadMission, None]) -> None:
"""设置某个tab的重命名文件名
:param tab_id: tab id
:param flag: 等待标志
:return: None
"""
...
def get_flag(self, tab_id: str) -> Union[bool, DownloadMission, None]: ...
def get_flag(self, tab_id: str) -> Union[bool, DownloadMission, None]:
"""获取tab下载等待标记
:param tab_id: tab id
:return: 任务对象或False
"""
...
def get_tab_missions(self, tab_id: str) -> list: ...
def get_tab_missions(self, tab_id: str) -> list:
"""获取某个tab正在下载的任务
:param tab_id:
:return: 下载任务组成的列表
"""
...
def set_done(self, mission: DownloadMission, state: str, final_path: str = None) -> None: ...
def set_done(self,
mission: DownloadMission,
state: str,
final_path: str = None) -> None:
"""设置任务结束
:param mission: 任务对象
:param state: 任务状态
:param final_path: 最终路径
:return: None
"""
...
def cancel(self, mission: DownloadMission) -> None: ...
def cancel(self, mission: DownloadMission) -> None:
"""取消任务
:param mission: 任务对象
:return: None
"""
...
def skip(self, mission: DownloadMission) -> None: ...
def skip(self, mission: DownloadMission) -> None:
"""跳过任务
:param mission: 任务对象
:return: None
"""
...
def clear_tab_info(self, tab_id: str) -> None: ...
def clear_tab_info(self, tab_id: str) -> None:
"""当tab关闭时清除有关信息
:param tab_id: 标签页id
:return: None
"""
...
def _onDownloadWillBegin(self, **kwargs) -> None: ...
def _onDownloadWillBegin(self, **kwargs) -> None:
"""用于获取弹出新标签页触发的下载任务"""
...
def _onDownloadProgress(self, **kwargs) -> None: ...
def _onDownloadProgress(self, **kwargs) -> None:
"""下载状态变化时执行"""
...
class TabDownloadSettings(object):
@ -58,7 +132,11 @@ class TabDownloadSettings(object):
path: Optional[str] = ...
when_file_exists: str = ...
def __init__(self, tab_id: str): ...
def __init__(self, tab_id: str):
"""
:param tab_id: tab id
"""
...
class DownloadMission(object):
@ -75,15 +153,47 @@ class DownloadMission(object):
save_path: str = ...
_is_done: bool = ...
def __init__(self, mgr: DownloadManager, tab_id: str, _id: str, path: str, name: str, url: str,
save_path: str): ...
def __init__(self,
mgr: DownloadManager,
tab_id: str,
_id: str,
path: str,
name: str,
url: str,
save_path: str):
"""
:param mgr: BrowserDownloadManager对象
:param tab_id: 标签页id
:param _id: 任务id
:param path: 保存路径
:param name: 文件名
:param url: url
:param save_path: 下载路径
"""
...
@property
def rate(self) -> float: ...
def rate(self) -> float:
"""以百分比形式返回下载进度"""
...
@property
def is_done(self) -> bool: ...
def is_done(self) -> bool:
"""返回任务是否在运行中"""
...
def cancel(self) -> None: ...
def cancel(self) -> None:
"""取消该任务,如任务已完成,删除已下载的文件"""
...
def wait(self, show: bool = True, timeout=None, cancel_if_timeout=True) -> Union[bool, str]: ...
def wait(self,
show: bool = True,
timeout=None,
cancel_if_timeout=True) -> Union[bool, str]:
"""等待任务结束
:param show: 是否显示下载信息
:param timeout: 超时时间为None则无限等待
:param cancel_if_timeout: 超时时是否取消任务
:return: 等待成功返回完整路径否则返回False
"""
...

View File

@ -22,9 +22,6 @@ class Listener(object):
"""监听器基类"""
def __init__(self, owner):
"""
:param owner: ChromiumBase对象
"""
self._owner = owner
self._address = owner.browser.address
self._target_id = owner._target_id
@ -41,7 +38,7 @@ class Listener(object):
self._targets = True
self._is_regex = False
self._method = ('GET', 'POST')
self._method = {'GET', 'POST'}
self._res_type = True
@property
@ -50,15 +47,6 @@ class Listener(object):
return self._targets
def set_targets(self, targets=True, is_regex=False, method=('GET', 'POST'), res_type=True):
"""指定要等待的数据包
:param targets: 要匹配的数据包url特征可用list等传入多个为True时获取所有
:param is_regex: 设置的target是否正则表达式
:param method: 设置监听的请求类型可指定多个为True时监听全部
:param res_type: 设置监听的资源类型可指定多个为True时监听全部可指定的值有
Document, Stylesheet, Image, Media, Font, Script, TextTrack, XHR, Fetch, Prefetch, EventSource, WebSocket,
Manifest, SignedExchange, Ping, CSPViolationReport, Preflight, Other
:return: None
"""
if targets is not None:
if not isinstance(targets, (str, list, tuple, set)) and targets is not True:
raise TypeError('targets只能是str、list、tuple、set、True。')
@ -91,15 +79,6 @@ class Listener(object):
raise TypeError('res_type参数只能是str、list、tuple、set、True类型。')
def start(self, targets=None, is_regex=None, method=None, res_type=None):
"""拦截目标请求,每次拦截前清空结果
:param targets: 要匹配的数据包url特征可用list等传入多个为True时获取所有
:param is_regex: 设置的target是否正则表达式为None时保持原来设置
:param method: 设置监听的请求类型可指定多个默认('GET', 'POST')为True时监听全部为None时保持原来设置
:param res_type: 设置监听的资源类型可指定多个默认为True时监听全部为None时保持原来设置可指定的值有
Document, Stylesheet, Image, Media, Font, Script, TextTrack, XHR, Fetch, Prefetch, EventSource, WebSocket,
Manifest, SignedExchange, Ping, CSPViolationReport, Preflight, Other
:return: None
"""
if targets is not None:
if is_regex is None:
is_regex = False
@ -117,13 +96,6 @@ class Listener(object):
self.listening = True
def wait(self, count=1, timeout=None, fit_count=True, raise_err=None):
"""等待符合要求的数据包到达指定数量
:param count: 需要捕捉的数据包数量
:param timeout: 超时时间为None无限等待
:param fit_count: 是否必须满足总数要求发生超时为True返回False为False返回已捕捉到的数据包
:param raise_err: 超时时是否抛出错误为None时根据Settings设置
:return: count为1时返回数据包对象大于1时返回列表超时且fit_count为True时返回False
"""
if not self.listening:
raise RuntimeError('监听未启动或已暂停。')
if not timeout:
@ -157,12 +129,6 @@ class Listener(object):
return [self._caught.get_nowait() for _ in range(count)]
def steps(self, count=None, timeout=None, gap=1):
"""用于单步操作,可实现每收到若干个数据包执行一步操作(如翻页)
:param count: 需捕获的数据包总数为None表示无限
:param timeout: 每个数据包等待时间为None表示无限
:param gap: 每接收到多少个数据包返回一次数据
:return: 用于在接收到监听目标时触发动作的可迭代对象
"""
if not self.listening:
raise RuntimeError('监听未启动或已暂停。')
caught = 0
@ -181,7 +147,6 @@ class Listener(object):
sleep(.03)
def stop(self):
"""停止监听,清空已监听到的列表"""
if self.listening:
self.pause()
self.clear()
@ -189,10 +154,6 @@ class Listener(object):
self._driver = None
def pause(self, clear=True):
"""暂停监听
:param clear: 是否清空已获取队列
:return: None
"""
if self.listening:
self._driver.set_callback('Network.requestWillBeSent', None)
self._driver.set_callback('Network.responseReceived', None)
@ -203,14 +164,12 @@ class Listener(object):
self.clear()
def resume(self):
"""继续暂停的监听"""
if self.listening:
return
self._set_callback()
self.listening = True
def clear(self):
"""清空结果"""
self._request_ids = {}
self._extra_info_ids = {}
self._caught = Queue(maxsize=0)
@ -218,12 +177,6 @@ class Listener(object):
self._running_targets = 0
def wait_silent(self, timeout=None, targets_only=False, limit=0):
"""等待所有请求结束
:param timeout: 超时时间为None时无限等待
:param targets_only: 是否只等待targets指定的请求结束
:param limit: 剩下多少个连接时视为结束
:return: 返回是否等待成功
"""
if not self.listening:
raise RuntimeError('监听未启动或已暂停。')
if timeout is None:
@ -242,12 +195,6 @@ class Listener(object):
return False
def _to_target(self, target_id, address, owner):
"""切换监听的页面对象
:param target_id: 新页面对象_target_id
:param address: 新页面对象address
:param owner: 新页面对象
:return: None
"""
self._target_id = target_id
self._address = address
self._owner = owner
@ -262,7 +209,6 @@ class Listener(object):
self._set_callback()
def _set_callback(self):
"""设置监听请求的回调函数"""
self._driver.set_callback('Network.requestWillBeSent', self._requestWillBeSent)
self._driver.set_callback('Network.requestWillBeSentExtraInfo', self._requestWillBeSentExtraInfo)
self._driver.set_callback('Network.responseReceived', self._response_received)
@ -271,7 +217,6 @@ class Listener(object):
self._driver.set_callback('Network.loadingFailed', self._loading_failed)
def _requestWillBeSent(self, **kwargs):
"""接收到请求时的回调函数"""
self._running_requests += 1
p = None
if self._targets is True:
@ -300,19 +245,16 @@ class Listener(object):
self._extra_info_ids.setdefault(kwargs['requestId'], {})['obj'] = p if p else False
def _requestWillBeSentExtraInfo(self, **kwargs):
"""接收到请求额外信息时的回调函数"""
self._running_requests += 1
self._extra_info_ids.setdefault(kwargs['requestId'], {})['request'] = kwargs
def _response_received(self, **kwargs):
"""接收到返回信息时处理方法"""
request = self._request_ids.get(kwargs['requestId'], None)
if request:
request._raw_response = kwargs['response']
request._resource_type = kwargs['type']
def _responseReceivedExtraInfo(self, **kwargs):
"""接收到返回额外信息时的回调函数"""
self._running_requests -= 1
r = self._extra_info_ids.get(kwargs['requestId'], None)
if r:
@ -327,7 +269,6 @@ class Listener(object):
r['response'] = kwargs
def _loading_finished(self, **kwargs):
"""请求完成时处理方法"""
self._running_requests -= 1
rid = kwargs['requestId']
packet = self._request_ids.get(rid)
@ -363,7 +304,6 @@ class Listener(object):
self._running_targets -= 1
def _loading_failed(self, **kwargs):
"""请求失败时的回调方法"""
self._running_requests -= 1
r_id = kwargs['requestId']
data_packet = self._request_ids.get(r_id, None)
@ -393,26 +333,19 @@ class Listener(object):
class FrameListener(Listener):
def _requestWillBeSent(self, **kwargs):
"""接收到请求时的回调函数"""
if not self._owner._is_diff_domain and kwargs.get('frameId', None) != self._owner._frame_id:
return
super()._requestWillBeSent(**kwargs)
def _response_received(self, **kwargs):
"""接收到返回信息时处理方法"""
if not self._owner._is_diff_domain and kwargs.get('frameId', None) != self._owner._frame_id:
return
super()._response_received(**kwargs)
class DataPacket(object):
"""返回的数据包管理类"""
def __init__(self, tab_id, target):
"""
:param tab_id: 产生这个数据包的tab的id
:param target: 监听目标
"""
self.tab_id = tab_id
self.target = target
self.is_failed = False
@ -479,10 +412,6 @@ class DataPacket(object):
return self._fail_info
def wait_extra_info(self, timeout=None):
"""等待额外的信息加载完成
:param timeout: 超时时间None为无限等待
:return: 是否等待成功
"""
if timeout is None:
while self._responseExtraInfo is None:
sleep(.1)
@ -511,14 +440,12 @@ class Request(object):
@property
def headers(self):
"""以大小写不敏感字典返回headers数据"""
if self._headers is None:
self._headers = CaseInsensitiveDict(self._request['headers'])
return self._headers
@property
def postData(self):
"""返回postData数据"""
if self._postData is None:
if self._raw_post_data:
postData = self._raw_post_data
@ -534,12 +461,10 @@ class Request(object):
@property
def cookies(self):
"""以list形式返回发送的cookies"""
return [c['cookie'] for c in self.extra_info.associatedCookies if not c['blockedReasons']]
@property
def extra_info(self):
"""返回额外数据"""
return RequestExtraInfo(self._data_packet._request_extra_info or {})
@ -557,19 +482,16 @@ class Response(object):
@property
def headers(self):
"""以大小写不敏感字典返回headers数据"""
if self._headers is None:
self._headers = CaseInsensitiveDict(self._response['headers'])
return self._headers
@property
def raw_body(self):
"""返回未被处理的body文本"""
return self._raw_body
@property
def body(self):
"""返回body内容如果是json格式自动进行转换如果时图片格式进行base64转换其它格式直接返回文本"""
if self._body is None:
if self._is_base64_body:
self._body = b64decode(self._raw_body)
@ -593,7 +515,6 @@ class ExtraInfo(object):
@property
def all_info(self):
"""以dict形式返回所有额外信息"""
return self._extra_info
def __getattr__(self, item):

View File

@ -19,21 +19,26 @@ __RES_TYPE__ = Literal['Document', 'Stylesheet', 'Image', 'Media', 'Font', 'Scri
class Listener(object):
_owner: ChromiumBase = ...
_address: str = ...
_target_id: str = ...
_targets: Union[str, dict, True, None] = ...
_method: Union[set, True] = ...
_res_type: Union[set, True] = ...
_caught: Optional[Queue] = ...
_is_regex: bool = ...
_driver: Optional[Driver] = ...
_request_ids: Optional[dict] = ...
_extra_info_ids: Optional[dict] = ...
_running_requests: int = ...
_running_targets: int = ...
listening: bool = ...
def __init__(self, owner: ChromiumBase):
self._owner: ChromiumBase = ...
self._address: str = ...
self._target_id: str = ...
self._targets: Union[str, dict, None] = ...
self._method: set = ...
self._res_type: set = ...
self._caught: Queue = ...
self._is_regex: bool = ...
self._driver: Driver = ...
self._request_ids: dict = ...
self._extra_info_ids: dict = ...
self.listening: bool = ...
self._running_requests: int = ...
self._running_targets: int = ...
"""
:param owner: 页面对象
"""
...
@property
def targets(self) -> Optional[set]: ...
@ -42,42 +47,101 @@ class Listener(object):
targets: Union[str, list, tuple, set, bool, None] = True,
is_regex: Optional[bool] = False,
method: Union[str, list, tuple, set, bool, None] = ('GET', 'POST'),
res_type: Union[__RES_TYPE__, list, tuple, set, bool, None] = True) -> None: ...
res_type: Union[__RES_TYPE__, list, tuple, set, bool, None] = True) -> None:
"""指定要等待的数据包
:param targets: 要匹配的数据包url特征可用list等传入多个为True时获取所有
:param is_regex: 设置的target是否正则表达式
:param method: 设置监听的请求类型可指定多个为True时监听全部
:param res_type: 设置监听的资源类型可指定多个为True时监听全部可指定的值有
Document, Stylesheet, Image, Media, Font, Script, TextTrack, XHR, Fetch, Prefetch, EventSource, WebSocket,
Manifest, SignedExchange, Ping, CSPViolationReport, Preflight, Other
:return: None
"""
...
def start(self,
targets: Union[str, list, tuple, set, bool, None] = None,
is_regex: Optional[bool] = None,
method: Union[str, list, tuple, set, bool, None] = None,
res_type: Union[__RES_TYPE__, list, tuple, set, bool, None] = None) -> None: ...
def stop(self) -> None: ...
def pause(self, clear: bool = True) -> None: ...
def resume(self) -> None: ...
res_type: Union[__RES_TYPE__, list, tuple, set, bool, None] = None) -> None:
"""拦截目标请求,每次拦截前清空结果
:param targets: 要匹配的数据包url特征可用list等传入多个为True时获取所有
:param is_regex: 设置的target是否正则表达式为None时保持原来设置
:param method: 设置监听的请求类型可指定多个默认('GET', 'POST')为True时监听全部为None时保持原来设置
:param res_type: 设置监听的资源类型可指定多个默认为True时监听全部为None时保持原来设置可指定的值有
Document, Stylesheet, Image, Media, Font, Script, TextTrack, XHR, Fetch, Prefetch, EventSource, WebSocket,
Manifest, SignedExchange, Ping, CSPViolationReport, Preflight, Other
:return: None
"""
...
def wait(self,
count: int = 1,
timeout: float = None,
fit_count: bool = True,
raise_err: bool = None) -> Union[List[DataPacket], DataPacket, None]: ...
raise_err: bool = None) -> Union[List[DataPacket], DataPacket, None]:
"""等待符合要求的数据包到达指定数量
:param count: 需要捕捉的数据包数量
:param timeout: 超时时间为None无限等待
:param fit_count: 是否必须满足总数要求发生超时为True返回False为False返回已捕捉到的数据包
:param raise_err: 超时时是否抛出错误为None时根据Settings设置
:return: count为1时返回数据包对象大于1时返回列表超时且fit_count为True时返回False
"""
...
def steps(self,
count: int = None,
timeout: float = None,
gap=1) -> Iterable[Union[DataPacket, List[DataPacket]]]: ...
gap=1) -> Iterable[Union[DataPacket, List[DataPacket]]]:
"""用于单步操作,可实现每收到若干个数据包执行一步操作(如翻页)
:param count: 需捕获的数据包总数为None表示无限
:param timeout: 每个数据包等待时间为None表示无限
:param gap: 每接收到多少个数据包返回一次数据
:return: 用于在接收到监听目标时触发动作的可迭代对象
"""
...
@property
def results(self) -> Union[DataPacket, Dict[str, List[DataPacket]], False]: ...
def stop(self) -> None:
"""停止监听,清空已监听到的列表"""
...
def clear(self) -> None: ...
def pause(self, clear: bool = True) -> None:
"""暂停监听
:param clear: 是否清空已获取队列
:return: None
"""
...
def resume(self) -> None:
"""继续暂停的监听"""
...
def clear(self) -> None:
"""清空监听到但还没返回的结果"""
...
def wait_silent(self,
timeout: float = None,
targets_only: bool = False,
limit: int = 0) -> bool: ...
limit: int = 0) -> bool:
"""等待所有请求结束
:param timeout: 超时时间为None时无限等待
:param targets_only: 是否只等待targets指定的请求结束
:param limit: 剩下多少个连接时视为结束
:return: 返回是否等待成功
"""
...
def _to_target(self, target_id: str, address: str, owner: ChromiumBase) -> None: ...
def _to_target(self, target_id: str, address: str, owner: ChromiumBase) -> None:
"""切换监听的页面对象
:param target_id: 新页面对象_target_id
:param address: 新页面对象address
:param owner: 新页面对象
:return: None
"""
...
def _set_callback(self) -> None: ...
def _requestWillBeSent(self, **kwargs) -> None: ...
@ -91,34 +155,85 @@ class Listener(object):
def _loading_failed(self, **kwargs) -> None: ...
def _set_callback(self) -> None: ...
class FrameListener(Listener):
_owner: ChromiumFrame = ...
_is_diff: bool = ...
def __init__(self, owner: ChromiumFrame):
self._owner: ChromiumFrame = ...
self._is_diff: bool = ...
"""
:param owner: ChromiumFrame对象
"""
...
class DataPacket(object):
"""返回的数据包管理类"""
"""数据包类"""
tab_id: str = ...
target: str = ...
is_failed: bool = ...
_raw_request: Optional[dict] = ...
_raw_response: Optional[dict] = ...
_raw_post_data: Optional[str] = ...
_raw_body: Optional[str] = ...
_raw_fail_info: Optional[dict] = ...
_base64_body: bool = ...
_request: Optional[Request] = ...
_response: Optional[Response] = ...
_fail_info: Optional[FailInfo] = ...
_resource_type: Optional[str] = ...
_requestExtraInfo: Optional[dict] = ...
_responseExtraInfo: Optional[dict] = ...
def __init__(self, tab_id: str, target: [str, bool]):
self.tab_id: str = ...
self.target: str = ...
self.is_failed: bool = ...
self._raw_request: Optional[dict] = ...
self._raw_response: Optional[dict] = ...
self._raw_post_data: str = ...
self._raw_body: str = ...
self._raw_fail_info: Optional[dict] = ...
self._base64_body: bool = ...
self._request: Request = ...
self._response: Response = ...
self._fail_info: Optional[FailInfo] = ...
self._resource_type: str = ...
self._requestExtraInfo: Optional[dict] = ...
self._responseExtraInfo: Optional[dict] = ...
"""
:param tab_id: 产生这个数据包的tab的id
:param target: 监听目标
"""
...
@property
def url(self) -> str:
"""请求网址"""
...
@property
def method(self) -> str:
"""请求类型"""
...
@property
def frameId(self) -> str:
"""发出请求的frame id"""
...
@property
def resourceType(self) -> str:
"""资源类型"""
...
@property
def request(self) -> Request:
"""数据"""
...
@property
def response(self) -> Response:
"""Response数据"""
...
@property
def fail_info(self) -> Optional[FailInfo]:
"""请求失败数据"""
...
def wait_extra_info(self, timeout: float = None) -> bool:
"""等待额外的信息加载完成
:param timeout: 超时时间None为无限等待
:return: 是否等待成功
"""
...
@property
def _request_extra_info(self) -> Optional[dict]: ...
@ -126,116 +241,142 @@ class DataPacket(object):
@property
def _response_extra_info(self) -> Optional[dict]: ...
@property
def url(self) -> str: ...
@property
def method(self) -> str: ...
@property
def frameId(self) -> str: ...
@property
def resourceType(self) -> str: ...
@property
def request(self) -> Request: ...
@property
def response(self) -> Response: ...
@property
def fail_info(self) -> Optional[FailInfo]: ...
def wait_extra_info(self, timeout: float = None) -> bool: ...
class Request(object):
_data_packet: DataPacket = ...
_request: dict = ...
_raw_post_data: str = ...
_postData: Optional[str] = ...
url: str = ...
_headers: Union[CaseInsensitiveDict, None] = ...
method: str = ...
urlFragment = ...
hasPostData = ...
postDataEntries = ...
mixedContentType = ...
initialPriority = ...
referrerPolicy = ...
isLinkPreload = ...
trustTokenParams = ...
isSameSite = ...
urlFragment: str = ...
hasPostData: bool = ...
postDataEntries: List[dict] = ...
mixedContentType: Literal['blockable', 'optionally-blockable', 'none'] = ...
initialPriority: Literal['VeryLow', 'Low', 'Medium', 'High', 'VeryHigh'] = ...
referrerPolicy: Literal['unsafe-url', 'no-referrer-when-downgrade', 'no-referrer', 'origin',
'origin-when-cross-origin', 'same-origin', 'strict-origin', 'strict-origin-when-cross-origin'] = ...
isLinkPreload: bool = ...
trustTokenParams: dict = ...
isSameSite: bool = ...
def __init__(self, data_packet: DataPacket, raw_request: dict, post_data: str):
self._data_packet: DataPacket = ...
self._request: dict = ...
self._raw_post_data: str = ...
self._postData: str = ...
def __init__(self,
data_packet: DataPacket,
raw_request: dict,
post_data: str):
"""
:param data_packet: DataPacket对象
:param raw_request: 未处理的请求数据
:param post_data: post发送的数据
"""
...
@property
def headers(self) -> dict: ...
def headers(self) -> dict:
"""以大小写不敏感字典返回headers数据"""
...
@property
def postData(self) -> Any: ...
def postData(self) -> Any:
"""返回postData数据"""
...
@property
def cookies(self) -> List[dict]: ...
def cookies(self) -> List[dict]:
"""以list形式返回发送的cookies"""
...
@property
def extra_info(self) -> Optional[RequestExtraInfo]: ...
def extra_info(self) -> Optional[RequestExtraInfo]:
"""返回额外数据"""
...
class Response(object):
url = ...
status = ...
statusText = ...
headersText = ...
mimeType = ...
requestHeaders = ...
requestHeadersText = ...
connectionReused = ...
_data_packet: DataPacket = ...
_response: dict = ...
_raw_body: str = ...
_is_base64_body: bool = ...
_body: Union[str, dict, bytes, None] = ...
_headers: Union[dict, CaseInsensitiveDict, None] = ...
url: str = ...
status: int = ...
statusText: str = ...
headersText: str = ...
mimeType: str = ...
requestHeaders: dict = ...
requestHeadersText: str = ...
connectionReused: bool = ...
connectionId = ...
remoteIPAddress = ...
remotePort = ...
fromDiskCache = ...
fromServiceWorker = ...
fromPrefetchCache = ...
encodedDataLength = ...
timing = ...
serviceWorkerResponseSource = ...
responseTime = ...
cacheStorageCacheName = ...
protocol = ...
alternateProtocolUsage = ...
securityState = ...
securityDetails = ...
remoteIPAddress: str = ...
remotePort: int = ...
fromDiskCache: bool = ...
fromServiceWorker: bool = ...
fromPrefetchCache: bool = ...
fromEarlyHints: bool = ...
serviceWorkerRouterInfo: dict = ...
encodedDataLength: int = ...
timing: dict = ...
serviceWorkerResponseSource: Literal['cache-storage', 'http-cache', 'fallback-code', 'network'] = ...
responseTime: float = ...
cacheStorageCacheName: str = ...
protocol: str = ...
alternateProtocolUsage: Literal['alternativeJobWonWithoutRace', 'alternativeJobWonRace', 'mainJobWonRace',
'mappingMissing', 'broken', 'dnsAlpnH3JobWonWithoutRace', 'dnsAlpnH3JobWonRace', 'unspecifiedReason'] = ...
securityState: Literal['unknown', 'neutral', 'insecure', 'secure', 'info', 'insecure-broken'] = ...
securityDetails: dict = ...
def __init__(self, data_packet: DataPacket, raw_response: dict, raw_body: str, base64_body: bool):
self._data_packet: DataPacket = ...
self._response: dict = ...
self._raw_body: str = ...
self._is_base64_body: bool = ...
self._body: Union[str, dict, None] = ...
self._headers: dict = ...
def __init__(self,
data_packet: DataPacket,
raw_response: dict,
raw_body: str,
base64_body: bool):
"""
:param data_packet: DataPacket对象
:param raw_response: 未处理的response信息
:param raw_body: 未处理的body
:param base64_body: body是否base64格式
"""
...
@property
def extra_info(self) -> Optional[ResponseExtraInfo]: ...
def headers(self) -> CaseInsensitiveDict:
"""以大小写不敏感字典返回headers数据"""
...
@property
def headers(self) -> CaseInsensitiveDict: ...
def raw_body(self) -> str:
"""返回未被处理的body文本"""
...
@property
def raw_body(self) -> str: ...
def body(self) -> Any:
"""返回body内容如果是json格式自动进行转换如果时图片格式进行base64转换其它格式直接返回文本"""
...
@property
def body(self) -> Any: ...
def extra_info(self) -> Optional[ResponseExtraInfo]:
"""额外信息"""
...
class ExtraInfo(object):
_extra_info: dict = ...
def __init__(self, extra_info: dict):
self._extra_info: dict = ...
"""
:param extra_info: dict格式信息
"""
...
@property
def all_info(self) -> dict: ...
def all_info(self) -> dict:
"""以dict形式返回所有额外信息"""
...
class RequestExtraInfo(ExtraInfo):
@ -261,10 +402,14 @@ class ResponseExtraInfo(ExtraInfo):
class FailInfo(object):
_data_packet: DataPacket
_fail_info: dict
_fail_info: float
errorText: str
canceled: bool
blockedReason: Optional[str]
corsErrorStatus: Optional[str]
def __init__(self, data_packet: DataPacket, fail_info: dict): ...
def __init__(self, data_packet: DataPacket, fail_info: dict):
"""
:param data_packet: DataPacket对象
:param fail_info: 返回的失败数据
"""
...

View File

@ -9,14 +9,10 @@
class ElementRect(object):
def __init__(self, ele):
"""
:param ele: ChromiumElement
"""
self._ele = ele
@property
def corners(self):
"""返回元素四个角坐标顺序左上、右上、右下、左下没有大小的元素抛出NoRectError"""
vr = self._get_viewport_rect('border')
r = self._ele.owner._run_cdp_loaded('Page.getLayoutMetrics')['visualViewport']
sx = r['pageX']
@ -25,53 +21,44 @@ class ElementRect(object):
@property
def viewport_corners(self):
"""返回元素四个角视口坐标顺序左上、右上、右下、左下没有大小的元素抛出NoRectError"""
r = self._get_viewport_rect('border')
return (r[0], r[1]), (r[2], r[3]), (r[4], r[5]), (r[6], r[7])
@property
def size(self):
"""返回元素大小,格式(宽, 高)"""
border = self._ele.owner._run_cdp('DOM.getBoxModel', backendNodeId=self._ele._backend_id,
nodeId=self._ele._node_id, objectId=self._ele._obj_id)['model']['border']
return border[2] - border[0], border[5] - border[1]
@property
def location(self):
"""返回元素左上角的绝对坐标"""
return self._get_page_coord(*self.viewport_location)
@property
def midpoint(self):
"""返回元素中间点的绝对坐标"""
return self._get_page_coord(*self.viewport_midpoint)
@property
def click_point(self):
"""返回元素接受点击的点的绝对坐标"""
return self._get_page_coord(*self.viewport_click_point)
@property
def viewport_location(self):
"""返回元素左上角在视口中的坐标"""
m = self._get_viewport_rect('border')
return m[0], m[1]
@property
def viewport_midpoint(self):
"""返回元素中间点在视口中的坐标"""
m = self._get_viewport_rect('border')
return m[0] + (m[2] - m[0]) // 2, m[3] + (m[5] - m[3]) // 2
@property
def viewport_click_point(self):
"""返回元素接受点击的点视口坐标"""
m = self._get_viewport_rect('padding')
return self.viewport_midpoint[0], m[1] + 3
@property
def screen_location(self):
"""返回元素左上角在屏幕上坐标,左上角为(0, 0)"""
vx, vy = self._ele.owner.rect.viewport_location
ex, ey = self.viewport_location
pr = self._ele.owner._run_js('return window.devicePixelRatio;')
@ -79,7 +66,6 @@ class ElementRect(object):
@property
def screen_midpoint(self):
"""返回元素中点在屏幕上坐标,左上角为(0, 0)"""
vx, vy = self._ele.owner.rect.viewport_location
ex, ey = self.viewport_midpoint
pr = self._ele.owner._run_js('return window.devicePixelRatio;')
@ -87,7 +73,6 @@ class ElementRect(object):
@property
def screen_click_point(self):
"""返回元素中点在屏幕上坐标,左上角为(0, 0)"""
vx, vy = self._ele.owner.rect.viewport_location
ex, ey = self.viewport_click_point
pr = self._ele.owner._run_js('return window.devicePixelRatio;')
@ -95,20 +80,14 @@ class ElementRect(object):
@property
def scroll_position(self):
"""返回滚动条位置,格式:(x, y)"""
r = self._ele._run_js('return this.scrollLeft.toString() + " " + this.scrollTop.toString();')
w, h = r.split(' ')
return int(w), int(h)
def _get_viewport_rect(self, quad):
"""按照类型返回在可视窗口中的范围
:param quad: 方框类型margin border padding
:return: 四个角坐标
"""
return self._ele.owner._run_cdp('DOM.getBoxModel', backendNodeId=self._ele._backend_id)['model'][quad]
def _get_page_coord(self, x, y):
"""根据视口坐标获取绝对坐标"""
r = self._ele.owner._run_cdp_loaded('Page.getLayoutMetrics')['visualViewport']
sx = r['pageX']
sy = r['pageY']
@ -117,19 +96,14 @@ class ElementRect(object):
class TabRect(object):
def __init__(self, owner):
"""
:param owner: Page对象和Tab对象
"""
self._owner = owner
@property
def window_state(self):
"""返回窗口状态normal、fullscreen、maximized、minimized"""
return self._get_window_rect()['windowState']
@property
def window_location(self):
"""返回窗口在屏幕上的坐标,左上角为(0, 0)"""
r = self._get_window_rect()
if r['windowState'] in ('maximized', 'fullscreen'):
return 0, 0
@ -137,7 +111,6 @@ class TabRect(object):
@property
def window_size(self):
"""返回窗口大小"""
r = self._get_window_rect()
if r['windowState'] == 'fullscreen':
return r['width'], r['height']
@ -148,14 +121,12 @@ class TabRect(object):
@property
def page_location(self):
"""返回页面左上角在屏幕中坐标,左上角为(0, 0)"""
w, h = self.viewport_location
r = self._get_page_rect()['layoutViewport']
return w - r['pageX'], h - r['pageY']
@property
def viewport_location(self):
"""返回视口在屏幕中坐标,左上角为(0, 0)"""
w_bl, h_bl = self.window_location
w_bs, h_bs = self.window_size
w_vs, h_vs = self.viewport_size_with_scrollbar
@ -163,35 +134,29 @@ class TabRect(object):
@property
def size(self):
"""返回页面总宽高,格式:(宽, 高)"""
r = self._get_page_rect()['contentSize']
return r['width'], r['height']
@property
def viewport_size(self):
"""返回视口宽高,不包括滚动条,格式:(宽, 高)"""
r = self._get_page_rect()['visualViewport']
return r['clientWidth'], r['clientHeight']
@property
def viewport_size_with_scrollbar(self):
"""返回视口宽高,包括滚动条,格式:(宽, 高)"""
r = self._owner._run_js('return window.innerWidth.toString() + " " + window.innerHeight.toString();')
w, h = r.split(' ')
return int(w), int(h)
@property
def scroll_position(self):
"""返回滚动条位置,格式:(x, y)"""
r = self._get_page_rect()['visualViewport']
return r['pageX'], r['pageY']
def _get_page_rect(self):
"""获取页面范围信息"""
return self._owner._run_cdp_loaded('Page.getLayoutMetrics')
def _get_window_rect(self):
"""获取窗口范围信息"""
return self._owner.browser._driver.run('Browser.getWindowForTarget', targetId=self._owner.tab_id)['bounds']
@ -199,51 +164,40 @@ class FrameRect(object):
"""异域iframe使用"""
def __init__(self, frame):
"""
:param frame: ChromiumFrame对象
"""
self._frame = frame
@property
def location(self):
"""返回iframe元素左上角的绝对坐标"""
return self._frame.frame_ele.rect.location
@property
def viewport_location(self):
"""返回元素在视口中坐标,左上角为(0, 0)"""
return self._frame.frame_ele.rect.viewport_location
@property
def screen_location(self):
"""返回元素左上角在屏幕上坐标,左上角为(0, 0)"""
return self._frame.frame_ele.rect.screen_location
@property
def size(self):
"""返回frame内页面尺寸格式(宽, 高)"""
w = self._frame.doc_ele._run_js('return this.body.scrollWidth')
h = self._frame.doc_ele._run_js('return this.body.scrollHeight')
return w, h
@property
def viewport_size(self):
"""返回视口宽高,格式:(宽, 高)"""
return self._frame.frame_ele.rect.size
@property
def corners(self):
"""返回元素四个角坐标,顺序:左上、右上、右下、左下"""
return self._frame.frame_ele.rect.corners
@property
def viewport_corners(self):
"""返回元素四个角视口坐标,顺序:左上、右上、右下、左下"""
return self._frame.frame_ele.rect.viewport_corners
@property
def scroll_position(self):
"""返回滚动条位置,格式:(x, y)"""
r = self._frame.doc_ele._run_js('return this.documentElement.scrollLeft.toString() + " " '
'+ this.documentElement.scrollTop.toString();')
w, h = r.split(' ')

View File

@ -17,113 +17,200 @@ from .._pages.mix_page import MixPage
class ElementRect(object):
_ele: ChromiumElement = ...
def __init__(self, ele: ChromiumElement):
self._ele: ChromiumElement = ...
"""
:param ele: ChromiumElement对象
"""
...
@property
def size(self) -> Tuple[float, float]: ...
def corners(self) -> Tuple[Tuple[float, float], ...]:
"""返回元素四个角坐标顺序左上、右上、右下、左下没有大小的元素抛出NoRectError"""
...
@property
def location(self) -> Tuple[float, float]: ...
def viewport_corners(self) -> Tuple[Tuple[float, float], ...]:
"""返回元素四个角视口坐标顺序左上、右上、右下、左下没有大小的元素抛出NoRectError"""
...
@property
def midpoint(self) -> Tuple[float, float]: ...
def size(self) -> Tuple[float, float]:
"""返回元素大小,格式(宽, 高)"""
...
@property
def click_point(self) -> Tuple[float, float]: ...
def location(self) -> Tuple[float, float]:
"""返回元素左上角的绝对坐标"""
...
@property
def viewport_location(self) -> Tuple[float, float]: ...
def midpoint(self) -> Tuple[float, float]:
"""返回元素中间点的绝对坐标"""
...
@property
def viewport_midpoint(self) -> Tuple[float, float]: ...
def click_point(self) -> Tuple[float, float]:
"""返回元素接受点击的点的绝对坐标"""
...
@property
def viewport_click_point(self) -> Tuple[float, float]: ...
def viewport_location(self) -> Tuple[float, float]:
"""返回元素左上角在视口中的坐标"""
...
@property
def screen_location(self) -> Tuple[float, float]: ...
def viewport_midpoint(self) -> Tuple[float, float]:
"""返回元素中间点在视口中的坐标"""
...
@property
def screen_midpoint(self) -> Tuple[float, float]: ...
def viewport_click_point(self) -> Tuple[float, float]:
"""返回元素接受点击的点视口坐标"""
...
@property
def screen_click_point(self) -> Tuple[float, float]: ...
def screen_location(self) -> Tuple[float, float]:
"""返回元素左上角在屏幕上坐标,左上角为(0, 0)"""
...
@property
def corners(self) -> Tuple[Tuple[float, float], ...]: ...
def screen_midpoint(self) -> Tuple[float, float]:
"""返回元素中点在屏幕上坐标,左上角为(0, 0)"""
...
@property
def viewport_corners(self) -> Tuple[Tuple[float, float], ...]: ...
def screen_click_point(self) -> Tuple[float, float]:
"""返回元素中点在屏幕上坐标,左上角为(0, 0)"""
...
@property
def scroll_position(self) -> Tuple[float, float]: ...
def scroll_position(self) -> Tuple[float, float]:
"""返回滚动条位置,格式:(x, y)"""
...
def _get_viewport_rect(self, quad: str) -> Union[list, None]: ...
def _get_viewport_rect(self, quad: str) -> Union[list, None]:
"""按照类型返回在可视窗口中的范围
:param quad: 方框类型margin border padding
:return: 四个角坐标
"""
...
def _get_page_coord(self, x: float, y: float) -> Tuple[float, float]: ...
def _get_page_coord(self, x: float, y: float) -> Tuple[float, float]:
"""根据视口坐标获取绝对坐标
:param x: 视口x坐标
:param y: 视口y坐标
:return: 坐标元组
"""
...
class TabRect(object):
def __init__(self, owner: ChromiumBase):
"""
:param owner: Page对象和Tab对象
"""
self._owner: Union[ChromiumPage, ChromiumTab, MixPage, MixTab] = ...
@property
def window_state(self) -> str: ...
def window_state(self) -> str:
"""返回窗口状态normal、fullscreen、maximized、minimized"""
...
@property
def window_location(self) -> Tuple[int, int]: ...
def window_location(self) -> Tuple[int, int]:
"""返回窗口在屏幕上的坐标,左上角为(0, 0)"""
...
@property
def page_location(self) -> Tuple[int, int]: ...
def window_size(self) -> Tuple[int, int]:
"""返回窗口大小"""
...
@property
def viewport_location(self) -> Tuple[int, int]: ...
def page_location(self) -> Tuple[int, int]:
"""返回页面左上角在屏幕中坐标,左上角为(0, 0)"""
...
@property
def window_size(self) -> Tuple[int, int]: ...
def viewport_location(self) -> Tuple[int, int]:
"""返回视口在屏幕中坐标,左上角为(0, 0)"""
...
@property
def size(self) -> Tuple[int, int]: ...
def size(self) -> Tuple[int, int]:
"""返回页面总宽高,格式:(宽, 高)"""
...
@property
def viewport_size(self) -> Tuple[int, int]: ...
def viewport_size(self) -> Tuple[int, int]:
"""返回视口宽高,不包括滚动条,格式:(宽, 高)"""
...
@property
def viewport_size_with_scrollbar(self) -> Tuple[int, int]: ...
def viewport_size_with_scrollbar(self) -> Tuple[int, int]:
"""返回视口宽高,包括滚动条,格式:(宽, 高)"""
...
@property
def scroll_position(self) -> Tuple[int, int]: ...
def scroll_position(self) -> Tuple[int, int]:
"""返回滚动条位置,格式:(x, y)"""
...
def _get_page_rect(self) -> dict: ...
def _get_page_rect(self) -> dict:
"""获取页面范围信息"""
...
def _get_window_rect(self) -> dict: ...
def _get_window_rect(self) -> dict:
"""获取窗口范围信息"""
...
class FrameRect(object):
_frame: ChromiumFrame = ...
def __init__(self, frame: ChromiumFrame):
self._frame: ChromiumFrame = ...
"""
:param frame: ChromiumFrame对象
"""
...
@property
def location(self) -> Tuple[float, float]: ...
def location(self) -> Tuple[float, float]:
"""返回iframe元素左上角的绝对坐标"""
...
@property
def viewport_location(self) -> Tuple[float, float]: ...
def viewport_location(self) -> Tuple[float, float]:
"""返回元素在视口中坐标,左上角为(0, 0)"""
...
@property
def screen_location(self) -> Tuple[float, float]: ...
def screen_location(self) -> Tuple[float, float]:
"""返回元素左上角在屏幕上坐标,左上角为(0, 0)"""
...
@property
def size(self) -> Tuple[float, float]: ...
def size(self) -> Tuple[float, float]:
"""返回frame内页面尺寸格式(宽, 高)"""
...
@property
def viewport_size(self) -> Tuple[float, float]: ...
def viewport_size(self) -> Tuple[float, float]:
"""返回视口宽高,格式:(宽, 高)"""
...
@property
def corners(self) -> Tuple[Tuple[float, float], ...]: ...
def corners(self) -> Tuple[Tuple[float, float], ...]:
"""返回元素四个角坐标,顺序:左上、右上、右下、左下"""
...
@property
def viewport_corners(self) -> Tuple[Tuple[float, float], ...]: ...
def viewport_corners(self) -> Tuple[Tuple[float, float], ...]:
"""返回元素四个角视口坐标,顺序:左上、右上、右下、左下"""
...
@property
def scroll_position(self) -> Tuple[float, float]: ...
def scroll_position(self) -> Tuple[float, float]:
"""返回滚动条位置,格式:(x, y)"""
...

View File

@ -25,75 +25,48 @@ class Scroller(object):
self._wait_scrolled()
def to_top(self):
"""滚动到顶端,水平位置不变"""
self._run_js('{}.scrollTo({}.scrollLeft, 0);')
return self._owner
def to_bottom(self):
"""滚动到底端,水平位置不变"""
self._run_js('{}.scrollTo({}.scrollLeft, {}.scrollHeight);')
return self._owner
def to_half(self):
"""滚动到垂直中间位置,水平位置不变"""
self._run_js('{}.scrollTo({}.scrollLeft, {}.scrollHeight/2);')
return self._owner
def to_rightmost(self):
"""滚动到最右边,垂直位置不变"""
self._run_js('{}.scrollTo({}.scrollWidth, {}.scrollTop);')
return self._owner
def to_leftmost(self):
"""滚动到最左边,垂直位置不变"""
self._run_js('{}.scrollTo(0, {}.scrollTop);')
return self._owner
def to_location(self, x, y):
"""滚动到指定位置
:param x: 水平距离
:param y: 垂直距离
:return: None
"""
self._run_js(f'{{}}.scrollTo({x}, {y});')
return self._owner
def up(self, pixel=300):
"""向上滚动若干像素,水平位置不变
:param pixel: 滚动的像素
:return: None
"""
pixel = -pixel
self._run_js(f'{{}}.scrollBy(0, {pixel});')
return self._owner
def down(self, pixel=300):
"""向下滚动若干像素,水平位置不变
:param pixel: 滚动的像素
:return: None
"""
self._run_js(f'{{}}.scrollBy(0, {pixel});')
return self._owner
def left(self, pixel=300):
"""向左滚动若干像素,垂直位置不变
:param pixel: 滚动的像素
:return: None
"""
pixel = -pixel
self._run_js(f'{{}}.scrollBy({pixel}, 0);')
return self._owner
def right(self, pixel=300):
"""向右滚动若干像素,垂直位置不变
:param pixel: 滚动的像素
:return: None
"""
self._run_js(f'{{}}.scrollBy({pixel}, 0);')
return self._owner
def _wait_scrolled(self):
"""等待滚动结束"""
if not self._wait_complete:
return
@ -118,44 +91,26 @@ class Scroller(object):
class ElementScroller(Scroller):
def to_see(self, center=None):
"""滚动页面直到元素可见
:param center: 是否尽量滚动到页面正中为None时如果被遮挡则滚动到页面正中
:return: None
"""
self._owner.owner.scroll.to_see(self._owner, center=center)
return self._owner
def to_center(self):
"""元素尽量滚动到视口中间"""
self._owner.owner.scroll.to_see(self._owner, center=True)
return self._owner
class PageScroller(Scroller):
def __init__(self, owner):
"""
:param owner: 页面对象
"""
super().__init__(owner)
self._t1 = 'window'
self._t2 = 'document.documentElement'
def to_see(self, loc_or_ele, center=None):
"""滚动页面直到元素可见
:param loc_or_ele: 元素的定位信息可以是loc元组或查询字符串
:param center: 是否尽量滚动到页面正中为None时如果被遮挡则滚动到页面正中
:return: None
"""
ele = self._owner._ele(loc_or_ele)
self._to_see(ele, center)
return self._owner
def _to_see(self, ele, center):
"""执行滚动页面直到元素可见
:param ele: 元素对象
:param center: 是否尽量滚动到页面正中为None时如果被遮挡则滚动到页面正中
:return: None
"""
txt = 'true' if center else 'false'
ele._run_js(f'this.scrollIntoViewIfNeeded({txt});')
if center or (center is not False and ele.states.is_covered):
@ -173,19 +128,14 @@ class PageScroller(Scroller):
class FrameScroller(PageScroller):
def __init__(self, frame):
def __init__(self, owner):
"""
:param frame: ChromiumFrame对象
:param owner: ChromiumFrame对象
"""
super().__init__(frame.doc_ele)
super().__init__(owner.doc_ele)
self._t1 = self._t2 = 'this.documentElement'
def to_see(self, loc_or_ele, center=None):
"""滚动页面直到元素可见
:param loc_or_ele: 元素的定位信息可以是loc元组或查询字符串
:param center: 是否尽量滚动到页面正中为None时如果被遮挡则滚动到页面正中
:return: None
"""
ele = self._owner._ele(loc_or_ele)
self._to_see(ele, center)
return self._owner

View File

@ -16,116 +16,304 @@ from .._pages.tabs import ChromiumTab, MixTab
class Scroller(object):
_owner: Union[ChromiumBase, ChromiumElement] = ...
_t1: str = ...
_t2: str = ...
_owner: Union[ChromiumBase, ChromiumElement] = ...
_wait_complete: bool = ...
def __init__(self, owner: Union[ChromiumBase, ChromiumElement]): ...
def to_top(self) -> None:
"""滚动到顶端,水平位置不变"""
...
def to_bottom(self) -> None:
"""滚动到底端,水平位置不变"""
...
def to_half(self) -> None:
"""滚动到垂直中间位置,水平位置不变"""
...
def to_rightmost(self) -> None:
"""滚动到最右边,垂直位置不变"""
...
def to_leftmost(self) -> None:
"""滚动到最左边,垂直位置不变"""
...
def to_location(self, x: int, y: int) -> None:
"""滚动到指定位置
:param x: 水平距离
:param y: 垂直距离
:return: None
"""
...
def up(self, pixel: int = 300) -> None:
"""向上滚动若干像素,水平位置不变
:param pixel: 滚动的像素
:return: None
"""
...
def down(self, pixel: int = 300) -> None:
"""向下滚动若干像素,水平位置不变
:param pixel: 滚动的像素
:return: None
"""
...
def left(self, pixel: int = 300) -> None:
"""向左滚动若干像素,垂直位置不变
:param pixel: 滚动的像素
:return: None
"""
...
def right(self, pixel: int = 300) -> None:
"""向右滚动若干像素,垂直位置不变
:param pixel: 滚动的像素
:return: None
"""
...
def _run_js(self, js: str): ...
def to_top(self) -> None: ...
def to_bottom(self) -> None: ...
def to_half(self) -> None: ...
def to_rightmost(self) -> None: ...
def to_leftmost(self) -> None: ...
def to_location(self, x: int, y: int) -> None: ...
def up(self, pixel: int = 300) -> None: ...
def down(self, pixel: int = 300) -> None: ...
def left(self, pixel: int = 300) -> None: ...
def right(self, pixel: int = 300) -> None: ...
def _wait_scrolled(self) -> None: ...
def _wait_scrolled(self) -> None:
"""等待滚动结束"""
...
class ElementScroller(Scroller):
_owner: ChromiumElement = ...
def to_see(self, center: Union[bool, None] = None) -> ChromiumElement: ...
def __init__(self, owner: ChromiumElement):
"""
:param owner: 元素对象
"""
...
def to_center(self) -> ChromiumElement: ...
def to_see(self, center: Union[bool, None] = None) -> ChromiumElement:
"""滚动页面直到元素可见
:param center: 是否尽量滚动到页面正中为None时如果被遮挡则滚动到页面正中
:return: None
"""
...
def to_top(self) -> ChromiumElement: ...
def to_center(self) -> ChromiumElement:
"""元素尽量滚动到视口中间"""
...
def to_bottom(self) -> ChromiumElement: ...
def to_top(self) -> ChromiumElement:
"""滚动到顶端,水平位置不变"""
...
def to_half(self) -> ChromiumElement: ...
def to_bottom(self) -> ChromiumElement:
"""滚动到底端,水平位置不变"""
...
def to_rightmost(self) -> ChromiumElement: ...
def to_half(self) -> ChromiumElement:
"""滚动到垂直中间位置,水平位置不变"""
...
def to_leftmost(self) -> ChromiumElement: ...
def to_rightmost(self) -> ChromiumElement:
"""滚动到最右边,垂直位置不变"""
...
def to_location(self, x: int, y: int) -> ChromiumElement: ...
def to_leftmost(self) -> ChromiumElement:
"""滚动到最左边,垂直位置不变"""
...
def up(self, pixel: int = 300) -> ChromiumElement: ...
def to_location(self, x: int, y: int) -> ChromiumElement:
"""滚动到指定位置
:param x: 水平距离
:param y: 垂直距离
:return: None
"""
...
def down(self, pixel: int = 300) -> ChromiumElement: ...
def up(self, pixel: int = 300) -> ChromiumElement:
"""向上滚动若干像素,水平位置不变
:param pixel: 滚动的像素
:return: None
"""
...
def left(self, pixel: int = 300) -> ChromiumElement: ...
def down(self, pixel: int = 300) -> ChromiumElement:
"""向下滚动若干像素,水平位置不变
:param pixel: 滚动的像素
:return: None
"""
...
def right(self, pixel: int = 300) -> ChromiumElement: ...
def left(self, pixel: int = 300) -> ChromiumElement:
"""向左滚动若干像素,垂直位置不变
:param pixel: 滚动的像素
:return: None
"""
...
def right(self, pixel: int = 300) -> ChromiumElement:
"""向右滚动若干像素,垂直位置不变
:param pixel: 滚动的像素
:return: None
"""
...
class PageScroller(Scroller):
def __init__(self, owner: Union[ChromiumBase, ChromiumElement]): ...
_owner: Union[ChromiumBase, ChromiumElement] = ...
def __init__(self, owner: Union[ChromiumBase, ChromiumElement]):
"""
:param owner: 页面对象
"""
...
def to_see(self,
loc_or_ele: Union[str, tuple, ChromiumElement],
center: Union[bool, None] = None) -> Union[ChromiumTab, MixTab, ChromiumPage, MixPage]: ...
center: Union[bool, None] = None) -> Union[ChromiumTab, MixTab, ChromiumPage, MixPage]:
"""滚动页面直到元素可见
:param loc_or_ele: 元素的定位信息可以是loc元组或查询字符串
:param center: 是否尽量滚动到页面正中为None时如果被遮挡则滚动到页面正中
:return: None
"""
...
def to_top(self) -> Union[ChromiumTab, MixTab, ChromiumPage, MixPage]: ...
def to_top(self) -> Union[ChromiumTab, MixTab, ChromiumPage, MixPage]:
"""滚动到顶端,水平位置不变"""
...
def to_bottom(self) -> Union[ChromiumTab, MixTab, ChromiumPage, MixPage]: ...
def to_bottom(self) -> Union[ChromiumTab, MixTab, ChromiumPage, MixPage]:
"""滚动到底端,水平位置不变"""
...
def to_half(self) -> Union[ChromiumTab, MixTab, ChromiumPage, MixPage]: ...
def to_half(self) -> Union[ChromiumTab, MixTab, ChromiumPage, MixPage]:
"""滚动到垂直中间位置,水平位置不变"""
...
def to_rightmost(self) -> Union[ChromiumTab, MixTab, ChromiumPage, MixPage]: ...
def to_rightmost(self) -> Union[ChromiumTab, MixTab, ChromiumPage, MixPage]:
"""滚动到最右边,垂直位置不变"""
...
def to_leftmost(self) -> Union[ChromiumTab, MixTab, ChromiumPage, MixPage]: ...
def to_leftmost(self) -> Union[ChromiumTab, MixTab, ChromiumPage, MixPage]:
"""滚动到最左边,垂直位置不变"""
...
def to_location(self, x: int, y: int) -> Union[ChromiumTab, MixTab, ChromiumPage, MixPage]: ...
def to_location(self, x: int, y: int) -> Union[ChromiumTab, MixTab, ChromiumPage, MixPage]:
"""滚动到指定位置
:param x: 水平距离
:param y: 垂直距离
:return: None
"""
...
def up(self, pixel: int = 300) -> Union[ChromiumTab, MixTab, ChromiumPage, MixPage]: ...
def up(self, pixel: int = 300) -> Union[ChromiumTab, MixTab, ChromiumPage, MixPage]:
"""向上滚动若干像素,水平位置不变
:param pixel: 滚动的像素
:return: None
"""
...
def down(self, pixel: int = 300) -> Union[ChromiumTab, MixTab, ChromiumPage, MixPage]: ...
def down(self, pixel: int = 300) -> Union[ChromiumTab, MixTab, ChromiumPage, MixPage]:
"""向下滚动若干像素,水平位置不变
:param pixel: 滚动的像素
:return: None
"""
...
def left(self, pixel: int = 300) -> Union[ChromiumTab, MixTab, ChromiumPage, MixPage]: ...
def left(self, pixel: int = 300) -> Union[ChromiumTab, MixTab, ChromiumPage, MixPage]:
"""向左滚动若干像素,垂直位置不变
:param pixel: 滚动的像素
:return: None
"""
...
def right(self, pixel: int = 300) -> Union[ChromiumTab, MixTab, ChromiumPage, MixPage]: ...
def right(self, pixel: int = 300) -> Union[ChromiumTab, MixTab, ChromiumPage, MixPage]:
"""向右滚动若干像素,垂直位置不变
:param pixel: 滚动的像素
:return: None
"""
...
def _to_see(self, ele: ChromiumElement, center: Union[bool, None]) -> None: ...
def _to_see(self, ele: ChromiumElement, center: Union[bool, None]) -> None:
"""执行滚动页面直到元素可见
:param ele: 元素对象
:param center: 是否尽量滚动到页面正中为None时如果被遮挡则滚动到页面正中
:return: None
"""
...
class FrameScroller(PageScroller):
def __init__(self, frame: ChromiumFrame): ...
_owner: ChromiumElement = ...
def to_top(self) -> ChromiumFrame: ...
def __init__(self, owner: ChromiumFrame): ...
def to_bottom(self) -> ChromiumFrame: ...
def to_see(self,
loc_or_ele: Union[str, tuple, ChromiumElement],
center: Union[bool, None] = None) -> ChromiumFrame:
"""滚动页面直到元素可见
:param loc_or_ele: 元素的定位信息可以是loc元组或查询字符串
:param center: 是否尽量滚动到页面正中为None时如果被遮挡则滚动到页面正中
:return: None
"""
...
def to_half(self) -> ChromiumFrame: ...
def to_top(self) -> ChromiumFrame:
"""滚动到顶端,水平位置不变"""
...
def to_rightmost(self) -> ChromiumFrame: ...
def to_bottom(self) -> ChromiumFrame:
"""滚动到底端,水平位置不变"""
...
def to_leftmost(self) -> ChromiumFrame: ...
def to_half(self) -> ChromiumFrame:
"""滚动到垂直中间位置,水平位置不变"""
...
def to_location(self, x: int, y: int) -> ChromiumFrame: ...
def to_rightmost(self) -> ChromiumFrame:
"""滚动到最右边,垂直位置不变"""
...
def up(self, pixel: int = 300) -> ChromiumFrame: ...
def to_leftmost(self) -> ChromiumFrame:
"""滚动到最左边,垂直位置不变"""
...
def down(self, pixel: int = 300) -> ChromiumFrame: ...
def to_location(self, x: int, y: int) -> ChromiumFrame:
"""滚动到指定位置
:param x: 水平距离
:param y: 垂直距离
:return: None
"""
...
def left(self, pixel: int = 300) -> ChromiumFrame: ...
def up(self, pixel: int = 300) -> ChromiumFrame:
"""向上滚动若干像素,水平位置不变
:param pixel: 滚动的像素
:return: None
"""
...
def right(self, pixel: int = 300) -> ChromiumFrame: ...
def down(self, pixel: int = 300) -> ChromiumFrame:
"""向下滚动若干像素,水平位置不变
:param pixel: 滚动的像素
:return: None
"""
...
def to_see(self, loc_or_ele, center=None) -> ChromiumFrame: ...
def left(self, pixel: int = 300) -> ChromiumFrame:
"""向左滚动若干像素,垂直位置不变
:param pixel: 滚动的像素
:return: None
"""
...
def right(self, pixel: int = 300) -> ChromiumFrame:
"""向右滚动若干像素,垂直位置不变
:param pixel: 滚动的像素
:return: None
"""
...

View File

@ -12,57 +12,38 @@ class SelectElement(object):
"""用于处理 select 标签"""
def __init__(self, ele):
"""
:param ele: select 元素对象
"""
if ele.tag != 'select':
raise TypeError("select方法只能在<select>元素使用。")
self._ele = ele
def __call__(self, text_or_index, timeout=None):
"""选定下拉列表中子元素
:param text_or_index: 根据文本值选或序号择选项若允许多选传入list或tuple可多选
:param timeout: 超时时间不输入默认实用页面超时时间
:return: None
"""
para_type = 'index' if isinstance(text_or_index, int) else 'text'
timeout = timeout if timeout is not None else self._ele.owner.timeout
return self._select(text_or_index, para_type, timeout=timeout)
@property
def is_multi(self):
"""返回是否多选表单"""
return self._ele.attr('multiple') is not None
@property
def options(self):
"""返回所有选项元素组成的列表"""
return [i for i in self._ele.eles('xpath://option') if not isinstance(i, int)]
@property
def selected_option(self):
"""返回第一个被选中的option元素
:return: ChromiumElement对象或None
"""
ele = self._ele._run_js('return this.options[this.selectedIndex];')
return ele
@property
def selected_options(self):
"""返回所有被选中的option元素列表
:return: ChromiumElement对象组成的列表
"""
return [x for x in self.options if x.states.is_selected]
def all(self):
"""全选"""
if not self.is_multi:
raise TypeError("只能在多选菜单执行此操作。")
return self._by_loc('tag:option', 1, False)
def invert(self):
"""反选"""
if not self.is_multi:
raise TypeError("只能对多项选框执行反选。")
change = False
@ -74,96 +55,41 @@ class SelectElement(object):
self._dispatch_change()
def clear(self):
"""清除所有已选项"""
if not self.is_multi:
raise TypeError("只能在多选菜单执行此操作。")
return self._by_loc('tag:option', 1, True)
def by_text(self, text, timeout=None):
"""此方法用于根据text值选择项。当元素是多选列表时可以接收list或tuple
:param text: text属性值传入list或tuple可选择多项
:param timeout: 超时时间为None默认使用页面超时时间
:return: 是否选择成功
"""
return self._select(text, 'text', False, timeout)
def by_value(self, value, timeout=None):
"""此方法用于根据value值选择项。当元素是多选列表时可以接收list或tuple
:param value: value属性值传入list或tuple可选择多项
:param timeout: 超时时间为None默认使用页面超时时间
:return: 是否选择成功
"""
return self._select(value, 'value', False, timeout)
def by_index(self, index, timeout=None):
"""此方法用于根据index值选择项。当元素是多选列表时可以接收list或tuple
:param index: 序号从1开始可传入负数获取倒数第几个传入list或tuple可选择多项
:param timeout: 超时时间为None默认使用页面超时时间
:return: 是否选择成功
"""
return self._select(index, 'index', False, timeout)
def by_locator(self, locator, timeout=None):
"""用定位符选择指定的项
:param locator: 定位符
:param timeout: 超时时间
:return: 是否选择成功
"""
return self._by_loc(locator, timeout)
def by_option(self, option):
"""选中单个或多个option元素
:param option: option元素或它们组成的列表
:return: None
"""
self._select_options(option, 'true')
def cancel_by_text(self, text, timeout=None):
"""此方法用于根据text值取消选择项。当元素是多选列表时可以接收list或tuple
:param text: 文本传入list或tuple可取消多项
:param timeout: 超时时间不输入默认实用页面超时时间
:return: 是否取消成功
"""
return self._select(text, 'text', True, timeout)
def cancel_by_value(self, value, timeout=None):
"""此方法用于根据value值取消选择项。当元素是多选列表时可以接收list或tuple
:param value: value属性值传入list或tuple可取消多项
:param timeout: 超时时间不输入默认实用页面超时时间
:return: 是否取消成功
"""
return self._select(value, 'value', True, timeout)
def cancel_by_index(self, index, timeout=None):
"""此方法用于根据index值取消选择项。当元素是多选列表时可以接收list或tuple
:param index: 序号从1开始可传入负数获取倒数第几个传入list或tuple可取消多项
:param timeout: 超时时间不输入默认实用页面超时时间
:return: 是否取消成功
"""
return self._select(index, 'index', True, timeout)
def cancel_by_locator(self, locator, timeout=None):
"""用定位符取消选择指定的项
:param locator: 定位符
:param timeout: 超时时间
:return: 是否选择成功
"""
return self._by_loc(locator, timeout, True)
def cancel_by_option(self, option):
"""取消选中单个或多个option元素
:param option: option元素或它们组成的列表
:return: None
"""
self._select_options(option, 'false')
def _by_loc(self, loc, timeout=None, cancel=False):
"""用定位符取消选择指定的项
:param loc: 定位符
:param timeout: 超时时间
:param cancel: 是否取消选择
:return: 是否选择成功
"""
eles = self._ele.eles(loc, timeout)
if not eles:
return False
@ -176,12 +102,6 @@ class SelectElement(object):
return True
def _select(self, condition, para_type='text', cancel=False, timeout=None):
"""选定或取消选定下拉列表中子元素
:param condition: 根据文本值选或序号择选项若允许多选传入list或tuple可多选
:param para_type: 参数类型可选 'text''value''index'
:param cancel: 是否取消选择
:return: 是否选择成功
"""
if not self.is_multi and isinstance(condition, (list, tuple)):
raise TypeError('单选列表只能传入str格式。')
@ -195,13 +115,6 @@ class SelectElement(object):
return self._index(condition, mode, timeout)
def _text_value(self, condition, para_type, mode, timeout):
"""执行text和value搜索
:param condition: 条件set
:param para_type: 参数类型可选 'text''value'
:param mode: 'true' 'false'
:param timeout: 超时时间
:return: 是否选择成功
"""
ok = False
text_len = len(condition)
eles = []
@ -224,12 +137,6 @@ class SelectElement(object):
return False
def _index(self, condition, mode, timeout):
"""执行index搜索
:param condition: 条件set
:param mode: 'true' 'false'
:param timeout: 超时时间
:return: 是否选择成功
"""
ok = False
condition = [int(i) for i in condition]
text_len = abs(max(condition, key=abs))
@ -249,11 +156,6 @@ class SelectElement(object):
return False
def _select_options(self, option, mode):
"""选中或取消某个选项
:param option: options元素对象
:param mode: 选中还是取消
:return: None
"""
if isinstance(option, (list, tuple, set)):
if not self.is_multi and len(option) > 1:
option = option[:1]
@ -265,5 +167,4 @@ class SelectElement(object):
self._dispatch_change()
def _dispatch_change(self):
"""触发修改动作"""
self._ele._run_js('this.dispatchEvent(new CustomEvent("change", {bubbles: true}));')

View File

@ -5,69 +5,213 @@
@Copyright: (c) 2024 by g1879, Inc. All Rights Reserved.
@License : BSD 3-Clause.
"""
from typing import Union, Tuple, List
from typing import Union, Tuple, List, Optional
from .._elements.chromium_element import ChromiumElement
class SelectElement(object):
_ele: ChromiumElement = ...
def __init__(self, ele: ChromiumElement):
self._ele: ChromiumElement = ...
"""
:param ele: <select>元素对象
"""
...
def __call__(self, text_or_index: Union[str, int, list, tuple], timeout: float = None) -> bool: ...
def __call__(self,
text_or_index: Union[str, int, list, tuple],
timeout: float = None) -> bool:
"""选定下拉列表中子元素
:param text_or_index: 根据文本值选或序号择选项若允许多选传入list或tuple可多选
:param timeout: 超时时间不输入默认实用页面超时时间
:return: None
"""
...
@property
def is_multi(self) -> bool: ...
def is_multi(self) -> bool:
"""返回是否多选表单"""
...
@property
def options(self) -> List[ChromiumElement]: ...
def options(self) -> List[ChromiumElement]:
"""返回所有选项元素组成的列表"""
...
@property
def selected_option(self) -> Union[ChromiumElement, None]: ...
def selected_option(self) -> Optional[ChromiumElement]:
"""返回第一个被选中的<option>元素"""
...
@property
def selected_options(self) -> List[ChromiumElement]: ...
def selected_options(self) -> List[ChromiumElement]:
"""返回所有被选中的<option>元素列表"""
...
def clear(self) -> None: ...
def all(self) -> None:
"""全选"""
...
def all(self) -> None: ...
def invert(self) -> None:
"""反选"""
...
def by_text(self, text: Union[str, list, tuple], timeout: float = None) -> bool: ...
def clear(self) -> None:
"""清除所有已选项"""
...
def by_value(self, value: Union[str, list, tuple], timeout: float = None) -> bool: ...
def by_text(self,
text: Union[str, list, tuple],
timeout: float = None) -> bool:
"""此方法用于根据text值选择项。当元素是多选列表时可以接收list或tuple
:param text: text属性值传入list或tuple可选择多项
:param timeout: 超时时间为None默认使用页面超时时间
:return: 是否选择成功
"""
...
def by_index(self, index: Union[int, list, tuple], timeout: float = None) -> bool: ...
def by_value(self,
value: Union[str, list, tuple],
timeout: float = None) -> bool:
"""此方法用于根据value值选择项。当元素是多选列表时可以接收list或tuple
:param value: value属性值传入list或tuple可选择多项
:param timeout: 超时时间为None默认使用页面超时时间
:return: 是否选择成功
"""
...
def by_locator(self, locator: Union[Tuple[str, str], str], timeout: float = None) -> bool: ...
def by_index(self,
index: Union[int, list, tuple],
timeout: float = None) -> bool:
"""此方法用于根据index值选择项。当元素是多选列表时可以接收list或tuple
:param index: 序号从1开始可传入负数获取倒数第几个传入list或tuple可选择多项
:param timeout: 超时时间为None默认使用页面超时时间
:return: 是否选择成功
"""
...
def by_option(self, option: Union[ChromiumElement, List[ChromiumElement], Tuple[ChromiumElement]]) -> None: ...
def by_locator(self,
locator: Union[Tuple[str, str], str],
timeout: float = None) -> bool:
"""用定位符选择指定的项
:param locator: 定位符
:param timeout: 超时时间
:return: 是否选择成功
"""
...
def cancel_by_text(self, text: Union[str, list, tuple], timeout: float = None) -> bool: ...
def by_option(self, option: Union[ChromiumElement, List[ChromiumElement], Tuple[ChromiumElement]]) -> None:
"""选中单个或多个<option>元素
:param option: <option>元素或它们组成的列表
:return: None
"""
...
def cancel_by_value(self, value: Union[str, list, tuple], timeout: float = None) -> bool: ...
def cancel_by_text(self,
text: Union[str, list, tuple],
timeout: float = None) -> bool:
"""此方法用于根据text值取消选择项。当元素是多选列表时可以接收list或tuple
:param text: 文本传入list或tuple可取消多项
:param timeout: 超时时间不输入默认实用页面超时时间
:return: 是否取消成功
"""
...
def cancel_by_index(self, index: Union[int, list, tuple], timeout: float = None) -> bool: ...
def cancel_by_value(self,
value: Union[str, list, tuple],
timeout: float = None) -> bool:
"""此方法用于根据value值取消选择项。当元素是多选列表时可以接收list或tuple
:param value: value属性值传入list或tuple可取消多项
:param timeout: 超时时间不输入默认实用页面超时时间
:return: 是否取消成功
"""
...
def cancel_by_locator(self, locator: Union[Tuple[str, str], str], timeout: float = None) -> bool: ...
def cancel_by_index(self,
index: Union[int, list, tuple],
timeout: float = None) -> bool:
"""此方法用于根据index值取消选择项。当元素是多选列表时可以接收list或tuple
:param index: 序号从1开始可传入负数获取倒数第几个传入list或tuple可取消多项
:param timeout: 超时时间不输入默认实用页面超时时间
:return: 是否取消成功
"""
...
def cancel_by_locator(self,
locator: Union[Tuple[str, str], str],
timeout: float = None) -> bool:
"""用定位符取消选择指定的项
:param locator: 定位符
:param timeout: 超时时间
:return: 是否选择成功
"""
...
def cancel_by_option(self,
option: Union[ChromiumElement, List[ChromiumElement], Tuple[ChromiumElement]]) -> None: ...
option: Union[ChromiumElement, List[ChromiumElement], Tuple[ChromiumElement]]) -> None:
"""取消选中单个或多个<option>元素
:param option: <option>元素或它们组成的列表
:return: None
"""
...
def invert(self) -> None: ...
def _by_loc(self, loc: Union[str, Tuple[str, str]], timeout: float = None, cancel: bool = False) -> bool: ...
def _by_loc(self,
loc: Union[str, Tuple[str, str]],
timeout: float = None,
cancel: bool = False) -> bool:
"""用定位符取消选择指定的项
:param loc: 定位符
:param timeout: 超时时间
:param cancel: 是否取消选择
:return: 是否选择成功
"""
...
def _select(self,
condition: Union[str, int, list, tuple] = None,
para_type: str = 'text',
cancel: bool = False,
timeout: float = None) -> bool: ...
timeout: float = None) -> bool:
"""选定或取消选定下拉列表中子元素
:param condition: 根据文本值选或序号择选项若允许多选传入list或tuple可多选
:param para_type: 参数类型可选 'text''value''index'
:param cancel: 是否取消选择
:return: 是否选择成功
"""
...
def _text_value(self, condition: Union[list, set], para_type: str, mode: str, timeout: float) -> bool: ...
def _text_value(self,
condition: Union[list, set],
para_type: str,
mode: str,
timeout: float) -> bool:
"""执行text和value搜索
:param condition: 条件set
:param para_type: 参数类型可选 'text''value'
:param mode: 'true' 'false'
:param timeout: 超时时间
:return: 是否选择成功
"""
...
def _index(self, condition: set, mode: str, timeout: float) -> bool: ...
def _index(self, condition: set, mode: str, timeout: float) -> bool:
"""执行index搜索
:param condition: 条件set
:param mode: 'true' 'false'
:param timeout: 超时时间
:return: 是否选择成功
"""
...
def _select_options(self, option: Union[ChromiumElement, List[ChromiumElement], Tuple[ChromiumElement]],
mode: str) -> None: ...
mode: str) -> None:
"""选中或取消某个选项
:param option: options元素对象
:param mode: 选中还是取消
:return: None
"""
...
def _dispatch_change(self) -> None: ...
def _dispatch_change(self) -> None:
"""触发修改动作"""
...

View File

@ -19,33 +19,19 @@ from ..errors import ElementLostError, JavaScriptError
class BaseSetter(object):
def __init__(self, owner):
"""
:param owner: BasePage对象
"""
self._owner = owner
def NoneElement_value(self, value=None, on_off=True):
"""设置空元素是否返回设定值
:param value: 返回的设定值
:param on_off: 是否启用
:return: None
"""
self._owner._none_ele_return_value = on_off
self._owner._none_ele_value = value
def retry_times(self, times):
"""设置连接失败重连次数"""
self._owner.retry_times = times
def retry_interval(self, interval):
"""设置连接失败重连间隔"""
self._owner.retry_interval = interval
def download_path(self, path):
"""设置下载路径
:param path: 下载路径
:return: None
"""
if path is None:
path = '.'
self._owner._download_path = str(Path(path).absolute())
@ -61,130 +47,61 @@ class SessionPageSetter(BaseSetter):
@property
def cookies(self):
"""返回用于设置cookies的对象"""
if self._cookies_setter is None:
self._cookies_setter = SessionCookiesSetter(self._owner)
return self._cookies_setter
def download_path(self, path):
"""设置下载路径
:param path: 下载路径
:return: None
"""
super().download_path(path)
if self._owner._DownloadKit:
self._owner._DownloadKit.set.goal_path(self._owner._download_path)
def timeout(self, second):
"""设置连接超时时间
:param second: 秒数
:return: None
"""
self._owner._timeout = second
def encoding(self, encoding, set_all=True):
"""设置编码
:param encoding: 编码名称如果要取消之前的设置传入None
:param set_all: 是否设置对象参数为False则只设置当前Response
:return: None
"""
if set_all:
self._owner._encoding = encoding if encoding else None
if self._owner.response:
self._owner.response.encoding = encoding
def headers(self, headers):
"""设置通用的headers
:param headers: dict形式的headers
:return: None
"""
self._owner._headers = CaseInsensitiveDict(format_headers(headers))
def header(self, name, value):
"""设置headers中一个项
:param name: 设置名称
:param value: 设置值
:return: None
"""
self._owner._headers[name] = value
def user_agent(self, ua):
"""设置user agent
:param ua: user agent
:return: None
"""
self._owner._headers['user-agent'] = ua
def proxies(self, http=None, https=None):
"""设置proxies参数
:param http: http代理地址
:param https: https代理地址
:return: None
"""
self._owner.session.proxies = {'http': http, 'https': https}
def auth(self, auth):
"""设置认证元组或对象
:param auth: 认证元组或对象
:return: None
"""
self._owner.session.auth = auth
def hooks(self, hooks):
"""设置回调方法
:param hooks: 回调方法
:return: None
"""
self._owner.session.hooks = hooks
def params(self, params):
"""设置查询参数字典
:param params: 查询参数字典
:return: None
"""
self._owner.session.params = params
def verify(self, on_off):
"""设置是否验证SSL证书
:param on_off: 是否验证 SSL 证书
:return: None
"""
self._owner.session.verify = on_off
def cert(self, cert):
"""SSL客户端证书文件的路径(.pem格式),或(cert, key)元组
:param cert: 证书路径或元组
:return: None
"""
self._owner.session.cert = cert
def stream(self, on_off):
"""设置是否使用流式响应内容
:param on_off: 是否使用流式响应内容
:return: None
"""
self._owner.session.stream = on_off
def trust_env(self, on_off):
"""设置是否信任环境
:param on_off: 是否信任环境
:return: None
"""
self._owner.session.trust_env = on_off
def max_redirects(self, times):
"""设置最大重定向次数
:param times: 最大重定向次数
:return: None
"""
self._owner.session.max_redirects = times
def add_adapter(self, url, adapter):
"""添加适配器
:param url: 适配器对应url
:param adapter: 适配器对象
:return: None
"""
self._owner.session.mount(url, adapter)
@ -200,16 +117,9 @@ class BrowserBaseSetter(BaseSetter):
@property
def load_mode(self):
"""返回用于设置页面加载策略的对象"""
return LoadMode(self._owner)
def timeouts(self, base=None, page_load=None, script=None):
"""设置超时时间,单位为秒
:param base: 基本等待时间除页面加载和脚本超时其它等待默认使用
:param page_load: 页面加载超时时间
:param script: 脚本运行超时时间
:return: None
"""
if base is not None:
self._owner.timeouts.base = base
@ -224,40 +134,21 @@ class BrowserSetter(BrowserBaseSetter):
@property
def cookies(self):
"""返回用于设置cookies的对象"""
if self._cookies_setter is None:
self._cookies_setter = BrowserCookiesSetter(self._owner)
return self._cookies_setter
def auto_handle_alert(self, on_off=True, accept=True):
"""设置是否启用自动处理弹窗
:param on_off: bool表示开或关
:param accept: bool表示确定还是取消
:return: None
"""
Settings.auto_handle_alert = accept if on_off else None
def download_path(self, path):
"""设置下载路径
:param path: 下载路径
:return: None
"""
super().download_path(path)
self._owner._dl_mgr.set_path('browser', self._owner._download_path)
def download_file_name(self, name=None, suffix=None):
"""设置下一个被下载文件的名称
:param name: 文件名可不含后缀会自动使用远程文件后缀
:param suffix: 后缀名显式设置后缀名不使用远程文件后缀
:return: None
"""
self._owner._dl_mgr.set_rename('browser', name, suffix)
def when_download_file_exists(self, mode):
"""设置当存在同名文件时的处理方式
:param mode: 可在 'rename', 'overwrite', 'skip', 'r', 'o', 's'中选择
:return: None
"""
types = {'rename': 'rename', 'overwrite': 'overwrite', 'skip': 'skip', 'r': 'rename', 'o': 'overwrite',
's': 'skip'}
mode = types.get(mode, mode)
@ -265,48 +156,30 @@ class BrowserSetter(BrowserBaseSetter):
raise ValueError(f'''mode参数只能是 '{"', '".join(types.keys())}' 之一,现在是:{mode}''')
self._owner._dl_mgr.set_file_exists('browser', mode)
# ---------- 即将废弃 ----------
def tab_to_front(self, tab_or_id):
"""激活标签页使其处于最前面
:param tab_or_id: 标签页对象或id
:return: None
"""
if not isinstance(tab_or_id, str): # 传入Tab对象
tab_or_id = tab_or_id.tab_id
self._owner.activate_tab(tab_or_id)
class ChromiumBaseSetter(BrowserBaseSetter):
@property
def scroll(self):
"""返回用于设置页面滚动设置的对象"""
return PageScrollSetter(self._owner.scroll)
@property
def cookies(self):
"""返回用于设置cookies的对象"""
if self._cookies_setter is None:
self._cookies_setter = CookiesSetter(self._owner)
return self._cookies_setter
def headers(self, headers):
self._owner._run_cdp('Network.enable')
self._owner._run_cdp('Network.setExtraHTTPHeaders', headers=format_headers(headers))
def user_agent(self, ua, platform=None):
"""为当前tab设置user agent只在当前tab有效
:param ua: user agent字符串
:param platform: platform字符串
:return: None
"""
keys = {'userAgent': ua}
if platform:
keys['platform'] = platform
self._owner._run_cdp('Emulation.setUserAgentOverride', **keys)
def session_storage(self, item, value):
"""设置或删除某项sessionStorage信息
:param item: 要设置的项
:param value: 项的值设置为False时删除该项
:return: None
"""
self._owner._run_cdp_loaded('DOMStorage.enable')
i = self._owner._run_cdp('Storage.getStorageKeyForFrame', frameId=self._owner._frame_id)['storageKey']
if value is False:
@ -318,11 +191,6 @@ class ChromiumBaseSetter(BrowserBaseSetter):
self._owner._run_cdp_loaded('DOMStorage.disable')
def local_storage(self, item, value):
"""设置或删除某项localStorage信息
:param item: 要设置的项
:param value: 项的值设置为False时删除该项
:return: None
"""
self._owner._run_cdp_loaded('DOMStorage.enable')
i = self._owner._run_cdp('Storage.getStorageKeyForFrame', frameId=self._owner._frame_id)['storageKey']
if value is False:
@ -334,10 +202,6 @@ class ChromiumBaseSetter(BrowserBaseSetter):
self._owner._run_cdp_loaded('DOMStorage.disable')
def upload_files(self, files):
"""等待上传的文件路径
:param files: 文件路径列表或字符串字符串时多个文件用回车分隔
:return: None
"""
if not self._owner._upload_list:
self._owner.driver.set_callback('Page.fileChooserOpened', self._owner._onFileChooserOpened)
self._owner._run_cdp('Page.setInterceptFileChooserDialog', enabled=True)
@ -348,27 +212,10 @@ class ChromiumBaseSetter(BrowserBaseSetter):
files = (files,)
self._owner._upload_list = [str(Path(i).absolute()) for i in files]
def headers(self, headers):
"""设置固定发送的headers
:param headers: dict格式的headers数据或从浏览器复制的headers文本\n分行
:return: None
"""
self._owner._run_cdp('Network.enable')
self._owner._run_cdp('Network.setExtraHTTPHeaders', headers=format_headers(headers))
def auto_handle_alert(self, on_off=True, accept=True):
"""设置是否启用自动处理弹窗
:param on_off: bool表示开或关
:param accept: bool表示确定还是取消
:return: None
"""
self._owner._alert.auto = accept if on_off else None
def blocked_urls(self, urls):
"""设置要忽略的url
:param urls: 要忽略的url可用*通配符可输入多个传入None时清空已设置的内容
:return: None
"""
if not urls:
urls = []
elif isinstance(urls, str):
@ -381,39 +228,22 @@ class ChromiumBaseSetter(BrowserBaseSetter):
class TabSetter(ChromiumBaseSetter):
def __init__(self, owner):
"""
:param owner: 标签页对象
"""
super().__init__(owner)
@property
def window(self):
"""返回用于设置浏览器窗口的对象"""
return WindowSetter(self._owner)
def download_path(self, path):
"""设置下载路径
:param path: 下载路径
:return: None
"""
super().download_path(path)
self._owner.browser._dl_mgr.set_path(self._owner, self._owner._download_path)
if self._owner._DownloadKit:
self._owner._DownloadKit.set.goal_path(self._owner._download_path)
def download_file_name(self, name=None, suffix=None):
"""设置下一个被下载文件的名称
:param name: 文件名可不含后缀会自动使用远程文件后缀
:param suffix: 后缀名显式设置后缀名不使用远程文件后缀
:return: None
"""
self._owner.browser._dl_mgr.set_rename(self._owner.tab_id, name, suffix)
def when_download_file_exists(self, mode):
"""设置当存在同名文件时的处理方式
:param mode: 可在 'rename', 'overwrite', 'skip', 'r', 'o', 's'中选择
:return: None
"""
types = {'rename': 'rename', 'overwrite': 'overwrite', 'skip': 'skip', 'r': 'rename', 'o': 'overwrite',
's': 'skip'}
mode = types.get(mode, mode)
@ -422,7 +252,6 @@ class TabSetter(ChromiumBaseSetter):
self._owner.browser._dl_mgr.set_file_exists(self._owner.tab_id, mode)
def activate(self):
"""使标签页处于最前面"""
self._owner.browser.activate_tab(self._owner.tab_id)
@ -457,29 +286,11 @@ class ChromiumPageSetter(TabSetter):
self._owner.browser._download_path = self._owner._download_path
def auto_handle_alert(self, on_off=True, accept=True, all_tabs=False):
"""设置是否启用自动处理弹窗
:param on_off: bool表示开或关
:param accept: bool表示确定还是取消
:param all_tabs: 是否为全局设置
:return: None
"""
if all_tabs:
Settings.auto_handle_alert = on_off
else:
self._owner._alert.auto = accept if on_off else None
# ---------- 即将废弃 ----------
def tab_to_front(self, tab_or_id=None):
"""激活标签页使其处于最前面
:param tab_or_id: 标签页对象或id为None表示当前标签页
:return: None
"""
if not tab_or_id:
tab_or_id = self._owner.tab_id
elif not isinstance(tab_or_id, str): # 传入Tab对象
tab_or_id = tab_or_id.tab_id
self._owner.browser.activate_tab(tab_or_id)
class MixPageSetter(ChromiumPageSetter):
def __init__(self, owner):
@ -495,17 +306,12 @@ class MixPageSetter(ChromiumPageSetter):
return self._cookies_setter
def headers(self, headers):
"""设置固定发送的headers
:param headers: dict格式的headers数据
:return: None
"""
if self._owner.mode == 's':
self._session_setter.headers(headers)
else:
self._chromium_setter.headers(headers)
def user_agent(self, ua, platform=None):
"""设置user agentd模式下只有当前tab有效"""
if self._owner.mode == 's':
self._session_setter.user_agent(ua)
else:
@ -520,35 +326,23 @@ class MixTabSetter(TabSetter):
@property
def cookies(self):
"""返回用于设置cookies的对象"""
if self._cookies_setter is None:
self._cookies_setter = MixPageCookiesSetter(self._owner)
return self._cookies_setter
def headers(self, headers):
"""设置固定发送的headers
:param headers: dict格式的headers数据
:return: None
"""
if self._owner._has_session:
self._session_setter.headers(headers)
if self._owner._has_driver:
self._chromium_setter.headers(headers)
def user_agent(self, ua, platform=None):
"""设置user agentd模式下只有当前tab有效"""
if self._owner._has_session:
self._session_setter.user_agent(ua)
if self._owner._has_driver:
self._chromium_setter.user_agent(ua, platform)
def timeouts(self, base=None, page_load=None, script=None):
"""设置超时时间,单位为秒
:param base: 基本等待时间除页面加载和脚本超时其它等待默认使用
:param page_load: 页面加载超时时间
:param script: 脚本运行超时时间
:return: None
"""
super().timeouts(base=base, page_load=page_load, script=script)
if base is not None:
self._owner._timeout = base
@ -556,17 +350,9 @@ class MixTabSetter(TabSetter):
class ChromiumElementSetter(object):
def __init__(self, ele):
"""
:param ele: ChromiumElement
"""
self._ele = ele
def attr(self, name, value=''):
"""设置元素attribute属性
:param name: 属性名
:param value: 属性值
:return: None
"""
try:
self._ele.owner._run_cdp('DOM.setAttributeValue',
nodeId=self._ele._node_id, name=name, value=str(value))
@ -576,63 +362,30 @@ class ChromiumElementSetter(object):
nodeId=self._ele._node_id, name=name, value=str(value))
def property(self, name, value):
"""设置元素property属性
:param name: 属性名
:param value: 属性值
:return: None
"""
value = value.replace('"', r'\"')
self._ele._run_js(f'this.{name}="{value}";')
def style(self, name, value):
"""设置元素style样式
:param name: 样式名称
:param value: 样式值
:return: None
"""
try:
self._ele._run_js(f'this.style.{name}="{value}";')
except JavaScriptError:
raise ValueError(f'设置失败,请检查属性名{name}')
def innerHTML(self, html):
"""设置元素innerHTML
:param html: html文本
:return: None
"""
self.property('innerHTML', html)
def value(self, value):
"""设置元素value值
:param value: value值
:return: None
"""
self.property('value', value)
class ChromiumFrameSetter(ChromiumBaseSetter):
def attr(self, name, value):
"""设置frame元素attribute属性
:param name: 属性名
:param value: 属性值
:return: None
"""
self._owner.frame_ele.set.attr(name, value)
def property(self, name, value):
"""设置元素property属性
:param name: 属性名
:param value: 属性值
:return: None
"""
self._owner.frame_ele.set.property(name=name, value=value)
def style(self, name, value):
"""设置元素style样式
:param name: 样式名称
:param value: 样式值
:return: None
"""
self._owner.frame_ele.set.style(name=name, value=value)
@ -640,16 +393,9 @@ class LoadMode(object):
"""用于设置页面加载策略的类"""
def __init__(self, owner):
"""
:param owner: ChromiumBase对象
"""
self._owner = owner
def __call__(self, value):
"""设置加载策略
:param value: 可选 'normal', 'eager', 'none'
:return: None
"""
if value.lower() not in ('normal', 'eager', 'none'):
raise ValueError("只能选择 'normal', 'eager', 'none'")
self._owner._load_mode = value
@ -657,43 +403,29 @@ class LoadMode(object):
self._owner.browser._load_mode = value
def normal(self):
"""设置页面加载策略为normal"""
self.__call__('normal')
def eager(self):
"""设置页面加载策略为eager"""
self.__call__('eager')
def none(self):
"""设置页面加载策略为none"""
self.__call__('none')
class PageScrollSetter(object):
def __init__(self, scroll):
"""
:param scroll: PageScroller对象
"""
self._scroll = scroll
def wait_complete(self, on_off=True):
"""设置滚动命令后是否等待完成
:param on_off: 开或关
:return: None
"""
if not isinstance(on_off, bool):
raise TypeError('on_off必须为bool。')
self._scroll._wait_complete = on_off
def smooth(self, on_off=True):
"""设置页面滚动是否平滑滚动
:param on_off: 开或关
:return: None
"""
if not isinstance(on_off, bool):
raise TypeError('on_off必须为bool。')
b = 'smooth' if on_off else 'auto'
self._scroll._driver._run_js(f'document.documentElement.style.setProperty("scroll-behavior","{b}");')
self._scroll._owner._run_js(f'document.documentElement.style.setProperty("scroll-behavior","{b}");')
self._scroll._wait_complete = on_off
@ -701,46 +433,34 @@ class WindowSetter(object):
"""用于设置窗口大小的类"""
def __init__(self, owner):
"""
:param owner: 页面对象
"""
self._owner = owner
self._window_id = self._get_info()['windowId']
def max(self):
"""窗口最大化"""
s = self._get_info()['bounds']['windowState']
if s in ('fullscreen', 'minimized'):
self._perform({'windowState': 'normal'})
self._perform({'windowState': 'maximized'})
def mini(self):
"""窗口最小化"""
s = self._get_info()['bounds']['windowState']
if s == 'fullscreen':
self._perform({'windowState': 'normal'})
self._perform({'windowState': 'minimized'})
def full(self):
"""设置窗口为全屏"""
s = self._get_info()['bounds']['windowState']
if s == 'minimized':
self._perform({'windowState': 'normal'})
self._perform({'windowState': 'fullscreen'})
def normal(self):
"""设置窗口为常规模式"""
s = self._get_info()['bounds']['windowState']
if s == 'fullscreen':
self._perform({'windowState': 'normal'})
self._perform({'windowState': 'normal'})
def size(self, width=None, height=None):
"""设置窗口大小
:param width: 窗口宽度
:param height: 窗口高度
:return: None
"""
if width or height:
s = self._get_info()['bounds']['windowState']
if s != 'normal':
@ -751,11 +471,6 @@ class WindowSetter(object):
self._perform({'width': width, 'height': height})
def location(self, x=None, y=None):
"""设置窗口在屏幕中的位置,相对左上角坐标
:param x: 距离顶部距离
:param y: 距离左边距离
:return: None
"""
if x is not None or y is not None:
self.normal()
info = self._get_info()['bounds']
@ -763,8 +478,13 @@ class WindowSetter(object):
y = y if y is not None else info['top']
self._perform({'left': x - 8, 'top': y})
def hide(self):
show_or_hide_browser(self._owner, hide=True)
def show(self):
show_or_hide_browser(self._owner, hide=False)
def _get_info(self):
"""获取窗口位置及大小信息"""
for _ in range(50):
try:
return self._owner._run_cdp('Browser.getWindowForTarget')
@ -773,33 +493,7 @@ class WindowSetter(object):
raise RuntimeError('获取窗口信息失败。')
def _perform(self, bounds):
"""执行改变窗口大小操作
:param bounds: 控制数据
:return: None
"""
try:
self._owner._run_cdp('Browser.setWindowBounds', windowId=self._window_id, bounds=bounds)
except:
raise RuntimeError('浏览器全屏或最小化状态时请先调用set.window.normal()恢复正常状态。')
# ------------即将废除----------
def maximized(self):
"""窗口最大化"""
self.max()
def minimized(self):
"""窗口最小化"""
self.mini()
def fullscreen(self):
"""设置窗口为全屏"""
self.full()
def hide(self):
"""隐藏浏览器窗口只在Windows系统可用"""
show_or_hide_browser(self._owner, hide=True)
def show(self):
"""显示浏览器窗口只在Windows系统可用"""
show_or_hide_browser(self._owner, hide=False)

View File

@ -27,16 +27,44 @@ FILE_EXISTS = Literal['skip', 'rename', 'overwrite', 's', 'r', 'o']
class BaseSetter(object):
_owner: Union[Chromium, BasePage] = ...
def __init__(self, owner: Union[Chromium, BasePage]):
self._owner: Union[Chromium, BasePage] = ...
"""
:param owner: BasePage对象
"""
...
def NoneElement_value(self, value: Any = None, on_off: bool = True) -> None: ...
def NoneElement_value(self,
value: Any = None,
on_off: bool = True) -> None:
"""设置空元素是否返回设定值
:param value: 返回的设定值
:param on_off: 是否启用
:return: None
"""
...
def retry_times(self, times: int) -> None: ...
def retry_times(self, times: int) -> None:
"""设置连接失败重连次数
:param times: 重试次数
:return: None
"""
...
def retry_interval(self, interval: float) -> None: ...
def retry_interval(self, interval: float) -> None:
"""设置连接失败重连间隔
:param interval: 重试间隔
:return: None
"""
...
def download_path(self, path: Union[str, Path, None]) -> None: ...
def download_path(self, path: Union[str, Path, None]) -> None:
"""设置下载路径
:param path: 下载路径
:return: None
"""
...
class SessionPageSetter(BaseSetter):
@ -46,52 +74,146 @@ class SessionPageSetter(BaseSetter):
def __init__(self, owner: SessionPage): ...
@property
def cookies(self) -> SessionCookiesSetter: ...
def cookies(self) -> SessionCookiesSetter:
"""返回用于设置cookies的对象"""
...
def retry_times(self, times: int) -> None: ...
def download_path(self, path: Union[str, Path, None]) -> None:
"""设置下载路径
:param path: 下载路径
:return: None
"""
...
def retry_interval(self, interval: float) -> None: ...
def timeout(self, second: float) -> None:
"""设置连接超时时间
:param second: 秒数
:return: None
"""
...
def download_path(self, path: Union[str, Path, None]) -> None: ...
def encoding(self, encoding: Union[str, None], set_all: bool = True) -> None:
"""设置编码
:param encoding: 编码名称如果要取消之前的设置传入None
:param set_all: 是否设置对象参数为False则只设置当前Response
:return: None
"""
...
def timeout(self, second: float) -> None: ...
def headers(self, headers: Union[str, dict]) -> None:
"""设置通用的headers
:param headers: dict形式的headers
:return: None
"""
...
def encoding(self, encoding: Union[str, None], set_all: bool = True) -> None: ...
def header(self, name: str, value: str) -> None:
"""设置headers中一个项
:param name: 设置名称
:param value: 设置值
:return: None
"""
...
def headers(self, headers: Union[str, dict]) -> None: ...
def user_agent(self, ua: str) -> None:
"""设置user agent
:param ua: user agent
:return: None
"""
...
def header(self, name: str, value: str) -> None: ...
def proxies(self, http: str = None, https: str = None) -> None:
"""设置proxies参数
:param http: http代理地址
:param https: https代理地址
:return: None
"""
...
def user_agent(self, ua: str) -> None: ...
def auth(self, auth: Union[Tuple[str, str], HTTPBasicAuth, None]) -> None:
"""设置认证元组或对象
:param auth: 认证元组或对象
:return: None
"""
...
def proxies(self, http: str = None, https: str = None) -> None: ...
def hooks(self, hooks: Union[dict, None]) -> None:
"""设置回调方法
:param hooks: 回调方法
:return: None
"""
...
def auth(self, auth: Union[Tuple[str, str], HTTPBasicAuth, None]) -> None: ...
def params(self, params: Union[dict, None]) -> None:
"""设置查询参数字典
:param params: 查询参数字典
:return: None
"""
...
def hooks(self, hooks: Union[dict, None]) -> None: ...
def verify(self, on_off: Union[bool, None]) -> None:
"""设置是否验证SSL证书
:param on_off: 是否验证 SSL 证书
:return: None
"""
...
def params(self, params: Union[dict, None]) -> None: ...
def cert(self, cert: Union[str, Tuple[str, str], None]) -> None:
"""SSL客户端证书文件的路径(.pem格式),或(cert, key)元组
:param cert: 证书路径或元组
:return: None
"""
...
def verify(self, on_off: Union[bool, None]) -> None: ...
def stream(self, on_off: Union[bool, None]) -> None:
"""设置是否使用流式响应内容
:param on_off: 是否使用流式响应内容
:return: None
"""
...
def cert(self, cert: Union[str, Tuple[str, str], None]) -> None: ...
def trust_env(self, on_off: Union[bool, None]) -> None:
"""设置是否信任环境
:param on_off: 是否信任环境
:return: None
"""
...
def stream(self, on_off: Union[bool, None]) -> None: ...
def max_redirects(self, times: Union[int, None]) -> None:
"""设置最大重定向次数
:param times: 最大重定向次数
:return: None
"""
...
def trust_env(self, on_off: Union[bool, None]) -> None: ...
def max_redirects(self, times: Union[int, None]) -> None: ...
def add_adapter(self, url: str, adapter: HTTPAdapter) -> None: ...
def add_adapter(self, url: str, adapter: HTTPAdapter) -> None:
"""添加适配器
:param url: 适配器对应url
:param adapter: 适配器对象
:return: None
"""
...
class BrowserBaseSetter(BaseSetter):
_cookies_setter: Optional[CookiesSetter] = ...
@property
def load_mode(self) -> LoadMode: ...
def load_mode(self) -> LoadMode:
"""返回用于设置页面加载策略的对象"""
...
def timeouts(self, base=None, page_load=None, script=None) -> None: ...
def timeouts(self,
base=None,
page_load=None,
script=None) -> None:
"""设置超时时间,单位为秒
:param base: 基本等待时间除页面加载和脚本超时其它等待默认使用
:param page_load: 页面加载超时时间
:param script: 脚本运行超时时间
:return: None
"""
...
class BrowserSetter(BrowserBaseSetter):
@ -99,15 +221,43 @@ class BrowserSetter(BrowserBaseSetter):
_cookies_setter: BrowserCookiesSetter = ...
@property
def cookies(self) -> BrowserCookiesSetter: ...
def cookies(self) -> BrowserCookiesSetter:
"""返回用于设置cookies的对象"""
...
def auto_handle_alert(self, on_off: bool = True, accept: bool = True): ...
def auto_handle_alert(self,
on_off: bool = True,
accept: bool = True):
"""设置是否启用自动处理弹窗
:param on_off: bool表示开或关
:param accept: bool表示确定还是取消
:return: None
"""
...
def download_path(self, path: Union[Path, str, None]): ...
def download_path(self, path: Union[Path, str, None]):
"""设置下载路径
:param path: 下载路径
:return: None
"""
...
def download_file_name(self, name: str = None, suffix: str = None): ...
def download_file_name(self,
name: str = None,
suffix: str = None):
"""设置下一个被下载文件的名称
:param name: 文件名可不含后缀会自动使用远程文件后缀
:param suffix: 后缀名显式设置后缀名不使用远程文件后缀
:return: None
"""
...
def when_download_file_exists(self, mode: FILE_EXISTS): ...
def when_download_file_exists(self, mode: FILE_EXISTS):
"""设置当存在同名文件时的处理方式
:param mode: 可在 'rename', 'overwrite', 'skip', 'r', 'o', 's'中选择
:return: None
"""
...
class ChromiumBaseSetter(BrowserBaseSetter):
@ -117,47 +267,134 @@ class ChromiumBaseSetter(BrowserBaseSetter):
def __init__(self, owner): ...
@property
def scroll(self) -> PageScrollSetter: ...
def scroll(self) -> PageScrollSetter:
"""返回用于设置页面滚动设置的对象"""
...
@property
def cookies(self) -> CookiesSetter: ...
def cookies(self) -> CookiesSetter:
"""返回用于设置cookies的对象"""
...
def user_agent(self, ua: str, platform: str = None) -> None: ...
def headers(self, headers: Union[dict, str]) -> None:
"""设置固定发送的headers
:param headers: dict格式的headers数据或从浏览器复制的headers文本\n分行
:return: None
"""
...
def session_storage(self, item: str, value: Union[str, bool]) -> None: ...
def user_agent(self, ua: str, platform: str = None) -> None:
"""为当前tab设置user agent只在当前tab有效
:param ua: user agent字符串
:param platform: platform字符串
:return: None
"""
...
def local_storage(self, item: str, value: Union[str, bool]) -> None: ...
def session_storage(self, item: str, value: Union[str, bool]) -> None:
"""设置或删除某项sessionStorage信息
:param item: 要设置的项
:param value: 项的值设置为False时删除该项
:return: None
"""
...
def headers(self, headers: Union[dict, str]) -> None: ...
def local_storage(self, item: str, value: Union[str, bool]) -> None:
"""设置或删除某项localStorage信息
:param item: 要设置的项
:param value: 项的值设置为False时删除该项
:return: None
"""
...
def auto_handle_alert(self, on_off: bool = True, accept: bool = True) -> None: ...
def upload_files(self, files: Union[str, Path, list, tuple]) -> None:
"""等待上传的文件路径
:param files: 文件路径列表或字符串字符串时多个文件用回车分隔
:return: None
"""
...
def upload_files(self, files: Union[str, Path, list, tuple]) -> None: ...
def auto_handle_alert(self,
on_off: bool = True,
accept: bool = True) -> None:
"""设置是否启用自动处理弹窗
:param on_off: bool表示开或关
:param accept: bool表示确定还是取消
:return: None
"""
...
def blocked_urls(self, urls: Union[list, tuple, str, None]) -> None: ...
def blocked_urls(self, urls: Union[list, tuple, str, None]) -> None:
"""设置要忽略的url
:param urls: 要忽略的url可用*通配符可输入多个传入None时清空已设置的内容
:return: None
"""
...
class TabSetter(ChromiumBaseSetter):
_owner: ChromiumTab = ...
def __init__(self, owner: Union[ChromiumTab, MixTab, MixPage, ChromiumPage]): ...
def __init__(self, owner: Union[ChromiumTab, MixTab, MixPage, ChromiumPage]):
"""
:param owner: 标签页对象
"""
...
@property
def window(self) -> WindowSetter: ...
def window(self) -> WindowSetter:
"""返回用于设置浏览器窗口的对象"""
...
def download_path(self, path: Union[str, Path, None]) -> None: ...
def download_path(self, path: Union[str, Path, None]) -> None:
"""设置下载路径
:param path: 下载路径
:return: None
"""
...
def download_file_name(self, name: str = None, suffix: str = None) -> None: ...
def download_file_name(self,
name: str = None,
suffix: str = None) -> None:
"""设置下一个被下载文件的名称
:param name: 文件名可不含后缀会自动使用远程文件后缀
:param suffix: 后缀名显式设置后缀名不使用远程文件后缀
:return: None
"""
...
def when_download_file_exists(self, mode: FILE_EXISTS) -> None: ...
def when_download_file_exists(self, mode: FILE_EXISTS) -> None:
"""设置当存在同名文件时的处理方式
:param mode: 可在 'rename', 'overwrite', 'skip', 'r', 'o', 's'中选择
:return: None
"""
...
def activate(self) -> None: ...
def activate(self) -> None:
"""使标签页处于最前面"""
...
class ChromiumPageSetter(TabSetter):
_owner: ChromiumPage = ...
def auto_handle_alert(self, on_off: bool = True, accept: bool = True, all_tabs: bool = False) -> None: ...
def __init__(self, owner: ChromiumPage):
"""
:param owner: ChromiumPage对象
"""
...
def auto_handle_alert(self,
on_off: bool = True,
accept: bool = True,
all_tabs: bool = False) -> None:
"""设置是否启用自动处理弹窗
:param on_off: bool表示开或关
:param accept: bool表示确定还是取消
:param all_tabs: 是否为全局设置
:return: None
"""
...
class MixPageSetter(ChromiumPageSetter):
@ -165,9 +402,11 @@ class MixPageSetter(ChromiumPageSetter):
_session_setter: SessionPageSetter = ...
_chromium_setter: ChromiumPageSetter = ...
def user_agent(self, ua: str, platform: str = None) -> None: ...
def headers(self, headers: Union[str, dict]) -> None: ...
def __init__(self, owner: MixPage):
"""
:param owner: MixPage对象
"""
...
@property
def cookies(self) -> MixPageCookiesSetter: ...
@ -178,81 +417,216 @@ class MixTabSetter(TabSetter):
_session_setter: SessionPageSetter = ...
_chromium_setter: ChromiumBaseSetter = ...
def user_agent(self, ua: str, platform: str = None) -> None: ...
def headers(self, headers: Union[str, dict]) -> None: ...
def __init__(self, owner: MixTab):
"""
:param owner: MixTab对象
"""
...
@property
def cookies(self) -> MixPageCookiesSetter: ...
def cookies(self) -> MixPageCookiesSetter:
"""返回用于设置cookies的对象"""
...
def timeouts(self, base: float = None, page_load: float = None, script: float = None) -> None: ...
def timeouts(self,
base: float = None,
page_load: float = None,
script: float = None) -> None:
"""设置超时时间,单位为秒
:param base: 基本等待时间除页面加载和脚本超时其它等待默认使用
:param page_load: 页面加载超时时间
:param script: 脚本运行超时时间
:return: None
"""
...
class ChromiumElementSetter(object):
_ele: ChromiumElement = ...
def __init__(self, ele: ChromiumElement):
self._ele: ChromiumElement = ...
"""
:param ele: ChromiumElement
"""
...
def attr(self, name: str, value: str = '') -> None: ...
def attr(self, name: str, value: str = '') -> None:
"""设置元素attribute属性
:param name: 属性名
:param value: 属性值
:return: None
"""
...
def property(self, name: str, value: str) -> None: ...
def property(self, name: str, value: str) -> None:
"""设置元素property属性
:param name: 属性名
:param value: 属性值
:return: None
"""
...
def style(self, name: str, value: str) -> None: ...
def style(self, name: str, value: str) -> None:
"""设置元素style样式
:param name: 样式名称
:param value: 样式值
:return: None
"""
...
def innerHTML(self, html: str) -> None: ...
def innerHTML(self, html: str) -> None:
"""设置元素innerHTML
:param html: html文本
:return: None
"""
...
def value(self, value: str) -> None: ...
def value(self, value: str) -> None:
"""设置元素value值
:param value: value值
:return: None
"""
...
class ChromiumFrameSetter(ChromiumBaseSetter):
_owner: ChromiumFrame = ...
def attr(self, name: str, value: str) -> None: ...
def attr(self, name: str, value: str) -> None:
"""设置frame元素attribute属性
:param name: 属性名
:param value: 属性值
:return: None
"""
...
def property(self, name, value) -> None:
"""设置元素property属性
:param name: 属性名
:param value: 属性值
:return: None
"""
...
def style(self, name, value) -> None:
"""设置元素style样式
:param name: 样式名称
:param value: 样式值
:return: None
"""
...
class LoadMode(object):
_owner: Union[Chromium, ChromiumBase] = ...
def __init__(self, owner: Union[Chromium, ChromiumBase]): ...
def __init__(self, owner: Union[Chromium, ChromiumBase]):
"""
:param owner: ChromiumBase对象
"""
...
def __call__(self, value: str) -> None: ...
def __call__(self, value: str) -> None:
"""设置加载策略
:param value: 可选 'normal', 'eager', 'none'
:return: None
"""
...
def normal(self) -> None: ...
def normal(self) -> None:
"""设置页面加载策略为normal"""
...
def eager(self) -> None: ...
def eager(self) -> None:
"""设置页面加载策略为eager"""
...
def none(self) -> None: ...
def none(self) -> None:
"""设置页面加载策略为none"""
...
class PageScrollSetter(object):
_scroll: PageScroller = ...
def __init__(self, scroll: PageScroller):
self._scroll: PageScroller = ...
"""
:param scroll: PageScroller对象
"""
...
def wait_complete(self, on_off: bool = True): ...
def wait_complete(self, on_off: bool = True):
"""设置滚动命令后是否等待完成
:param on_off: 开或关
:return: None
"""
...
def smooth(self, on_off: bool = True): ...
def smooth(self, on_off: bool = True):
"""设置页面滚动是否平滑滚动
:param on_off: 开或关
:return: None
"""
...
class WindowSetter(object):
def __init__(self, owner: ChromiumBase):
self._owner: ChromiumBase = ...
self._window_id: str = ...
_owner: ChromiumBase = ...
_window_id: str = ...
def max(self) -> None: ...
def __init__(self, owner: Union[ChromiumTab, ChromiumPage]):
"""
:param owner: Tab或Page对象
"""
...
def mini(self) -> None: ...
def max(self) -> None:
"""窗口最大化"""
...
def full(self) -> None: ...
def mini(self) -> None:
"""窗口最小化"""
...
def normal(self) -> None: ...
def full(self) -> None:
"""设置窗口为全屏"""
...
def size(self, width: int = None, height: int = None) -> None: ...
def normal(self) -> None:
"""设置窗口为常规模式"""
...
def location(self, x: int = None, y: int = None) -> None: ...
def size(self, width: int = None, height: int = None) -> None:
"""设置窗口大小
:param width: 窗口宽度
:param height: 窗口高度
:return: None
"""
...
def _get_info(self) -> dict: ...
def location(self, x: int = None, y: int = None) -> None:
"""设置窗口在屏幕中的位置,相对左上角坐标
:param x: 距离顶部距离
:param y: 距离左边距离
:return: None
"""
...
def _perform(self, bounds: dict) -> None: ...
def hide(self) -> None:
"""隐藏浏览器窗口只在Windows系统可用"""
...
def hide(self) -> None: ...
def show(self) -> None:
"""显示浏览器窗口只在Windows系统可用"""
...
def show(self) -> None: ...
def _get_info(self) -> dict:
"""获取窗口位置及大小信息"""
...
def _perform(self, bounds: dict) -> None:
"""执行改变窗口大小操作
:param bounds: 控制数据
:return: None
"""
...

View File

@ -17,11 +17,6 @@ class OriginWaiter(object):
self._owner = owner
def __call__(self, second, scope=None):
"""等待若干秒,如传入两个参数,等待时间为这两个数间的一个随机数
:param second: 秒数
:param scope: 随机数范围
:return: None
"""
if scope is None:
sleep(second)
else:
@ -33,12 +28,6 @@ class OriginWaiter(object):
class BrowserWaiter(OriginWaiter):
def new_tab(self, timeout=None, curr_tab=None, raise_err=None):
"""等待新标签页出现
:param timeout: 超时时间为None则使用页面对象timeout属性
:param curr_tab: 指定当前最新的tab对象或tab id用于判断新tab出现为None自动获取
:param raise_err: 等待失败时是否报错为None时根据Settings设置
:return: 等到新标签页返回其id否则返回False
"""
if not curr_tab:
curr_tab = self._owner.tab_ids[0]
elif hasattr(curr_tab, '_type'):
@ -57,11 +46,6 @@ class BrowserWaiter(OriginWaiter):
return False
def download_begin(self, timeout=None, cancel_it=False):
"""等待浏览器下载开始,可将其拦截
:param timeout: 超时时间None使用页面对象超时时间
:param cancel_it: 是否取消该任务
:return: 成功返回任务对象失败返回False
"""
if not self._owner._dl_mgr._running:
raise RuntimeError('此功能需显式设置下载路径才能使用。使用set.download_path()方法、配置对象或ini文件均可。')
self._owner._dl_mgr.set_flag('browser', False if cancel_it else True)
@ -81,11 +65,6 @@ class BrowserWaiter(OriginWaiter):
return r
def all_downloads_done(self, timeout=None, cancel_if_timeout=True):
"""等待所有浏览器下载任务结束
:param timeout: 超时时间为None时无限等待
:param cancel_if_timeout: 超时时是否取消剩余任务
:return: 是否等待成功
"""
if not self._owner._dl_mgr._running:
raise RuntimeError('此功能需显式设置下载路径使用set.download_path()方法、配置对象或ini文件均可')
if not timeout:
@ -112,22 +91,10 @@ class BrowserWaiter(OriginWaiter):
class BaseWaiter(OriginWaiter):
def ele_deleted(self, loc_or_ele, timeout=None, raise_err=None):
"""等待元素从DOM中删除
:param loc_or_ele: 要等待的元素可以是已有元素定位符
:param timeout: 超时时间默认读取页面超时时间
:param raise_err: 等待失败时是否报错为None时根据Settings设置
:return: 是否等待成功
"""
ele = self._owner._ele(loc_or_ele, raise_err=False, timeout=0)
return ele.wait.deleted(timeout, raise_err=raise_err) if ele else True
def ele_displayed(self, loc_or_ele, timeout=None, raise_err=None):
"""等待元素变成显示状态
:param loc_or_ele: 要等待的元素可以是已有元素定位符
:param timeout: 超时时间默认读取页面超时时间
:param raise_err: 等待失败时是否报错为None时根据Settings设置
:return: 是否等待成功
"""
if timeout is None:
timeout = self._owner.timeout
end_time = perf_counter() + timeout
@ -141,12 +108,6 @@ class BaseWaiter(OriginWaiter):
return ele.wait.displayed(timeout, raise_err=raise_err)
def ele_hidden(self, loc_or_ele, timeout=None, raise_err=None):
"""等待元素变成隐藏状态
:param loc_or_ele: 要等待的元素可以是已有元素定位符
:param timeout: 超时时间默认读取页面超时时间
:param raise_err: 等待失败时是否报错为None时根据Settings设置
:return: 是否等待成功
"""
if timeout is None:
timeout = self._owner.timeout
end_time = perf_counter() + timeout
@ -160,13 +121,6 @@ class BaseWaiter(OriginWaiter):
return ele.wait.hidden(timeout, raise_err=raise_err)
def eles_loaded(self, locators, timeout=None, any_one=False, raise_err=None):
"""等待元素加载到DOM可等待全部或任意一个
:param locators: 要等待的元素输入定位符用list输入多个
:param timeout: 超时时间默认读取页面超时时间
:param any_one: 是否等待到一个就返回
:param raise_err: 等待失败时是否报错为None时根据Settings设置
:return: 成功返回True失败返回False
"""
def _find(loc, driver):
r = driver.run('DOM.performSearch', query=loc, includeUserAgentShadowDOM=True)
@ -211,23 +165,12 @@ class BaseWaiter(OriginWaiter):
return False
def load_start(self, timeout=None, raise_err=None):
"""等待页面开始加载
:param timeout: 超时时间为None时使用页面timeout属性
:param raise_err: 等待失败时是否报错为None时根据Settings设置
:return: 是否等待成功
"""
return self._loading(timeout=timeout, gap=.002, raise_err=raise_err)
def doc_loaded(self, timeout=None, raise_err=None):
"""等待页面加载完成
:param timeout: 超时时间为None时使用页面timeout属性
:param raise_err: 等待失败时是否报错为None时根据Settings设置
:return: 是否等待成功
"""
return self._loading(timeout=timeout, start=False, raise_err=raise_err)
def upload_paths_inputted(self):
"""等待自动填写上传文件路径"""
end_time = perf_counter() + self._owner.timeout
while perf_counter() < end_time:
if not self._owner._upload_list:
@ -236,11 +179,6 @@ class BaseWaiter(OriginWaiter):
return False
def download_begin(self, timeout=None, cancel_it=False):
"""等待浏览器下载开始,可将其拦截
:param timeout: 超时时间None使用页面对象超时时间
:param cancel_it: 是否取消该任务
:return: 成功返回任务对象失败返回False
"""
if not self._owner.browser._dl_mgr._running:
raise RuntimeError('此功能需显式设置下载路径使用set.download_path()方法、配置对象或ini文件均可')
self._owner.browser._dl_mgr.set_flag(self._owner.tab_id, False if cancel_it else True)
@ -260,34 +198,12 @@ class BaseWaiter(OriginWaiter):
return r
def url_change(self, text, exclude=False, timeout=None, raise_err=None):
"""等待url变成包含或不包含指定文本
:param text: 用于识别的文本
:param exclude: 是否排除为True时当url不包含text指定文本时返回True
:param timeout: 超时时间
:param raise_err: 等待失败时是否报错为None时根据Settings设置
:return: 等待成功返回页面对象否则返回False
"""
return self._owner if self._change('url', text, exclude, timeout, raise_err) else False
def title_change(self, text, exclude=False, timeout=None, raise_err=None):
"""等待title变成包含或不包含指定文本
:param text: 用于识别的文本
:param exclude: 是否排除为True时当title不包含text指定文本时返回True
:param timeout: 超时时间为None使用页面设置
:param raise_err: 等待失败时是否报错为None时根据Settings设置
:return: 等待成功返回页面对象否则返回False
"""
return self._owner if self._change('title', text, exclude, timeout, raise_err) else False
def _change(self, arg, text, exclude=False, timeout=None, raise_err=None):
"""等待指定属性变成包含或不包含指定文本
:param arg: 要被匹配的属性
:param text: 用于识别的文本
:param exclude: 是否排除为True时当属性不包含text指定文本时返回True
:param timeout: 超时时间
:param raise_err: 等待失败时是否报错为None时根据Settings设置
:return: 是否等待成功
"""
def do():
if arg == 'url':
@ -317,13 +233,6 @@ class BaseWaiter(OriginWaiter):
return False
def _loading(self, timeout=None, start=True, gap=.01, raise_err=None):
"""等待页面开始加载或加载完成
:param timeout: 超时时间为None时使用页面timeout属性
:param start: 等待开始还是结束
:param gap: 间隔秒数
:param raise_err: 等待失败时是否报错为None时根据Settings设置
:return: 是否等待成功
"""
if timeout is None:
timeout = self._owner.timeout
timeout = .1 if timeout <= 0 else timeout
@ -343,11 +252,6 @@ class TabWaiter(BaseWaiter):
"""标签页对象等待对象"""
def downloads_done(self, timeout=None, cancel_if_timeout=True):
"""等待所有浏览器下载任务结束
:param timeout: 超时时间为None时无限等待
:param cancel_if_timeout: 超时时是否取消剩余任务
:return: 是否等待成功
"""
if not self._owner.browser._dl_mgr._running:
raise RuntimeError('此功能需显式设置下载路径使用set.download_path()方法、配置对象或ini文件均可')
if not timeout:
@ -371,7 +275,6 @@ class TabWaiter(BaseWaiter):
return True
def alert_closed(self):
"""等待弹出框关闭"""
while not self._owner.states.has_alert:
sleep(.2)
while self._owner.states.has_alert:
@ -382,19 +285,9 @@ class PageWaiter(TabWaiter):
"""ChromiumPage和MixPage的等待对象"""
def new_tab(self, timeout=None, raise_err=None):
"""等待新标签页出现
:param timeout: 超时时间为None则使用页面对象timeout属性
:param raise_err: 等待失败时是否报错为None时根据Settings设置
:return: 等到新标签页返回其id否则返回False
"""
return self._owner.browser.wait.new_tab(timeout=timeout, raise_err=raise_err)
def all_downloads_done(self, timeout=None, cancel_if_timeout=True):
"""等待所有浏览器下载任务结束
:param timeout: 超时时间为None时无限等待
:param cancel_if_timeout: 超时时是否取消剩余任务
:return: 是否等待成功
"""
return self._owner.browser.wait.all_downloads_done(timeout=timeout, cancel_if_timeout=cancel_if_timeout)
@ -407,71 +300,30 @@ class ElementWaiter(OriginWaiter):
@property
def _timeout(self):
"""返回超时设置"""
return self._ele.owner.timeout
def deleted(self, timeout=None, raise_err=None):
"""等待元素从dom删除
:param timeout: 超时时间为None使用元素所在页面timeout属性
:param raise_err: 等待失败时是否报错为None时根据Settings设置
:return: 成功返回元素对象失败返回False
"""
return self._wait_state('is_alive', False, timeout, raise_err, err_text='等待元素被删除失败。')
def displayed(self, timeout=None, raise_err=None):
"""等待元素从dom显示
:param timeout: 超时时间为None使用元素所在页面timeout属性
:param raise_err: 等待失败时是否报错为None时根据Settings设置
:return: 成功返回元素对象失败返回False
"""
return self._wait_state('is_displayed', True, timeout, raise_err, err_text='等待元素显示失败。')
def hidden(self, timeout=None, raise_err=None):
"""等待元素从dom隐藏
:param timeout: 超时时间为None使用元素所在页面timeout属性
:param raise_err: 等待失败时是否报错为None时根据Settings设置
:return: 成功返回元素对象失败返回False
"""
return self._wait_state('is_displayed', False, timeout, raise_err, err_text='等待元素隐藏失败。')
def covered(self, timeout=None, raise_err=None):
"""等待当前元素被遮盖
:param timeout: 超时时间为None使用元素所在页面timeout属性
:param raise_err: 等待失败时是否报错为None时根据Settings设置
:return: 成功返回覆盖元素id返回False
"""
return self._wait_state('is_covered', True, timeout, raise_err, err_text='等待元素被覆盖失败。')
def not_covered(self, timeout=None, raise_err=None):
"""等待当前元素不被遮盖
:param timeout: 超时时间为None使用元素所在页面timeout属性
:param raise_err: 等待失败时是否报错为None时根据Settings设置
:return: 成功返回元素对象失败返回False
"""
return self._wait_state('is_covered', False, timeout, raise_err, err_text='等待元素不被覆盖失败。')
def enabled(self, timeout=None, raise_err=None):
"""等待当前元素变成可用
:param timeout: 超时时间为None使用元素所在页面timeout属性
:param raise_err: 等待失败时是否报错为None时根据Settings设置
:return: 成功返回元素对象失败返回False
"""
return self._wait_state('is_enabled', True, timeout, raise_err, err_text='等待元素变成可用失败。')
def disabled(self, timeout=None, raise_err=None):
"""等待当前元素变成不可用
:param timeout: 超时时间为None使用元素所在页面timeout属性
:param raise_err: 等待失败时是否报错为None时根据Settings设置
:return: 成功返回元素对象失败返回False
"""
return self._wait_state('is_enabled', False, timeout, raise_err, err_text='等待元素变成不可用失败。')
def disabled_or_deleted(self, timeout=None, raise_err=None):
"""等待当前元素变成不可用或从DOM移除
:param timeout: 超时时间为None使用元素所在页面timeout属性
:param raise_err: 等待失败时是否报错为None时根据Settings设置
:return: 成功返回元素对象失败返回False
"""
if not self._ele.states.is_enabled or not self._ele.states.is_alive:
return self._ele
@ -488,13 +340,20 @@ class ElementWaiter(OriginWaiter):
else:
return False
def clickable(self, wait_moved=True, timeout=None, raise_err=None):
if timeout is None:
timeout = self._timeout
t1 = perf_counter()
r = self._wait_state('is_clickable', True, timeout, raise_err, err_text='等待元素可点击失败(等{}秒)。')
r = self.stop_moving(timeout=timeout - perf_counter() + t1) if wait_moved and r else r
if raise_err and not r:
raise WaitTimeoutError(f'等待元素可点击失败(等{timeout}秒)。')
return r
def has_rect(self, timeout=None, raise_err=None):
return self._wait_state('has_rect', True, timeout, raise_err, err_text='等待元素拥有大小及位置失败(等{}秒)。')
def stop_moving(self, timeout=None, gap=.1, raise_err=None):
"""等待当前元素停止运动
:param timeout: 超时时间为None使用元素所在页面timeout属性
:param gap: 检测间隔时间
:param raise_err: 等待失败时是否报错为None时根据Settings设置
:return: 成功返回元素对象失败返回False
"""
if timeout is None:
timeout = self._timeout
if timeout <= 0:
@ -524,39 +383,7 @@ class ElementWaiter(OriginWaiter):
else:
return False
def clickable(self, wait_moved=True, timeout=None, raise_err=None):
"""等待当前元素可被点击
:param wait_moved: 是否等待元素运动结束
:param timeout: 超时时间为None使用元素所在页面timeout属性
:param raise_err: 等待失败时是否报错为None时根据Settings设置
:return: 成功返回元素对象失败返回False
"""
if timeout is None:
timeout = self._timeout
t1 = perf_counter()
r = self._wait_state('is_clickable', True, timeout, raise_err, err_text='等待元素可点击失败(等{}秒)。')
r = self.stop_moving(timeout=timeout - perf_counter() + t1) if wait_moved and r else r
if raise_err and not r:
raise WaitTimeoutError(f'等待元素可点击失败(等{timeout}秒)。')
return r
def has_rect(self, timeout=None, raise_err=None):
"""等待当前元素有大小及位置属性
:param timeout: 超时时间为None使用元素所在页面timeout属性
:param raise_err: 等待失败时是否报错为None时根据Settings设置
:return: 成功返回元素四角坐标左上 右上 右下 左下失败返回False
"""
return self._wait_state('has_rect', True, timeout, raise_err, err_text='等待元素拥有大小及位置失败(等{}秒)。')
def _wait_state(self, attr, mode=False, timeout=None, raise_err=None, err_text=None):
"""等待元素某个元素状态到达指定状态
:param attr: 状态名称
:param mode: 等待True还是False
:param timeout: 超时时间为None使用元素所在页面timeout属性
:param raise_err: 等待失败时是否报错为None时根据Settings设置
:param err_text: 抛出错误时显示的信息
:return: 成功返回元素对象失败返回False
"""
a = self._ele.states.__getattribute__(attr)
if (a and mode) or (not a and not mode):
return self._ele if isinstance(a, bool) else a
@ -584,5 +411,4 @@ class FrameWaiter(BaseWaiter, ElementWaiter):
@property
def _timeout(self):
"""返回超时设置"""
return self._owner.timeout

View File

@ -5,7 +5,7 @@
@Copyright: (c) 2024 by g1879, Inc. All Rights Reserved.
@License : BSD 3-Clause.
"""
from typing import Union, Tuple, List
from typing import Union, Tuple, List, Any
from .downloader import DownloadMission
from .._base.browser import Chromium
@ -18,28 +18,63 @@ from .._pages.tabs import ChromiumTab, MixTab
class OriginWaiter(object):
_owner = ...
_owner: Any = ...
def __init__(self, owner): ...
def __init__(self, owner: Any): ...
def __call__(self, second: float, scope: float = None): ...
def __call__(self, second: float, scope: float = None):
"""等待若干秒,如传入两个参数,等待时间为这两个数间的一个随机数
:param second: 秒数
:param scope: 随机数范围
:return: None
"""
...
class BrowserWaiter(OriginWaiter):
_owner: Chromium = ...
def __init__(self, owner: Chromium): ...
def __init__(self, owner: Chromium):
"""
:param owner: Chromium对象
"""
...
def __call__(self, second: float, scope: float = None) -> Chromium: ...
def download_begin(self, timeout: float = None, cancel_it: bool = False) -> DownloadMission: ...
def __call__(self, second: float, scope: float = None) -> Chromium:
"""等待若干秒,如传入两个参数,等待时间为这两个数间的一个随机数
:param second: 秒数
:param scope: 随机数范围
:return: None
"""
...
def new_tab(self,
timeout: float = None,
curr_tab: Union[str, ChromiumTab] = None,
raise_err: bool = None) -> Union[str, bool]: ...
raise_err: bool = None) -> Union[str, bool]:
"""等待新标签页出现
:param timeout: 超时时间为None则使用页面对象timeout属性
:param curr_tab: 指定当前最新的tab对象或tab id用于判断新tab出现为None自动获取
:param raise_err: 等待失败时是否报错为None时根据Settings设置
:return: 等到新标签页返回其id否则返回False
"""
...
def all_downloads_done(self, timeout: float = None, cancel_if_timeout: bool = True) -> bool: ...
def download_begin(self, timeout: float = None, cancel_it: bool = False) -> DownloadMission:
"""等待浏览器下载开始,可将其拦截
:param timeout: 超时时间None使用页面对象超时时间
:param cancel_it: 是否取消该任务
:return: 成功返回任务对象失败返回False
"""
...
def all_downloads_done(self, timeout: float = None, cancel_if_timeout: bool = True) -> bool:
"""等待所有浏览器下载任务结束
:param timeout: 超时时间为None时无限等待
:param cancel_if_timeout: 超时时是否取消剩余任务
:return: 是否等待成功
"""
...
class BaseWaiter(OriginWaiter):
@ -48,131 +83,417 @@ class BaseWaiter(OriginWaiter):
def ele_deleted(self,
loc_or_ele: Union[str, tuple, ChromiumElement],
timeout: float = None,
raise_err: bool = None) -> bool: ...
raise_err: bool = None) -> bool:
"""等待元素从DOM中删除
:param loc_or_ele: 要等待的元素可以是已有元素定位符
:param timeout: 超时时间默认读取页面超时时间
:param raise_err: 等待失败时是否报错为None时根据Settings设置
:return: 是否等待成功
"""
...
def ele_displayed(self,
loc_or_ele: Union[str, tuple, ChromiumElement],
timeout: float = None,
raise_err: bool = None) -> bool: ...
raise_err: bool = None) -> bool:
"""等待元素变成显示状态
:param loc_or_ele: 要等待的元素可以是已有元素定位符
:param timeout: 超时时间默认读取页面超时时间
:param raise_err: 等待失败时是否报错为None时根据Settings设置
:return: 是否等待成功
"""
...
def ele_hidden(self, loc_or_ele: Union[str, tuple, ChromiumElement], timeout: float = None,
raise_err: bool = None) -> bool: ...
raise_err: bool = None) -> bool:
"""等待元素变成隐藏状态
:param loc_or_ele: 要等待的元素可以是已有元素定位符
:param timeout: 超时时间默认读取页面超时时间
:param raise_err: 等待失败时是否报错为None时根据Settings设置
:return: 是否等待成功
"""
...
def eles_loaded(self,
locators: Union[Tuple[str, str], str, list, tuple],
timeout: float = None,
any_one: bool = False,
raise_err: bool = None) -> bool: ...
raise_err: bool = None) -> bool:
"""等待元素加载到DOM可等待全部或任意一个
:param locators: 要等待的元素输入定位符用list输入多个
:param timeout: 超时时间默认读取页面超时时间
:param any_one: 是否等待到一个就返回
:param raise_err: 等待失败时是否报错为None时根据Settings设置
:return: 成功返回True失败返回False
"""
...
def _loading(self, timeout: float = None, start: bool = True, gap: float = .01, raise_err: bool = None) -> bool: ...
def load_start(self, timeout: float = None, raise_err: bool = None) -> bool:
"""等待页面开始加载
:param timeout: 超时时间为None时使用页面timeout属性
:param raise_err: 等待失败时是否报错为None时根据Settings设置
:return: 是否等待成功
"""
...
def load_start(self, timeout: float = None, raise_err: bool = None) -> bool: ...
def doc_loaded(self, timeout: float = None, raise_err: bool = None) -> bool:
"""等待页面加载完成
:param timeout: 超时时间为None时使用页面timeout属性
:param raise_err: 等待失败时是否报错为None时根据Settings设置
:return: 是否等待成功
"""
...
def doc_loaded(self, timeout: float = None, raise_err: bool = None) -> bool: ...
def upload_paths_inputted(self) -> bool:
"""等待自动填写上传文件路径"""
...
def upload_paths_inputted(self) -> bool: ...
def download_begin(self, timeout: float = None, cancel_it: bool = False) -> Union[DownloadMission, bool]:
"""等待浏览器下载开始,可将其拦截
:param timeout: 超时时间None使用页面对象超时时间
:param cancel_it: 是否取消该任务
:return: 成功返回任务对象失败返回False
"""
...
def download_begin(self, timeout: float = None, cancel_it: bool = False) -> Union[DownloadMission, bool]: ...
def url_change(self,
text: str,
exclude: bool = False,
timeout: float = None,
raise_err: bool = None) -> bool:
"""等待url变成包含或不包含指定文本
:param text: 用于识别的文本
:param exclude: 是否排除为True时当url不包含text指定文本时返回True
:param timeout: 超时时间
:param raise_err: 等待失败时是否报错为None时根据Settings设置
:return: 等待成功返回页面对象否则返回False
"""
...
def downloads_done(self, timeout: float = None, cancel_if_timeout: bool = True) -> bool: ...
def url_change(self, text: str, exclude: bool = False, timeout: float = None, raise_err: bool = None) -> bool: ...
def title_change(self, text: str, exclude: bool = False, timeout: float = None, raise_err: bool = None) -> bool: ...
def title_change(self,
text: str,
exclude: bool = False,
timeout: float = None,
raise_err: bool = None) -> bool:
"""等待title变成包含或不包含指定文本
:param text: 用于识别的文本
:param exclude: 是否排除为True时当title不包含text指定文本时返回True
:param timeout: 超时时间为None使用页面设置
:param raise_err: 等待失败时是否报错为None时根据Settings设置
:return: 等待成功返回页面对象否则返回False
"""
...
def _change(self, arg: str, text: str, exclude: bool = False, timeout: float = None,
raise_err: bool = None) -> bool: ...
raise_err: bool = None) -> bool:
"""等待指定属性变成包含或不包含指定文本
:param arg: 要被匹配的属性
:param text: 用于识别的文本
:param exclude: 是否排除为True时当属性不包含text指定文本时返回True
:param timeout: 超时时间
:param raise_err: 等待失败时是否报错为None时根据Settings设置
:return: 是否等待成功
"""
...
def _loading(self, timeout: float = None, start: bool = True, gap: float = .01, raise_err: bool = None) -> bool:
"""等待页面开始加载或加载完成
:param timeout: 超时时间为None时使用页面timeout属性
:param start: 等待开始还是结束
:param gap: 间隔秒数
:param raise_err: 等待失败时是否报错为None时根据Settings设置
:return: 是否等待成功
"""
...
class TabWaiter(BaseWaiter):
_owner: Union[ChromiumTab, MixTab] = ...
def __init__(self, owner: Union[ChromiumTab, MixTab]): ...
def __init__(self, owner: Union[ChromiumTab, MixTab]):
"""
:param owner: Tab对象
"""
...
def __call__(self, second: float, scope: float = None) -> Union[ChromiumTab, MixTab]: ...
def __call__(self, second: float, scope: float = None) -> Union[ChromiumTab, MixTab]:
"""等待若干秒,如传入两个参数,等待时间为这两个数间的一个随机数
:param second: 秒数
:param scope: 随机数范围
:return: None
"""
...
def downloads_done(self, timeout: float = None, cancel_if_timeout: bool = True) -> bool: ...
def downloads_done(self, timeout: float = None, cancel_if_timeout: bool = True) -> bool:
"""等待所有浏览器下载任务结束
:param timeout: 超时时间为None时无限等待
:param cancel_if_timeout: 超时时是否取消剩余任务
:return: 是否等待成功
"""
...
def alert_closed(self) -> None: ...
def alert_closed(self) -> None:
"""等待弹出框关闭"""
...
def url_change(self, text: str, exclude: bool = False,
timeout: float = None, raise_err: bool = None) -> Union[False, ChromiumTab, MixTab]: ...
timeout: float = None, raise_err: bool = None) -> Union[False, ChromiumTab, MixTab]:
"""等待url变成包含或不包含指定文本
:param text: 用于识别的文本
:param exclude: 是否排除为True时当url不包含text指定文本时返回True
:param timeout: 超时时间
:param raise_err: 等待失败时是否报错为None时根据Settings设置
:return: 等待成功返回页面对象否则返回False
"""
...
def title_change(self, text: str, exclude: bool = False,
timeout: float = None, raise_err: bool = None) -> Union[False, ChromiumTab, MixTab]: ...
timeout: float = None, raise_err: bool = None) -> Union[False, ChromiumTab, MixTab]:
"""等待title变成包含或不包含指定文本
:param text: 用于识别的文本
:param exclude: 是否排除为True时当title不包含text指定文本时返回True
:param timeout: 超时时间为None使用页面设置
:param raise_err: 等待失败时是否报错为None时根据Settings设置
:return: 等待成功返回页面对象否则返回False
"""
...
class PageWaiter(TabWaiter):
_owner: Union[ChromiumPage, MixPage] = ...
def __init__(self, owner: Union[ChromiumPage, MixPage]): ...
def __init__(self, owner: Union[ChromiumPage, MixPage]):
"""
:param owner: Page对象
"""
...
def __call__(self, second: float, scope: float = None) -> Union[ChromiumPage, MixPage]: ...
def __call__(self, second: float, scope: float = None) -> Union[ChromiumPage, MixPage]:
"""等待若干秒,如传入两个参数,等待时间为这两个数间的一个随机数
:param second: 秒数
:param scope: 随机数范围
:return: None
"""
...
def new_tab(self, timeout: float = None, raise_err: bool = None) -> Union[str, bool]: ...
def new_tab(self, timeout: float = None, raise_err: bool = None) -> Union[str, bool]:
"""等待新标签页出现
:param timeout: 超时时间为None则使用页面对象timeout属性
:param raise_err: 等待失败时是否报错为None时根据Settings设置
:return: 等到新标签页返回其id否则返回False
"""
...
def all_downloads_done(self, timeout: float = None, cancel_if_timeout: bool = True) -> bool: ...
def all_downloads_done(self, timeout: float = None, cancel_if_timeout: bool = True) -> bool:
"""等待所有浏览器下载任务结束
:param timeout: 超时时间为None时无限等待
:param cancel_if_timeout: 超时时是否取消剩余任务
:return: 是否等待成功
"""
...
def url_change(self, text: str, exclude: bool = False,
timeout: float = None, raise_err: bool = None) -> Union[False, ChromiumPage, MixPage]: ...
timeout: float = None, raise_err: bool = None) -> Union[False, ChromiumPage, MixPage]:
"""等待url变成包含或不包含指定文本
:param text: 用于识别的文本
:param exclude: 是否排除为True时当url不包含text指定文本时返回True
:param timeout: 超时时间
:param raise_err: 等待失败时是否报错为None时根据Settings设置
:return: 等待成功返回页面对象否则返回False
"""
...
def title_change(self, text: str, exclude: bool = False,
timeout: float = None, raise_err: bool = None) -> Union[False, ChromiumPage, MixPage]: ...
timeout: float = None, raise_err: bool = None) -> Union[False, ChromiumPage, MixPage]:
"""等待title变成包含或不包含指定文本
:param text: 用于识别的文本
:param exclude: 是否排除为True时当title不包含text指定文本时返回True
:param timeout: 超时时间为None使用页面设置
:param raise_err: 等待失败时是否报错为None时根据Settings设置
:return: 等待成功返回页面对象否则返回False
"""
...
class ElementWaiter(OriginWaiter):
_owner: ChromiumElement = ...
_ele: ChromiumElement = ...
def __init__(self, owner: ChromiumElement): ...
def __init__(self, owner: ChromiumElement):
"""
:param owner: ChromiumElement对象
"""
...
def __call__(self, second: float, scope: float = None) -> ChromiumElement: ...
def __call__(self,
second: float,
scope: float = None) -> ChromiumElement:
"""等待若干秒,如传入两个参数,等待时间为这两个数间的一个随机数
:param second: 秒数
:param scope: 随机数范围
:return: None
"""
...
@property
def _timeout(self) -> float: ...
def _timeout(self) -> float:
"""返回超时设置"""
...
def deleted(self, timeout: float = None, raise_err: bool = None) -> Union[ChromiumElement, False]: ...
def deleted(self, timeout: float = None, raise_err: bool = None) -> Union[ChromiumElement, False]:
"""等待元素从dom删除
:param timeout: 超时时间为None使用元素所在页面timeout属性
:param raise_err: 等待失败时是否报错为None时根据Settings设置
:return: 成功返回元素对象失败返回False
"""
...
def displayed(self, timeout: float = None, raise_err: bool = None) -> Union[ChromiumElement, False]: ...
def displayed(self, timeout: float = None, raise_err: bool = None) -> Union[ChromiumElement, False]:
"""等待元素从dom显示
:param timeout: 超时时间为None使用元素所在页面timeout属性
:param raise_err: 等待失败时是否报错为None时根据Settings设置
:return: 成功返回元素对象失败返回False
"""
...
def hidden(self, timeout: float = None, raise_err: bool = None) -> Union[ChromiumElement, False]: ...
def hidden(self, timeout: float = None, raise_err: bool = None) -> Union[ChromiumElement, False]:
"""等待元素从dom隐藏
:param timeout: 超时时间为None使用元素所在页面timeout属性
:param raise_err: 等待失败时是否报错为None时根据Settings设置
:return: 成功返回元素对象失败返回False
"""
...
def covered(self, timeout: float = None, raise_err: bool = None) -> Union[False, int]: ...
def covered(self, timeout: float = None, raise_err: bool = None) -> Union[False, int]:
"""等待当前元素被遮盖
:param timeout: 超时时间为None使用元素所在页面timeout属性
:param raise_err: 等待失败时是否报错为None时根据Settings设置
:return: 成功返回覆盖元素id返回False
"""
...
def not_covered(self, timeout: float = None, raise_err: bool = None) -> Union[ChromiumElement, False]: ...
def not_covered(self, timeout: float = None, raise_err: bool = None) -> Union[ChromiumElement, False]:
"""等待当前元素不被遮盖
:param timeout: 超时时间为None使用元素所在页面timeout属性
:param raise_err: 等待失败时是否报错为None时根据Settings设置
:return: 成功返回元素对象失败返回False
"""
...
def enabled(self, timeout: float = None, raise_err: bool = None) -> Union[ChromiumElement, False]: ...
def enabled(self, timeout: float = None, raise_err: bool = None) -> Union[ChromiumElement, False]:
"""等待当前元素变成可用
:param timeout: 超时时间为None使用元素所在页面timeout属性
:param raise_err: 等待失败时是否报错为None时根据Settings设置
:return: 成功返回元素对象失败返回False
"""
...
def disabled(self, timeout: float = None, raise_err: bool = None) -> Union[ChromiumElement, False]: ...
def disabled(self, timeout: float = None, raise_err: bool = None) -> Union[ChromiumElement, False]:
"""等待当前元素变成不可用
:param timeout: 超时时间为None使用元素所在页面timeout属性
:param raise_err: 等待失败时是否报错为None时根据Settings设置
:return: 成功返回元素对象失败返回False
"""
...
def disabled_or_deleted(self, timeout: float = None, raise_err: bool = None) -> bool:
"""等待当前元素变成不可用或从DOM移除
:param timeout: 超时时间为None使用元素所在页面timeout属性
:param raise_err: 等待失败时是否报错为None时根据Settings设置
:return: 成功返回元素对象失败返回False
"""
...
def clickable(self, wait_moved: bool = True,
timeout: float = None, raise_err: bool = None) -> Union[ChromiumElement, False]: ...
timeout: float = None, raise_err: bool = None) -> Union[ChromiumElement, False]:
"""等待当前元素可被点击
:param wait_moved: 是否等待元素运动结束
:param timeout: 超时时间为None使用元素所在页面timeout属性
:param raise_err: 等待失败时是否报错为None时根据Settings设置
:return: 成功返回元素对象失败返回False
"""
...
def has_rect(self,
timeout: float = None,
raise_err: bool = None) -> Union[False, List[Tuple[float, float]]]: ...
raise_err: bool = None) -> Union[False, List[Tuple[float, float]]]:
"""等待当前元素有大小及位置属性
:param timeout: 超时时间为None使用元素所在页面timeout属性
:param raise_err: 等待失败时是否报错为None时根据Settings设置
:return: 成功返回元素四角坐标左上 右上 右下 左下失败返回False
"""
...
def disabled_or_deleted(self, timeout: float = None, raise_err: bool = None) -> bool: ...
def stop_moving(self, timeout: float = None, gap: float = .1, raise_err: bool = None) -> Union[ChromiumElement, False]: ...
def stop_moving(self, timeout: float = None, gap: float = .1, raise_err: bool = None) -> Union[
ChromiumElement, False]:
"""等待当前元素停止运动
:param timeout: 超时时间为None使用元素所在页面timeout属性
:param gap: 检测间隔时间
:param raise_err: 等待失败时是否报错为None时根据Settings设置
:return: 成功返回元素对象失败返回False
"""
...
def _wait_state(self,
attr: str,
mode: bool = False,
timeout: float = None,
raise_err: bool = None,
err_text: str = None) -> Union[ChromiumElement, False]: ...
err_text: str = None) -> Union[ChromiumElement, False]:
"""等待元素某个元素状态到达指定状态
:param attr: 状态名称
:param mode: 等待True还是False
:param timeout: 超时时间为None使用元素所在页面timeout属性
:param raise_err: 等待失败时是否报错为None时根据Settings设置
:param err_text: 抛出错误时显示的信息
:return: 成功返回元素对象失败返回False
"""
...
class FrameWaiter(BaseWaiter, ElementWaiter):
_owner: ChromiumFrame = ...
def __init__(self, owner: ChromiumFrame): ...
def __init__(self, owner: ChromiumFrame):
"""
:param owner: ChromiumFrame对象
"""
...
def __call__(self, second: float, scope: float = None) -> ChromiumFrame: ...
def __call__(self,
second: float,
scope: float = None) -> ChromiumFrame:
"""等待若干秒,如传入两个参数,等待时间为这两个数间的一个随机数
:param second: 秒数
:param scope: 随机数范围
:return: None
"""
...
def url_change(self, text: str, exclude: bool = False,
timeout: float = None, raise_err: bool = None) -> Union[False, ChromiumFrame]: ...
def url_change(self,
text: str,
exclude: bool = False,
timeout: float = None,
raise_err: bool = None) -> Union[False, ChromiumFrame]:
"""等待url变成包含或不包含指定文本
:param text: 用于识别的文本
:param exclude: 是否排除为True时当url不包含text指定文本时返回True
:param timeout: 超时时间
:param raise_err: 等待失败时是否报错为None时根据Settings设置
:return: 等待成功返回页面对象否则返回False
"""
...
def title_change(self, text: str, exclude: bool = False,
timeout: float = None, raise_err: bool = None) -> Union[False, ChromiumFrame]: ...
def title_change(self,
text: str,
exclude: bool = False,
timeout: float = None,
raise_err: bool = None) -> Union[False, ChromiumFrame]:
"""等待title变成包含或不包含指定文本
:param text: 用于识别的文本
:param exclude: 是否排除为True时当title不包含text指定文本时返回True
:param timeout: 超时时间为None使用页面设置
:param raise_err: 等待失败时是否报错为None时根据Settings设置
:return: 等待成功返回页面对象否则返回False
"""
...