From f68dd8e743eae14dcb8c01215924aa276b348c26 Mon Sep 17 00:00:00 2001 From: g1879 Date: Fri, 16 Aug 2024 16:22:48 +0800 Subject: [PATCH] =?UTF-8?q?4.1.0.0b20=E4=BF=AE=E6=94=B9=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DrissionPage/__init__.py | 2 +- DrissionPage/_base/browser.pyi | 4 +- DrissionPage/_elements/session_element.py | 2 +- DrissionPage/_elements/session_element.pyi | 4 +- DrissionPage/_functions/tools.pyi | 2 +- DrissionPage/_functions/web.py | 7 +- DrissionPage/_pages/chromium_base.pyi | 2 +- DrissionPage/_pages/chromium_page.py | 72 +---- DrissionPage/_pages/chromium_page.pyi | 169 ++++++++-- DrissionPage/_pages/mix_page.py | 125 +------- DrissionPage/_pages/mix_page.pyi | 349 ++++++++++++++++----- DrissionPage/_pages/tabs.pyi | 8 +- DrissionPage/_units/waiter.py | 17 +- DrissionPage/_units/waiter.pyi | 232 ++++++++++++-- requirements.txt | 2 +- setup.py | 2 +- 16 files changed, 638 insertions(+), 361 deletions(-) diff --git a/DrissionPage/__init__.py b/DrissionPage/__init__.py index 39c0eb0..ca587ef 100644 --- a/DrissionPage/__init__.py +++ b/DrissionPage/__init__.py @@ -14,4 +14,4 @@ from ._pages.chromium_page import ChromiumPage from ._pages.mix_page import MixPage from ._pages.mix_page import MixPage as WebPage -__version__ = '4.1.0.0b19' +__version__ = '4.1.0.0b20' diff --git a/DrissionPage/_base/browser.pyi b/DrissionPage/_base/browser.pyi index ed5305c..33f8423 100644 --- a/DrissionPage/_base/browser.pyi +++ b/DrissionPage/_base/browser.pyi @@ -113,7 +113,7 @@ class Chromium(object): ... @property - def latest_tab(self) -> Union[ChromiumTab, str]: + def latest_tab(self) -> Union[ChromiumTab, MixTab, str]: """返回最新的标签页,最新标签页指最后创建或最后被激活的 当Settings.singleton_tab_obj==True时返回Tab对象,否则返回tab id""" ... @@ -206,7 +206,7 @@ class Chromium(object): tab_type: str = 'page', as_id: bool = False) -> Union[MixTab, str]: """获取一个标签页对象,id_or_num不为None时,后面几个参数无效 - :param id_or_num: 要获取的标签页id或序号,序号从1开始,可传入负数获取倒数第几个,不是视觉排列顺序,而是激活顺序 + :param id_or_num: 要获取的标签页id或序号,序号从1开始,可传入负数获取倒数第几个,不是视觉排列顺序,而是激活顺序,为None时获取最后的 :param title: 要匹配title的文本,模糊匹配,为None则匹配所有 :param url: 要匹配url的文本,模糊匹配,为None则匹配所有 :param tab_type: tab类型,可用列表输入多个,如 'page', 'iframe' 等,为None则匹配所有 diff --git a/DrissionPage/_elements/session_element.py b/DrissionPage/_elements/session_element.py index 7ed8bdb..797ae7d 100644 --- a/DrissionPage/_elements/session_element.py +++ b/DrissionPage/_elements/session_element.py @@ -69,7 +69,7 @@ class SessionElement(DrissionElement): def raw_text(self): return str(self._inner_ele.text_content()) - def parent(self, level_or_loc=1, index=1): + def parent(self, level_or_loc=1, index=1, timeout: float = None): return super().parent(level_or_loc, index) def child(self, locator='', index=1, timeout=None, ele_only=True): diff --git a/DrissionPage/_elements/session_element.pyi b/DrissionPage/_elements/session_element.pyi index 506df00..e967a5f 100644 --- a/DrissionPage/_elements/session_element.pyi +++ b/DrissionPage/_elements/session_element.pyi @@ -77,10 +77,12 @@ class SessionElement(DrissionElement): def parent(self, level_or_loc: Union[tuple, str, int] = 1, - index: int = 1) -> SessionElement: + index: int = 1, + timeout: float = None) -> SessionElement: """返回上面某一级父元素,可指定层数或用查询语法定位 :param level_or_loc: 第几级父元素,或定位符 :param index: 当level_or_loc传入定位符,使用此参数选择第几个结果 + :param timeout: 此参数不起实际作用 :return: 上级元素对象 """ ... diff --git a/DrissionPage/_functions/tools.pyi b/DrissionPage/_functions/tools.pyi index 5946a9c..8a7c3c8 100644 --- a/DrissionPage/_functions/tools.pyi +++ b/DrissionPage/_functions/tools.pyi @@ -90,7 +90,7 @@ def wait_until(function: callable, kwargs: dict = None, timeout: float = 10): ... -def configs_to_here(file_name: Union[Path, str] = None) -> None: +def configs_to_here(save_name: Union[Path, str] = None) -> None: """把默认ini文件复制到当前目录 :param save_name: 指定文件名,为None则命名为'dp_configs.ini' :return: None diff --git a/DrissionPage/_functions/web.py b/DrissionPage/_functions/web.py index 58bfd22..387b73e 100644 --- a/DrissionPage/_functions/web.py +++ b/DrissionPage/_functions/web.py @@ -31,7 +31,7 @@ def get_ele_txt(e): if e.tag in noText_list: return e.raw_text - def get_node_txt(ele, pre: bool = False): + def get_node_txt(ele, pre=False) -> list: tag = ele.tag if tag == 'br': return [True] @@ -84,10 +84,10 @@ def get_ele_txt(e): if i1 is True: r.append('\n') continue - if i2 is True: + elif i2 is True: r.append(i1) continue - if i1.endswith(' ') and i2.startswith(' '): + elif i1.endswith(' ') and i2.startswith(' '): i1 = i1[:-1] r.append(i1) r.append('\n' if re_str[-1] is True else re_str[-1]) @@ -253,7 +253,6 @@ def get_pdf(page, path=None, name=None, kwargs=None): def tree(ele_or_page, text=False, show_js=False, show_css=False): - def _tree(obj, last_one=True, body=''): list_ele = obj.children() length = len(list_ele) diff --git a/DrissionPage/_pages/chromium_base.pyi b/DrissionPage/_pages/chromium_base.pyi index 7965bf1..c5a58ed 100644 --- a/DrissionPage/_pages/chromium_base.pyi +++ b/DrissionPage/_pages/chromium_base.pyi @@ -31,7 +31,7 @@ PIC_TYPE = Literal['jpg', 'jpeg', 'png', 'webp', True] class ChromiumBase(BasePage): - _tab: Union[ChromiumTab, MixTab, ChromiumFrame] = ... + _tab: Union[ChromiumTab, MixTab, ChromiumFrame, ChromiumPage, MixPage] = ... _browser: Chromium = ... _driver: Optional[Driver] = ... _frame_id: str = ... diff --git a/DrissionPage/_pages/chromium_page.py b/DrissionPage/_pages/chromium_page.py index ef4ee2f..ef50d21 100644 --- a/DrissionPage/_pages/chromium_page.py +++ b/DrissionPage/_pages/chromium_page.py @@ -11,7 +11,7 @@ from .._base.browser import Chromium from .._functions.web import save_page from .._pages.chromium_base import ChromiumBase from .._units.setter import ChromiumPageSetter -from .._units.waiter import PageWaiter +from .._units.waiter import ChromiumPageWaiter class ChromiumPage(ChromiumBase): @@ -19,11 +19,6 @@ class ChromiumPage(ChromiumBase): _PAGES = {} def __new__(cls, addr_or_opts=None, tab_id=None, timeout=None): - """ - :param addr_or_opts: 浏览器地址:端口、ChromiumOptions对象或端口数字(int) - :param tab_id: 要控制的标签页id,不指定默认为激活的 - :param timeout: 超时时间(秒) - """ browser = Chromium(addr_or_opts=addr_or_opts) if browser.id in cls._PAGES: r = cls._PAGES[browser.id] @@ -37,11 +32,6 @@ class ChromiumPage(ChromiumBase): return r def __init__(self, addr_or_opts=None, tab_id=None, timeout=None): - """ - :param addr_or_opts: 浏览器地址:端口、ChromiumOptions对象或端口数字(int) - :param tab_id: 要控制的标签页id,不指定默认为激活的 - :param timeout: 超时时间(秒) - """ if hasattr(self, '_created'): return self._created = True @@ -62,127 +52,69 @@ class ChromiumPage(ChromiumBase): @property def set(self): - """返回用于设置的对象""" if self._set is None: self._set = ChromiumPageSetter(self) return self._set @property def wait(self): - """返回用于等待的对象""" if self._wait is None: - self._wait = PageWaiter(self) + self._wait = ChromiumPageWaiter(self) return self._wait - # ----------挂件---------- - @property def browser(self): - """返回用于控制浏览器cdp的driver""" return self._browser @property def tabs_count(self): - """返回标签页数量""" return self.browser.tabs_count @property def tab_ids(self): - """返回所有标签页id组成的列表""" return self.browser.tab_ids @property def latest_tab(self): - """返回最新的标签页,最新标签页指最后创建或最后被激活的 - 当Settings.singleton_tab_obj==True时返回Tab对象,否则返回tab id""" return self.browser.latest_tab @property def process_id(self): - """返回浏览器进程id""" return self.browser.process_id @property def browser_version(self): - """返回所控制的浏览器版本号""" return self._browser.version @property def address(self): - """返回浏览器地址ip:port""" return self.browser.address def save(self, path=None, name=None, as_pdf=False, **kwargs): - """把当前页面保存为文件,如果path和name参数都为None,只返回文本 - :param path: 保存路径,为None且name不为None时保存在当前路径 - :param name: 文件名,为None且path不为None时用title属性值 - :param as_pdf: 为Ture保存为pdf,否则为mhtml且忽略kwargs参数 - :param kwargs: pdf生成参数 - :return: as_pdf为True时返回bytes,否则返回文件文本 - """ return save_page(self, path, name, as_pdf, kwargs) def get_tab(self, id_or_num=None, title=None, url=None, tab_type='page', as_id=False): - """获取一个标签页对象,id_or_num不为None时,后面几个参数无效 - :param id_or_num: 要获取的标签页id或序号,序号从1开始,可传入负数获取倒数第几个,不是视觉排列顺序,而是激活顺序 - :param title: 要匹配title的文本,模糊匹配,为None则匹配所有 - :param url: 要匹配url的文本,模糊匹配,为None则匹配所有 - :param tab_type: tab类型,可用列表输入多个,如 'page', 'iframe' 等,为None则匹配所有 - :param as_id: 是否返回标签页id而不是标签页对象 - :return: ChromiumTab对象 - """ return self.browser.get_tab(id_or_num=id_or_num, title=title, url=url, tab_type=tab_type, as_id=as_id) def get_tabs(self, title=None, url=None, tab_type='page', as_id=False): - """查找符合条件的tab,返回它们组成的列表 - :param title: 要匹配title的文本,模糊匹配,为None则匹配所有 - :param url: 要匹配url的文本,模糊匹配,为None则匹配所有 - :param tab_type: tab类型,可用列表输入多个,如 'page', 'iframe' 等,为None则匹配所有 - :param as_id: 是否返回标签页id而不是标签页对象 - :return: ChromiumTab对象组成的列表 - """ return self.browser.get_tabs(title=title, url=url, tab_type=tab_type, as_id=as_id) def new_tab(self, url=None, new_window=False, background=False, new_context=False): - """新建一个标签页 - :param url: 新标签页跳转到的网址 - :param new_window: 是否在新窗口打开标签页 - :param background: 是否不激活新标签页,如new_window为True则无效 - :param new_context: 是否创建新的上下文 - :return: 新标签页对象 - """ return self.browser.new_tab(url=url, new_window=new_window, background=background, new_context=new_context) def activate_tab(self, id_ind_tab): - """使标签页变为活动状态 - :param id_ind_tab: 标签页id(str)、Tab对象或标签页序号(int),序号从1开始 - :return: None - """ self.browser.activate_tab(id_ind_tab) def close(self): - """关闭Page管理的标签页""" self.close_tabs(self.tab_id) def close_tabs(self, tabs_or_ids=None, others=False): - """关闭传入的标签页,默认关闭当前页。可传入多个 - :param tabs_or_ids: 要关闭的标签页对象或id,可传入列表或元组,为None时关闭当前页 - :param others: 是否关闭指定标签页之外的 - :return: None - """ self.browser.close_tabs(tabs_or_ids=tabs_or_ids or self.tab_id, others=others) def quit(self, timeout=5, force=True, del_data=False): - """关闭浏览器 - :param timeout: 等待浏览器关闭超时时间(秒) - :param force: 关闭超时是否强制终止进程 - :param del_data: 是否删除用户文件夹 - :return: None - """ self.browser.quit(timeout, force, del_data=del_data) def _on_disconnect(self): - """浏览器退出时执行""" ChromiumPage._PAGES.pop(self._browser.id, None) def __repr__(self): diff --git a/DrissionPage/_pages/chromium_page.pyi b/DrissionPage/_pages/chromium_page.pyi index 992ced3..5ef3e66 100644 --- a/DrissionPage/_pages/chromium_page.pyi +++ b/DrissionPage/_pages/chromium_page.pyi @@ -14,7 +14,7 @@ from .._pages.chromium_base import ChromiumBase from .._pages.tabs import ChromiumTab from .._units.rect import TabRect from .._units.setter import ChromiumPageSetter -from .._units.waiter import PageWaiter +from .._units.waiter import ChromiumPageWaiter class ChromiumPage(ChromiumBase): @@ -27,45 +27,70 @@ class ChromiumPage(ChromiumBase): def __new__(cls, addr_or_opts: Union[str, int, ChromiumOptions] = None, tab_id: str = None, - timeout: float = None): ... + timeout: float = None): + """ + :param addr_or_opts: 浏览器地址:端口、ChromiumOptions对象或端口数字(int) + :param tab_id: 要控制的标签页id,不指定默认为激活的 + :param timeout: 超时时间(秒) + """ + ... def __init__(self, addr_or_opts: Union[str, int, ChromiumOptions] = None, tab_id: str = None, - timeout: float = None):... - - def _handle_options(self, addr_or_opts: Union[str, ChromiumOptions]) -> str: ... - - def _run_browser(self) -> None: ... - - def _page_init(self) -> None: ... + timeout: float = None): + """ + :param addr_or_opts: 浏览器地址:端口、ChromiumOptions对象或端口数字(int) + :param tab_id: 要控制的标签页id,不指定默认为激活的 + :param timeout: 超时时间(秒) + """ + ... @property - def browser(self) -> Chromium: ... + def set(self) -> ChromiumPageSetter: + """返回用于设置的对象""" + ... @property - def tabs_count(self) -> int: ... + def wait(self) -> ChromiumPageWaiter: + """返回用于等待的对象""" + ... @property - def tab_ids(self) -> List[str]: ... + def browser(self) -> Chromium: + """返回浏览器对象""" + ... @property - def wait(self) -> PageWaiter: ... + def tabs_count(self) -> int: + """返回标签页数量""" + ... @property - def latest_tab(self) -> Union[ChromiumTab, ChromiumPage, str]: ... + def tab_ids(self) -> List[str]: + """返回所有标签页id组成的列表""" + ... @property - def process_id(self) -> Optional[int]: ... + def latest_tab(self) -> Union[ChromiumTab, ChromiumPage, str]: + """返回最新的标签页,最新标签页指最后创建或最后被激活的 + 当Settings.singleton_tab_obj==True时返回Tab对象,否则返回tab id""" + ... @property - def browser_version(self) -> str: ... + def process_id(self) -> Optional[int]: + """返回浏览器进程id""" + ... @property - def address(self) -> str: ... + def browser_version(self) -> str: + """返回所控制的浏览器版本号""" + ... @property - def set(self) -> ChromiumPageSetter: ... + def address(self) -> str: + """返回浏览器地址ip:port""" + ... def save(self, path: Union[str, Path] = None, @@ -86,31 +111,117 @@ class ChromiumPage(ChromiumBase): footerTemplate: str = ..., preferCSSPageSize: bool = ..., generateTaggedPDF: bool = ..., - generateDocumentOutline: bool = ...) -> Union[bytes, str]: ... + generateDocumentOutline: bool = ...) -> Union[bytes, str]: + """把当前页面保存为文件,如果path和name参数都为None,只返回文本 + :param path: 保存路径,为None且name不为None时保存在当前路径 + :param name: 文件名,为None且path不为None时用title属性值 + :param as_pdf: 为Ture保存为pdf,否则为mhtml且忽略kwargs参数 + :param landscape: 纸张方向,as_pdf为True时才生效 + :param displayHeaderFooter: 是否显示页头页脚,as_pdf为True时才生效 + :param printBackground: 是否打印背景图片,as_pdf为True时才生效 + :param scale: 缩放比例,as_pdf为True时才生效 + :param paperWidth: 页面宽度(英寸),as_pdf为True时才生效 + :param paperHeight: 页面高度(英寸),as_pdf为True时才生效 + :param marginTop: 上边距(英寸),as_pdf为True时才生效 + :param marginBottom: 下边距(英寸),as_pdf为True时才生效 + :param marginLeft: 左边距(英寸),as_pdf为True时才生效 + :param marginRight: 右边距(英寸),as_pdf为True时才生效 + :param pageRanges: 页面范围,格式'1-5, 8, 11-13',as_pdf为True时才生效 + :param headerTemplate: 页头HTML模板,as_pdf为True时才生效 + 模板可包含以下class: + - date:日期 + - title:文档标题 + - url:文档url + - pageNumber:当前页码 + - totalPages:总页数 + 示例: + :param footerTemplate: 页脚HTML模板,格式与页头的一样,as_pdf为True时才生效 + :param preferCSSPageSize: 是否使用css定义的页面大小,as_pdf为True时才生效 + :param generateTaggedPDF: 是否生成带标签的(可访问的)PDF。默认为嵌入器选择,as_pdf为True时才生效 + :param generateDocumentOutline: 是否将文档大纲嵌入到PDF中。,as_pdf为True时才生效 + :return: as_pdf为True时返回bytes,否则返回文件文本 + """ + ... def get_tab(self, id_or_num: Union[str, ChromiumTab, int] = None, title: str = None, url: str = None, tab_type: Union[str, list, tuple] = 'page', - as_id: bool = False) -> Union[ChromiumTab, str, None]: ... + as_id: bool = False) -> Union[ChromiumTab, str, None]: + """获取一个标签页对象,id_or_num不为None时,后面几个参数无效 + :param id_or_num: 要获取的标签页id或序号,序号从1开始,可传入负数获取倒数第几个,不是视觉排列顺序,而是激活顺序 + :param title: 要匹配title的文本,模糊匹配,为None则匹配所有 + :param url: 要匹配url的文本,模糊匹配,为None则匹配所有 + :param tab_type: tab类型,可用列表输入多个,如 'page', 'iframe' 等,为None则匹配所有 + :param as_id: 是否返回标签页id而不是标签页对象 + :return: ChromiumTab对象 + """ + ... def get_tabs(self, title: str = None, url: str = None, tab_type: Union[str, list, tuple] = 'page', - as_id: bool = False) -> Union[List[ChromiumTab], List[str]]: ... + as_id: bool = False) -> Union[List[ChromiumTab], List[str]]: + """查找符合条件的tab,返回它们组成的列表 + :param title: 要匹配title的文本,模糊匹配,为None则匹配所有 + :param url: 要匹配url的文本,模糊匹配,为None则匹配所有 + :param tab_type: tab类型,可用列表输入多个,如 'page', 'iframe' 等,为None则匹配所有 + :param as_id: 是否返回标签页id而不是标签页对象 + :return: ChromiumTab对象组成的列表 + """ + ... - def new_tab(self, url: str = None, new_window: bool = False, background: bool = False, - new_context: bool = False) -> ChromiumTab: ... + def new_tab(self, + url: str = None, + new_window: bool = False, + background: bool = False, + new_context: bool = False) -> ChromiumTab: + """新建一个标签页 + :param url: 新标签页跳转到的网址 + :param new_window: 是否在新窗口打开标签页 + :param background: 是否不激活新标签页,如new_window为True则无效 + :param new_context: 是否创建新的上下文 + :return: 新标签页对象 + """ + ... - def activate_tab(self, id_ind_tab: Union[int, str, ChromiumTab]) -> None: ... + def activate_tab(self, + id_ind_tab: Union[int, str, ChromiumTab]) -> None: + """使标签页变为活动状态 + :param id_ind_tab: 标签页id(str)、Tab对象或标签页序号(int),序号从1开始 + :return: None + """ + ... - def close(self) -> None: ... + def close(self) -> None: + """关闭Page管理的标签页""" + ... - def close_tabs(self, tabs_or_ids: Union[str, ChromiumTab, List[Union[str, ChromiumTab]], - Tuple[Union[str, ChromiumTab]]] = None, others: bool = False) -> None: ... + def close_tabs(self, + tabs_or_ids: Union[str, ChromiumTab, List[Union[str, ChromiumTab]], + Tuple[Union[str, ChromiumTab]]] = None, + others: bool = False) -> None: + """关闭传入的标签页,默认关闭当前页。可传入多个 + :param tabs_or_ids: 要关闭的标签页对象或id,可传入列表或元组,为None时关闭当前页 + :param others: 是否关闭指定标签页之外的 + :return: None + """ + ... - def quit(self, timeout: float = 5, force: bool = True, del_data: bool = False) -> None: ... + def quit(self, + timeout: float = 5, + force: bool = True, + del_data: bool = False) -> None: + """关闭浏览器 + :param timeout: 等待浏览器关闭超时时间(秒) + :param force: 关闭超时是否强制终止进程 + :param del_data: 是否删除用户文件夹 + :return: None + """ + ... - def _on_disconnect(self) -> None: ... + def _on_disconnect(self) -> None: + """浏览器退出时执行""" + ... diff --git a/DrissionPage/_pages/mix_page.py b/DrissionPage/_pages/mix_page.py index 24f9295..ed994ed 100644 --- a/DrissionPage/_pages/mix_page.py +++ b/DrissionPage/_pages/mix_page.py @@ -10,6 +10,7 @@ from .session_page import SessionPage from .._base.base import BasePage from .._configs.chromium_options import ChromiumOptions from .._functions.cookies import set_session_cookies, set_tab_cookies +from .._functions.settings import Settings from .._units.setter import MixPageSetter @@ -26,12 +27,6 @@ class MixPage(SessionPage, ChromiumPage, BasePage): return super().__new__(cls, chromium_options) def __init__(self, mode='d', timeout=None, chromium_options=None, session_or_options=None): - """初始化函数 - :param mode: 'd' 或 's',即driver模式和session模式 - :param timeout: 超时时间(秒),d模式时为寻找元素时间,s模式时为连接时间,默认10秒 - :param chromium_options: ChromiumOptions对象,只使用s模式时应传入False - :param session_or_options: Session对象或SessionOptions对象,只使用d模式时应传入False - """ if hasattr(self, '_created'): return @@ -50,28 +45,23 @@ class MixPage(SessionPage, ChromiumPage, BasePage): self.change_mode(self._mode, go=False, copy_cookies=False) def __call__(self, locator, index=1, timeout=None): - """在内部查找元素 - 例:ele = page('@id=ele_id') - :param locator: 元素的定位信息,可以是loc元组,或查询字符串 - :param index: 获取第几个,从1开始,可传入负数获取倒数第几个 - :param timeout: 超时时间(秒) - :return: 子元素对象 - """ if self._mode == 'd': return super(SessionPage, self).__call__(locator, index=index, timeout=timeout) elif self._mode == 's': return super().__call__(locator, index=index) + @property + def latest_tab(self): + return self.browser.get_mix_tab(self.tab_ids[0], as_id=not Settings.singleton_tab_obj) + @property def set(self): - """返回用于设置的对象""" if self._set is None: self._set = MixPageSetter(self) return self._set @property def url(self): - """返回当前url""" if self._mode == 'd': return self._browser_url elif self._mode == 's': @@ -79,12 +69,10 @@ class MixPage(SessionPage, ChromiumPage, BasePage): @property def _browser_url(self): - """返回浏览器当前url""" return super(SessionPage, self).url if self._driver else None @property def title(self): - """返回当前页面title""" if self._mode == 's': return super().title elif self._mode == 'd': @@ -92,7 +80,6 @@ class MixPage(SessionPage, ChromiumPage, BasePage): @property def raw_data(self): - """返回页码原始数据数据""" if self._mode == 's': return super().raw_data elif self._mode == 'd': @@ -100,7 +87,6 @@ class MixPage(SessionPage, ChromiumPage, BasePage): @property def html(self): - """返回页面html文本""" if self._mode == 's': return super().html elif self._mode == 'd': @@ -108,7 +94,6 @@ class MixPage(SessionPage, ChromiumPage, BasePage): @property def json(self): - """当返回内容是json格式时,返回对应的字典""" if self._mode == 's': return super().json elif self._mode == 'd': @@ -116,17 +101,14 @@ class MixPage(SessionPage, ChromiumPage, BasePage): @property def response(self): - """返回 s 模式获取到的 Response 对象,切换到 s 模式""" return self._response @property def mode(self): - """返回当前模式,'s'或'd' """ return self._mode @property def user_agent(self): - """返回user agent""" if self._mode == 's': return super().user_agent elif self._mode == 'd': @@ -134,31 +116,19 @@ class MixPage(SessionPage, ChromiumPage, BasePage): @property def session(self): - """返回Session对象,如未初始化则按配置信息创建""" if self._session is None: self._create_session() return self._session @property def _session_url(self): - """返回 session 保存的url""" return self._response.url if self._response else None @property def timeout(self): - """返回通用timeout设置""" return self._timeout if self._mode == 's' else self.timeouts.base def get(self, url, show_errmsg=False, retry=None, interval=None, timeout=None, **kwargs): - """跳转到一个url - :param url: 目标url - :param show_errmsg: 是否显示和抛出异常 - :param retry: 重试次数,为None时使用页面对象retry_times属性值 - :param interval: 重试间隔(秒),为None时使用页面对象retry_interval属性值 - :param timeout: 连接超时时间(秒),为None时使用页面对象timeouts.page_load属性值 - :param kwargs: 连接参数,s模式专用 - :return: url是否可用,d模式返回None时表示不确定 - """ if self._mode == 'd': return super(SessionPage, self).get(url, show_errmsg, retry, interval, timeout) elif self._mode == 's': @@ -167,14 +137,6 @@ class MixPage(SessionPage, ChromiumPage, BasePage): return super().get(url, show_errmsg, retry, interval, timeout, **kwargs) def post(self, url, show_errmsg=False, retry=None, interval=None, **kwargs): - """用post方式跳转到url,会切换到s模式 - :param url: 目标url - :param show_errmsg: 是否显示和抛出异常 - :param retry: 重试次数,为None时使用页面对象retry_times属性值 - :param interval: 重试间隔(秒),为None时使用页面对象retry_interval属性值 - :param kwargs: 连接参数 - :return: s模式时返回url是否可用,d模式时返回获取到的Response对象 - """ if self.mode == 'd': self.cookies_to_session() super().post(url, show_errmsg, retry, interval, **kwargs) @@ -182,58 +144,30 @@ class MixPage(SessionPage, ChromiumPage, BasePage): return super().post(url, show_errmsg, retry, interval, **kwargs) def ele(self, locator, index=1, timeout=None): - """返回第一个符合条件的元素、属性或节点文本 - :param locator: 元素的定位信息,可以是元素对象,loc元组,或查询字符串 - :param index: 获取第几个,从1开始,可传入负数获取倒数第几个 - :param timeout: 查找元素超时时间(秒),默认与页面等待时间一致 - :return: 元素对象或属性、文本节点文本 - """ if self._mode == 's': return super().ele(locator, index=index) elif self._mode == 'd': return super(SessionPage, self).ele(locator, index=index, timeout=timeout) def eles(self, locator, timeout=None): - """返回页面中所有符合条件的元素、属性或节点文本 - :param locator: 元素的定位信息,可以是loc元组,或查询字符串 - :param timeout: 查找元素超时时间(秒),默认与页面等待时间一致 - :return: 元素对象或属性、文本组成的列表 - """ if self._mode == 's': return super().eles(locator) elif self._mode == 'd': return super(SessionPage, self).eles(locator, timeout=timeout) def s_ele(self, locator=None, index=1): - """查找第一个符合条件的元素以SessionElement形式返回,d模式处理复杂页面时效率很高 - :param locator: 元素的定位信息,可以是loc元组,或查询字符串 - :param index: 获取第几个,从1开始,可传入负数获取倒数第几个 - :return: SessionElement对象或属性、文本 - """ if self._mode == 's': return super().s_ele(locator, index=index) elif self._mode == 'd': return super(SessionPage, self).s_ele(locator, index=index) def s_eles(self, locator): - """查找所有符合条件的元素以SessionElement形式返回,d模式处理复杂页面时效率很高 - :param locator: 元素的定位信息,可以是loc元组,或查询字符串 - :return: SessionElement对象或属性、文本组成的列表 - """ if self._mode == 's': return super().s_eles(locator) elif self._mode == 'd': return super(SessionPage, self).s_eles(locator) def change_mode(self, mode=None, go=True, copy_cookies=True): - """切换模式,接收's'或'd',除此以外的字符串会切换为 d 模式 - 如copy_cookies为True,切换时会把当前模式的cookies复制到目标模式 - 切换后,如果go是True,调用相应的get函数使访问的页面同步 - :param mode: 模式字符串 - :param go: 是否跳转到原模式的url - :param copy_cookies: 是否复制cookies到目标模式 - :return: None - """ if mode is not None and mode.lower() == self._mode: return @@ -267,10 +201,6 @@ class MixPage(SessionPage, ChromiumPage, BasePage): raise ConnectionError('s模式访问失败,请设置go=False,自行构造连接参数进行访问。') def cookies_to_session(self, copy_user_agent=True): - """把driver对象的cookies复制到session对象 - :param copy_user_agent: 是否复制ua信息 - :return: None - """ if not self._has_session: return @@ -281,56 +211,27 @@ class MixPage(SessionPage, ChromiumPage, BasePage): set_session_cookies(self.session, super(SessionPage, self).cookies()) def cookies_to_browser(self): - """把session对象的cookies复制到浏览器""" if not self._has_driver: return set_tab_cookies(self, super().cookies()) def cookies(self, all_domains=False, all_info=False): - """返回cookies - :param all_domains: 是否返回所有域的cookies - :param all_info: 是否返回所有信息,False则只返回name、value、domain - :return: cookies信息 - """ if self._mode == 's': return super().cookies(all_domains, all_info) elif self._mode == 'd': return super(SessionPage, self).cookies(all_domains, all_info) def get_tab(self, id_or_num=None, title=None, url=None, tab_type='page', as_id=False): - """获取一个标签页对象,id_or_num不为None时,后面几个参数无效 - :param id_or_num: 要获取的标签页id或序号,序号从1开始,可传入负数获取倒数第几个,不是视觉排列顺序,而是激活顺序 - :param title: 要匹配title的文本,模糊匹配,为None则匹配所有 - :param url: 要匹配url的文本,模糊匹配,为None则匹配所有 - :param tab_type: tab类型,可用列表输入多个,如 'page', 'iframe' 等,为None则匹配所有 - :param as_id: 是否返回标签页id而不是标签页对象 - :return: MixTab对象 - """ return self.browser._get_tab(id_or_num=id_or_num, title=title, url=url, tab_type=tab_type, mix=True, as_id=as_id) def get_tabs(self, title=None, url=None, tab_type='page', as_id=False): - """查找符合条件的tab,返回它们组成的列表 - :param title: 要匹配title的文本,模糊匹配,为None则匹配所有 - :param url: 要匹配url的文本,模糊匹配,为None则匹配所有 - :param tab_type: tab类型,可用列表输入多个,如 'page', 'iframe' 等,为None则匹配所有 - :param as_id: 是否返回标签页id而不是标签页对象 - :return: ChromiumTab对象组成的列表 - """ return self.browser._get_tabs(title=title, url=url, tab_type=tab_type, mix=True, as_id=as_id) def new_tab(self, url=None, new_window=False, background=False, new_context=False): - """新建一个标签页 - :param url: 新标签页跳转到的网址 - :param new_window: 是否在新窗口打开标签页 - :param background: 是否不激活新标签页,如new_window为True则无效 - :param new_context: 是否创建新的上下文 - :return: 新标签页对象 - """ return self.browser.new_mix_tab(url=url, new_window=new_window, background=background, new_context=new_context) def close_driver(self): - """关闭driver及浏览器""" if self._has_driver: self.change_mode('s') try: @@ -342,7 +243,6 @@ class MixPage(SessionPage, ChromiumPage, BasePage): self._has_driver = None def close_session(self): - """关闭session""" if self._has_session: self.change_mode('d') self._session.close() @@ -353,7 +253,6 @@ class MixPage(SessionPage, ChromiumPage, BasePage): self._has_session = None def close(self): - """关闭标签页和Session""" if self._has_driver: self.close_tabs(self.tab_id) if self._session: @@ -362,26 +261,12 @@ class MixPage(SessionPage, ChromiumPage, BasePage): self._response.close() def _find_elements(self, locator, timeout=None, index=1, relative=False, raise_err=None): - """返回页面中符合条件的元素、属性或节点文本,默认返回第一个 - :param locator: 元素的定位信息,可以是元素对象,loc元组,或查询字符串 - :param timeout: 查找元素超时时间(秒),d模式专用 - :param index: 第几个结果,从1开始,可传入负数获取倒数第几个,为None返回所有 - :param relative: MixTab用的表示是否相对定位的参数 - :param raise_err: 找不到元素是是否抛出异常,为None时根据全局设置 - :return: 元素对象或属性、文本节点文本 - """ if self._mode == 's': return super()._find_elements(locator, index=index) elif self._mode == 'd': return super(SessionPage, self)._find_elements(locator, timeout=timeout, index=index, relative=relative) def quit(self, timeout=5, force=True, del_data=False): - """关闭浏览器和Session - :param timeout: 等待浏览器关闭超时时间(秒) - :param force: 关闭超时是否强制终止进程 - :param del_data: 是否删除用户文件夹 - :return: None - """ if self._has_session: self._session.close() self._session = None diff --git a/DrissionPage/_pages/mix_page.pyi b/DrissionPage/_pages/mix_page.pyi index 9979141..4dedd36 100644 --- a/DrissionPage/_pages/mix_page.pyi +++ b/DrissionPage/_pages/mix_page.pyi @@ -5,22 +5,22 @@ @Copyright: (c) 2024 by g1879, Inc. All Rights Reserved. @License : BSD 3-Clause. """ -from typing import Union, Tuple, List, Any, Optional +from typing import Union, Tuple, List, Any, Optional, Literal from requests import Session, Response from .chromium_frame import ChromiumFrame from .chromium_page import ChromiumPage -from .tabs import MixTab from .session_page import SessionPage +from .tabs import MixTab from .._base.base import BasePage -from .._base.driver import Driver from .._configs.chromium_options import ChromiumOptions from .._configs.session_options import SessionOptions from .._elements.chromium_element import ChromiumElement from .._elements.session_element import SessionElement from .._functions.elements import SessionElementsList, ChromiumElementsList from .._units.setter import MixPageSetter +from .._units.waiter import MixPageWaiter class MixPage(SessionPage, ChromiumPage, BasePage): @@ -36,49 +36,101 @@ class MixPage(SessionPage, ChromiumPage, BasePage): timeout: float = None, chromium_options: Union[ChromiumOptions, bool] = None, session_or_options: Union[Session, SessionOptions, bool] = None) -> None: + """初始化函数 + :param mode: 'd' 或 's',即driver模式和session模式 + :param timeout: 超时时间(秒),d模式时为寻找元素时间,s模式时为连接时间,默认10秒 + :param chromium_options: ChromiumOptions对象,只使用s模式时应传入False + :param session_or_options: Session对象或SessionOptions对象,只使用d模式时应传入False + """ ... def __call__(self, locator: Union[Tuple[str, str], str, ChromiumElement, SessionElement], index: int = 1, - timeout: float = None) -> Union[ChromiumElement, SessionElement]: ... - - # -----------------共有属性和方法------------------- - @property - def url(self) -> Union[str, None]: ... + timeout: float = None) -> Union[ChromiumElement, SessionElement]: + """在内部查找元素 + :param locator: 元素的定位信息,可以是loc元组,或查询字符串 + :param index: 获取第几个,从1开始,可传入负数获取倒数第几个 + :param timeout: 超时时间(秒) + :return: 子元素对象 + """ + ... @property - def _browser_url(self) -> Union[str, None]: ... + def latest_tab(self) -> Union[MixTab, MixPage, str]: + """返回最新的标签页,最新标签页指最后创建或最后被激活的 + 当Settings.singleton_tab_obj==True时返回Tab对象,否则返回tab id""" + ... @property - def title(self) -> str: ... + def set(self) -> MixPageSetter: + """返回用于设置的对象""" + ... @property - def raw_data(self) -> Union[str, bytes]: ... + def wait(self) -> MixPageWaiter: + """返回用于等待的对象""" + ... @property - def html(self) -> str: ... + def url(self) -> Union[str, None]: + """返回浏览器当前url""" + ... @property - def json(self) -> dict: ... + def _browser_url(self) -> Union[str, None]: + """返回浏览器当前url""" + ... @property - def response(self) -> Response: ... + def title(self) -> str: + """返回当前页面title""" + ... @property - def mode(self) -> str: ... + def raw_data(self) -> Union[str, bytes]: + """返回页码原始数据数据""" + ... @property - def user_agent(self) -> str: ... + def html(self) -> str: + """返回页面html文本""" + ... @property - def session(self) -> Session: ... + def json(self) -> dict: + """当返回内容是json格式时,返回对应的字典""" + ... @property - def _session_url(self) -> str: ... + def response(self) -> Response: + """返回 s 模式获取到的 Response 对象,切换到 s 模式""" + ... @property - def timeout(self) -> float: ... + def mode(self) -> Literal['s', 'd']: + """返回当前模式,'s'或'd' """ + ... + + @property + def user_agent(self) -> str: + """返回user agent""" + ... + + @property + def session(self) -> Session: + """返回Session对象,如未初始化则按配置信息创建""" + ... + + @property + def _session_url(self) -> str: + """返回 session 保存的url""" + ... + + @property + def timeout(self) -> float: + """返回通用timeout设置""" + ... def get(self, url: str, @@ -98,59 +150,30 @@ class MixPage(SessionPage, ChromiumPage, BasePage): hooks: Any | None = ..., stream: Any | None = ..., verify: Any | None = ..., - cert: Any | None = ...) -> Union[bool, None]: ... + cert: Any | None = ...) -> Union[bool, None]: + """跳转到一个url + :param url: 目标url + :param show_errmsg: 是否显示和抛出异常 + :param retry: 重试次数,为None时使用页面对象retry_times属性值 + :param interval: 重试间隔(秒),为None时使用页面对象retry_interval属性值 + :param timeout: 连接超时时间 + :param params: url中的参数 + :param data: 携带的数据 + :param json: 要发送的 JSON 数据,会自动设置 Content-Type 为 application/json + :param headers: 请求头 + :param cookies: cookies信息 + :param files: 要上传的文件,可以是一个字典,其中键是文件名,值是文件对象或文件路径 + :param auth: 身份认证信息 + :param allow_redirects: 是否允许重定向 + :param proxies: 代理信息 + :param hooks: 回调方法 + :param stream: 是否使用流式传输 + :param verify: 是否验证 SSL 证书 + :param cert: SSL客户端证书文件的路径(.pem格式),或(‘cert’, ‘key’)元组 + :return: s模式时返回url是否可用,d模式时返回获取到的Response对象 + """ + ... - def ele(self, - locator: Union[Tuple[str, str], str, ChromiumElement, SessionElement], - index: int = 1, - timeout: float = None) -> Union[ChromiumElement, SessionElement]: ... - - def eles(self, - locator: Union[Tuple[str, str], str], - timeout: float = None) -> Union[SessionElementsList, ChromiumElementsList]: ... - - def s_ele(self, - locator: Union[Tuple[str, str], str] = None, - index: int = 1) -> SessionElement: ... - - def s_eles(self, locator: Union[Tuple[str, str], str]) -> SessionElementsList: ... - - def change_mode(self, mode: str = None, go: bool = True, copy_cookies: bool = True) -> None: ... - - def cookies_to_session(self, copy_user_agent: bool = True) -> None: ... - - def cookies_to_browser(self) -> None: ... - - def cookies(self, - all_domains: bool = False, - all_info: bool = False) -> Union[dict, list]: ... - - def get_tab(self, - id_or_num: Union[str, MixTab, int] = None, - title: str = None, - url: str = None, - tab_type: Union[str, list, tuple] = 'page', - as_id: bool = False) -> Union[MixTab, str, None]: ... - - def get_tabs(self, - title: str = None, - url: str = None, - tab_type: Union[str, list, tuple] = 'page', - as_id: bool = False) -> Union[List[MixTab], List[str]]: ... - - def new_tab(self, - url: str = None, - new_window: bool = False, - background: bool = False, - new_context: bool = False) -> MixTab: ... - - def close_driver(self) -> None: ... - - def close_session(self) -> None: ... - - def close(self) -> None: ... - - # ----------------重写SessionPage的函数----------------------- def post(self, url: str, data: Union[dict, str, None] = None, @@ -169,24 +192,184 @@ class MixPage(SessionPage, ChromiumPage, BasePage): hooks: Any | None = ..., stream: Any | None = ..., verify: Any | None = ..., - cert: Any | None = ...) -> Union[bool, Response]: ... + cert: Any | None = ...) -> Union[bool, Response]: + """用post方式跳转到url + :param url: 目标url + :param show_errmsg: 是否显示和抛出异常 + :param retry: 重试次数,为None时使用页面对象retry_times属性值 + :param interval: 重试间隔(秒),为None时使用页面对象retry_interval属性值 + :param timeout: 连接超时时间 + :param params: url中的参数 + :param data: 携带的数据 + :param json: 要发送的 JSON 数据,会自动设置 Content-Type 为 application/json + :param headers: 请求头 + :param cookies: cookies信息 + :param files: 要上传的文件,可以是一个字典,其中键是文件名,值是文件对象或文件路径 + :param auth: 身份认证信息 + :param allow_redirects: 是否允许重定向 + :param proxies: 代理信息 + :param hooks: 回调方法 + :param stream: 是否使用流式传输 + :param verify: 是否验证 SSL 证书 + :param cert: SSL客户端证书文件的路径(.pem格式),或(‘cert’, ‘key’)元组 + :return: s模式时返回url是否可用,d模式时返回获取到的Response对象 + """ + ... - @property - def latest_tab(self) -> Union[MixTab, MixPage]: ... + def ele(self, + locator: Union[Tuple[str, str], str, ChromiumElement, SessionElement], + index: int = 1, + timeout: float = None) -> Union[ChromiumElement, SessionElement]: + """返回第一个符合条件的元素、属性或节点文本 + :param locator: 元素的定位信息,可以是元素对象,loc元组,或查询字符串 + :param index: 获取第几个,从1开始,可传入负数获取倒数第几个 + :param timeout: 查找元素超时时间(秒),默认与页面等待时间一致 + :return: 元素对象或属性、文本节点文本 + """ + ... - @property - def set(self) -> MixPageSetter: ... + def eles(self, + locator: Union[Tuple[str, str], str], + timeout: float = None) -> Union[SessionElementsList, ChromiumElementsList]: + """返回页面中所有符合条件的元素、属性或节点文本 + :param locator: 元素的定位信息,可以是loc元组,或查询字符串 + :param timeout: 查找元素超时时间(秒),默认与页面等待时间一致 + :return: 元素对象或属性、文本组成的列表 + """ + ... + + def s_ele(self, + locator: Union[Tuple[str, str], str] = None, + index: int = 1) -> SessionElement: + """查找第一个符合条件的元素以SessionElement形式返回,d模式处理复杂页面时效率很高 + :param locator: 元素的定位信息,可以是loc元组,或查询字符串 + :param index: 获取第几个,从1开始,可传入负数获取倒数第几个 + :return: SessionElement对象或属性、文本 + """ + ... + + def s_eles(self, locator: Union[Tuple[str, str], str]) -> SessionElementsList: + """查找所有符合条件的元素以SessionElement形式返回,d模式处理复杂页面时效率很高 + :param locator: 元素的定位信息,可以是loc元组,或查询字符串 + :return: SessionElement对象或属性、文本组成的列表 + """ + ... + + def change_mode(self, + mode: str = None, + go: bool = True, + copy_cookies: bool = True) -> None: + """切换模式,接收's'或'd',除此以外的字符串会切换为 d 模式 + 如copy_cookies为True,切换时会把当前模式的cookies复制到目标模式 + 切换后,如果go是True,调用相应的get函数使访问的页面同步 + :param mode: 模式字符串 + :param go: 是否跳转到原模式的url + :param copy_cookies: 是否复制cookies到目标模式 + :return: None + """ + ... + + def cookies_to_session(self, copy_user_agent: bool = True) -> None: + """把driver对象的cookies复制到session对象 + :param copy_user_agent: 是否复制ua信息 + :return: None + """ + ... + + def cookies_to_browser(self) -> None: + """把session对象的cookies复制到浏览器""" + ... + + def cookies(self, + all_domains: bool = False, + all_info: bool = False) -> Union[dict, list]: + """返回cookies + :param all_domains: 是否返回所有域的cookies + :param all_info: 是否返回所有信息,False则只返回name、value、domain + :return: cookies信息 + """ + ... + + def get_tab(self, + id_or_num: Union[str, MixTab, int] = None, + title: str = None, + url: str = None, + tab_type: Union[str, list, tuple] = 'page', + as_id: bool = False) -> Union[MixTab, str, None]: + """获取一个标签页对象,id_or_num不为None时,后面几个参数无效 + :param id_or_num: 要获取的标签页id或序号,序号从1开始,可传入负数获取倒数第几个,不是视觉排列顺序,而是激活顺序 + :param title: 要匹配title的文本,模糊匹配,为None则匹配所有 + :param url: 要匹配url的文本,模糊匹配,为None则匹配所有 + :param tab_type: tab类型,可用列表输入多个,如 'page', 'iframe' 等,为None则匹配所有 + :param as_id: 是否返回标签页id而不是标签页对象 + :return: MixTab对象 + """ + ... + + def get_tabs(self, + title: str = None, + url: str = None, + tab_type: Union[str, list, tuple] = 'page', + as_id: bool = False) -> Union[List[MixTab], List[str]]: + """查找符合条件的tab,返回它们组成的列表 + :param title: 要匹配title的文本,模糊匹配,为None则匹配所有 + :param url: 要匹配url的文本,模糊匹配,为None则匹配所有 + :param tab_type: tab类型,可用列表输入多个,如 'page', 'iframe' 等,为None则匹配所有 + :param as_id: 是否返回标签页id而不是标签页对象 + :return: ChromiumTab对象组成的列表 + """ + ... + + def new_tab(self, + url: str = None, + new_window: bool = False, + background: bool = False, + new_context: bool = False) -> MixTab: + """新建一个标签页 + :param url: 新标签页跳转到的网址 + :param new_window: 是否在新窗口打开标签页 + :param background: 是否不激活新标签页,如new_window为True则无效 + :param new_context: 是否创建新的上下文 + :return: 新标签页对象 + """ + ... + + def close_driver(self) -> None: + """关闭driver及浏览器""" + ... + + def close_session(self) -> None: + """关闭session""" + ... + + def close(self) -> None: + """关闭标签页和Session""" + ... def _find_elements(self, locator: Union[Tuple[str, str], str, ChromiumElement, SessionElement, ChromiumFrame], timeout: float = None, index: Optional[int] = 1, relative: bool = False, - raise_err: bool = None) \ - -> Union[ChromiumElement, SessionElement, ChromiumFrame, SessionElementsList, ChromiumElementsList]: ... + raise_err: bool = None) -> Union[ChromiumElement, SessionElement, ChromiumFrame, SessionElementsList, ChromiumElementsList]: + """返回页面中符合条件的元素、属性或节点文本,默认返回第一个 + :param locator: 元素的定位信息,可以是元素对象,loc元组,或查询字符串 + :param timeout: 查找元素超时时间(秒),d模式专用 + :param index: 第几个结果,从1开始,可传入负数获取倒数第几个,为None返回所有 + :param relative: MixTab用的表示是否相对定位的参数 + :param raise_err: 找不到元素是是否抛出异常,为None时根据全局设置 + :return: 元素对象或属性、文本节点文本 + """ + ... - def _set_start_options(self, - dr_opt: Union[Driver, bool, None], - se_opt: Union[Session, SessionOptions, bool, None]) -> None: ... - - def quit(self, timeout: float = 5, force: bool = True, del_data: bool = False) -> None: ... + def quit(self, + timeout: float = 5, + force: bool = True, + del_data: bool = False) -> None: + """关闭浏览器和Session + :param timeout: 等待浏览器关闭超时时间(秒) + :param force: 关闭超时是否强制终止进程 + :param del_data: 是否删除用户文件夹 + :return: None + """ + ... diff --git a/DrissionPage/_pages/tabs.pyi b/DrissionPage/_pages/tabs.pyi index 886a14c..17934c6 100644 --- a/DrissionPage/_pages/tabs.pyi +++ b/DrissionPage/_pages/tabs.pyi @@ -20,7 +20,7 @@ from .._functions.cookies import CookiesList from .._functions.elements import SessionElementsList, ChromiumElementsList from .._units.rect import TabRect from .._units.setter import TabSetter, MixTabSetter -from .._units.waiter import TabWaiter +from .._units.waiter import TabWaiter, MixTabWaiter class ChromiumTab(ChromiumBase): @@ -120,6 +120,7 @@ class MixTab(SessionPage, ChromiumTab): _mode: str = ... _has_driver: bool = ... _has_session: bool = ... + _set: MixTabSetter = ... def __init__(self, browser: Chromium, tab_id: str): """ @@ -146,6 +147,11 @@ class MixTab(SessionPage, ChromiumTab): """返回用于设置的对象""" ... + @property + def wait(self) -> MixTabWaiter: + """返回用于等待的对象""" + ... + @property def url(self) -> Union[str, None]: """返回浏览器当前url""" diff --git a/DrissionPage/_units/waiter.py b/DrissionPage/_units/waiter.py index f204b1e..74aeee6 100644 --- a/DrissionPage/_units/waiter.py +++ b/DrissionPage/_units/waiter.py @@ -26,7 +26,6 @@ class OriginWaiter(object): class BrowserWaiter(OriginWaiter): - def new_tab(self, timeout=None, curr_tab=None, raise_err=None): if not curr_tab: curr_tab = self._owner.tab_ids[0] @@ -89,7 +88,6 @@ class BrowserWaiter(OriginWaiter): class BaseWaiter(OriginWaiter): - def ele_deleted(self, loc_or_ele, timeout=None, raise_err=None): 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 @@ -249,21 +247,19 @@ class BaseWaiter(OriginWaiter): class TabWaiter(BaseWaiter): - """标签页对象等待对象""" - def downloads_done(self, timeout=None, cancel_if_timeout=True): if not self._owner.browser._dl_mgr._running: raise RuntimeError('此功能需显式设置下载路径(使用set.download_path()方法、配置对象或ini文件均可)。') if not timeout: while self._owner.browser._dl_mgr.get_tab_missions(self._owner.tab_id): sleep(.5) - return True + return self._owner else: end_time = perf_counter() + timeout while perf_counter() < end_time: if not self._owner.browser._dl_mgr.get_tab_missions(self._owner.tab_id): - return True + return self._owner sleep(.5) if self._owner.browser._dl_mgr.get_tab_missions(self._owner.tab_id): @@ -272,18 +268,17 @@ class TabWaiter(BaseWaiter): m.cancel() return False else: - return True + return self._owner def alert_closed(self): while not self._owner.states.has_alert: sleep(.2) while self._owner.states.has_alert: sleep(.2) + return self._owner -class PageWaiter(TabWaiter): - """ChromiumPage和MixPage的等待对象""" - +class ChromiumPageWaiter(TabWaiter): def new_tab(self, timeout=None, raise_err=None): return self._owner.browser.wait.new_tab(timeout=timeout, raise_err=raise_err) @@ -292,8 +287,6 @@ class PageWaiter(TabWaiter): class ElementWaiter(OriginWaiter): - """等待元素在dom中某种状态,如删除、显示、隐藏""" - def __init__(self, owner): super().__init__(owner) self._ele = owner diff --git a/DrissionPage/_units/waiter.pyi b/DrissionPage/_units/waiter.pyi index 75475e7..46a5b62 100644 --- a/DrissionPage/_units/waiter.pyi +++ b/DrissionPage/_units/waiter.pyi @@ -104,7 +104,9 @@ class BaseWaiter(OriginWaiter): """ ... - def ele_hidden(self, loc_or_ele: Union[str, tuple, ChromiumElement], timeout: float = None, + def ele_hidden(self, + loc_or_ele: Union[str, tuple, ChromiumElement], + timeout: float = None, raise_err: bool = None) -> bool: """等待元素变成隐藏状态 :param loc_or_ele: 要等待的元素,可以是已有元素、定位符 @@ -184,7 +186,11 @@ class BaseWaiter(OriginWaiter): """ ... - def _change(self, arg: str, text: str, exclude: bool = False, timeout: float = None, + def _change(self, + arg: str, + text: str, + exclude: bool = False, + timeout: float = None, raise_err: bool = None) -> bool: """等待指定属性变成包含或不包含指定文本 :param arg: 要被匹配的属性 @@ -196,7 +202,11 @@ class BaseWaiter(OriginWaiter): """ ... - def _loading(self, timeout: float = None, start: bool = True, gap: float = .01, raise_err: bool = None) -> bool: + def _loading(self, + timeout: float = None, + start: bool = True, + gap: float = .01, + raise_err: bool = None) -> bool: """等待页面开始加载或加载完成 :param timeout: 超时时间(秒),为None时使用页面timeout属性 :param start: 等待开始还是结束 @@ -210,13 +220,15 @@ class BaseWaiter(OriginWaiter): class TabWaiter(BaseWaiter): _owner: Union[ChromiumTab, MixTab] = ... - def __init__(self, owner: Union[ChromiumTab, MixTab]): + def __init__(self, owner: ChromiumTab): """ :param owner: Tab对象 """ ... - def __call__(self, second: float, scope: float = None) -> Union[ChromiumTab, MixTab]: + def __call__(self, + second: float, + scope: float = None) -> ChromiumTab: """等待若干秒,如传入两个参数,等待时间为这两个数间的一个随机数 :param second: 秒数 :param scope: 随机数范围 @@ -224,7 +236,9 @@ class TabWaiter(BaseWaiter): """ ... - 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) -> Union[False, ChromiumTab]: """等待所有浏览器下载任务结束 :param timeout: 超时时间(秒),为None时无限等待 :param cancel_if_timeout: 超时时是否取消剩余任务 @@ -232,12 +246,15 @@ class TabWaiter(BaseWaiter): """ ... - def alert_closed(self) -> None: + def alert_closed(self) -> ChromiumTab: """等待弹出框关闭""" ... - def url_change(self, text: str, exclude: bool = False, - timeout: float = None, raise_err: bool = None) -> Union[False, ChromiumTab, MixTab]: + def url_change(self, + text: str, + exclude: bool = False, + timeout: float = None, + raise_err: bool = None) -> Union[False, ChromiumTab]: """等待url变成包含或不包含指定文本 :param text: 用于识别的文本 :param exclude: 是否排除,为True时当url不包含text指定文本时返回True @@ -247,8 +264,11 @@ class TabWaiter(BaseWaiter): """ ... - def title_change(self, text: str, exclude: bool = False, - timeout: float = None, raise_err: bool = None) -> Union[False, ChromiumTab, MixTab]: + def title_change(self, + text: str, + exclude: bool = False, + timeout: float = None, + raise_err: bool = None) -> Union[False, ChromiumTab]: """等待title变成包含或不包含指定文本 :param text: 用于识别的文本 :param exclude: 是否排除,为True时当title不包含text指定文本时返回True @@ -259,16 +279,18 @@ class TabWaiter(BaseWaiter): ... -class PageWaiter(TabWaiter): - _owner: Union[ChromiumPage, MixPage] = ... +class MixTabWaiter(BaseWaiter): + _owner: Union[ChromiumTab, MixTab] = ... - def __init__(self, owner: Union[ChromiumPage, MixPage]): + def __init__(self, owner: MixTab): """ - :param owner: Page对象 + :param owner: Tab对象 """ ... - def __call__(self, second: float, scope: float = None) -> Union[ChromiumPage, MixPage]: + def __call__(self, + second: float, + scope: float = None) -> MixTab: """等待若干秒,如传入两个参数,等待时间为这两个数间的一个随机数 :param second: 秒数 :param scope: 随机数范围 @@ -276,15 +298,9 @@ class PageWaiter(TabWaiter): """ ... - 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 downloads_done(self, + timeout: float = None, + cancel_if_timeout: bool = True) -> Union[False, MixTab]: """等待所有浏览器下载任务结束 :param timeout: 超时时间(秒),为None时无限等待 :param cancel_if_timeout: 超时时是否取消剩余任务 @@ -292,8 +308,15 @@ class PageWaiter(TabWaiter): """ ... - def url_change(self, text: str, exclude: bool = False, - timeout: float = None, raise_err: bool = None) -> Union[False, ChromiumPage, MixPage]: + def alert_closed(self) -> MixTab: + """等待弹出框关闭""" + ... + + def url_change(self, + text: str, + exclude: bool = False, + timeout: float = None, + raise_err: bool = None) -> Union[False, MixTab]: """等待url变成包含或不包含指定文本 :param text: 用于识别的文本 :param exclude: 是否排除,为True时当url不包含text指定文本时返回True @@ -303,8 +326,147 @@ class PageWaiter(TabWaiter): """ ... - def title_change(self, text: str, exclude: bool = False, - timeout: float = None, raise_err: bool = None) -> Union[False, ChromiumPage, MixPage]: + def title_change(self, + text: str, + exclude: bool = False, + timeout: float = None, + raise_err: bool = None) -> Union[False, MixTab]: + """等待title变成包含或不包含指定文本 + :param text: 用于识别的文本 + :param exclude: 是否排除,为True时当title不包含text指定文本时返回True + :param timeout: 超时时间(秒),为None使用页面设置 + :param raise_err: 等待失败时是否报错,为None时根据Settings设置 + :return: 等待成功返回页面对象,否则返回False + """ + ... + + +class ChromiumPageWaiter(TabWaiter): + _owner: Union[ChromiumPage, MixPage] = ... + + def __init__(self, owner: ChromiumPage): + """ + :param owner: Page对象 + """ + ... + + def __call__(self, + second: float, + scope: float = None) -> ChromiumPage: + """等待若干秒,如传入两个参数,等待时间为这两个数间的一个随机数 + :param second: 秒数 + :param scope: 随机数范围 + :return: None + """ + ... + + 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: + """等待所有浏览器下载任务结束 + :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]: + """等待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]: + """等待title变成包含或不包含指定文本 + :param text: 用于识别的文本 + :param exclude: 是否排除,为True时当title不包含text指定文本时返回True + :param timeout: 超时时间(秒),为None使用页面设置 + :param raise_err: 等待失败时是否报错,为None时根据Settings设置 + :return: 等待成功返回页面对象,否则返回False + """ + ... + + +class MixPageWaiter(TabWaiter): + _owner: Union[ChromiumPage, MixPage] = ... + + def __init__(self, owner: MixPage): + """ + :param owner: Page对象 + """ + ... + + def __call__(self, + second: float, + scope: float = None) -> MixPage: + """等待若干秒,如传入两个参数,等待时间为这两个数间的一个随机数 + :param second: 秒数 + :param scope: 随机数范围 + :return: None + """ + ... + + 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: + """等待所有浏览器下载任务结束 + :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, 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, MixPage]: """等待title变成包含或不包含指定文本 :param text: 用于识别的文本 :param exclude: 是否排除,为True时当title不包含text指定文本时返回True @@ -404,8 +566,10 @@ class ElementWaiter(OriginWaiter): """ ... - def clickable(self, wait_moved: bool = True, - timeout: float = None, raise_err: bool = None) -> Union[ChromiumElement, False]: + def clickable(self, + wait_moved: bool = True, + timeout: float = None, + raise_err: bool = None) -> Union[ChromiumElement, False]: """等待当前元素可被点击 :param wait_moved: 是否等待元素运动结束 :param timeout: 超时时间(秒),为None使用元素所在页面timeout属性 @@ -424,8 +588,10 @@ class ElementWaiter(OriginWaiter): """ ... - 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: 检测间隔时间 diff --git a/requirements.txt b/requirements.txt index 63f0080..0b26968 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,7 @@ requests lxml cssselect -DownloadKit>=2.0.0 +DownloadKit>=2.0.2 websocket-client click tldextract diff --git a/setup.py b/setup.py index 2ad5dcb..de23a28 100644 --- a/setup.py +++ b/setup.py @@ -23,7 +23,7 @@ setup( 'lxml', 'requests', 'cssselect', - 'DownloadKit>=2.0.0', + 'DownloadKit>=2.0.2', 'websocket-client', 'click', 'tldextract',