diff --git a/DrissionPage/__init__.py b/DrissionPage/__init__.py index 917271d..a254d7c 100644 --- a/DrissionPage/__init__.py +++ b/DrissionPage/__init__.py @@ -14,4 +14,4 @@ from ._configs.chromium_options import ChromiumOptions from ._configs.session_options import SessionOptions __all__ = ['ChromiumPage', 'ChromiumOptions', 'SessionOptions', 'SessionPage', 'WebPage', '__version__'] -__version__ = '4.0.4.8' +__version__ = '4.0.4.9' diff --git a/DrissionPage/_base/browser.py b/DrissionPage/_base/browser.py index 92b8b6b..caa04d2 100644 --- a/DrissionPage/_base/browser.py +++ b/DrissionPage/_base/browser.py @@ -129,7 +129,7 @@ class Browser(object): return len([i for i in j if i['type'] in ('page', 'webview') and not i['url'].startswith('devtools://')]) @property - def tabs(self): + def tab_ids(self): """返回所有标签页id组成的列表""" j = self._driver.get(f'http://{self.address}/json').json() # 不要改用cdp,因为顺序不对 return [i['id'] for i in j if i['type'] in ('page', 'webview') and not i['url'].startswith('devtools://')] @@ -139,13 +139,12 @@ class Browser(object): """返回浏览器进程id""" return self._process_id - def find_tabs(self, title=None, url=None, tab_type=None, single=True): - """查找符合条件的tab,返回它们的id组成的列表 + def find_tabs(self, title=None, url=None, tab_type=None): + """查找符合条件的tab,返回它们组成的列表 :param title: 要匹配title的文本 :param url: 要匹配url的文本 :param tab_type: tab类型,可用列表输入多个 - :param single: 是否返回首个结果的id,为False返回所有信息 - :return: tab id或tab列表 + :return: dict格式的tab信息列表列表 """ tabs = self._driver.get(f'http://{self.address}/json').json() # 不要改用cdp @@ -156,9 +155,8 @@ class Browser(object): elif tab_type is not None: raise TypeError('tab_type只能是set、list、tuple、str、None。') - r = [i for i in tabs if ((title is None or title in i['title']) and (url is None or url in i['url']) - and (tab_type is None or i['type'] in tab_type))] - return r[0]['id'] if r and single else r + return [i for i in tabs if ((title is None or title in i['title']) and (url is None or url in i['url']) + and (tab_type is None or i['type'] in tab_type))] def close_tab(self, tab_id): """关闭标签页 diff --git a/DrissionPage/_base/browser.pyi b/DrissionPage/_base/browser.pyi index 4f44b8c..7f80b57 100644 --- a/DrissionPage/_base/browser.pyi +++ b/DrissionPage/_base/browser.pyi @@ -40,13 +40,13 @@ class Browser(object): def tabs_count(self) -> int: ... @property - def tabs(self) -> List[str]: ... + def tab_ids(self) -> List[str]: ... @property def process_id(self) -> Optional[int]: ... def find_tabs(self, title: str = None, url: str = None, - tab_type: Union[str, list, tuple] = None, single: bool = True) -> Union[str, List[str]]: ... + tab_type: Union[str, list, tuple] = None) -> List[dict]: ... def close_tab(self, tab_id: str) -> None: ... diff --git a/DrissionPage/_base/driver.py b/DrissionPage/_base/driver.py index 293f3d0..7dba12e 100644 --- a/DrissionPage/_base/driver.py +++ b/DrissionPage/_base/driver.py @@ -30,7 +30,7 @@ class Driver(object): self.address = address self.type = tab_type self.owner = owner - self._debug = False + # self._debug = False self.alert_flag = False # 标记alert出现,跳过一条请求后复原 self._websocket_url = f'ws://{address}/devtools/{tab_type}/{tab_id}' @@ -180,7 +180,6 @@ class Driver(object): def run(self, _method, **kwargs): """执行cdp方法 :param _method: cdp方法名 - :param args: cdp参数 :param kwargs: cdp参数 :return: 执行结果 """ diff --git a/DrissionPage/_pages/chromium_page.py b/DrissionPage/_pages/chromium_page.py index c6b10fc..4cd45dd 100644 --- a/DrissionPage/_pages/chromium_page.py +++ b/DrissionPage/_pages/chromium_page.py @@ -124,14 +124,14 @@ class ChromiumPage(ChromiumBase): return self.browser.tabs_count @property - def tabs(self): + def tab_ids(self): """返回所有标签页id组成的列表""" - return self.browser.tabs + return self.browser.tab_ids @property def latest_tab(self): - """返回最新的标签页id,最新标签页指最后创建或最后被激活的""" - return self.tabs[0] + """返回最新的标签页对象,最新标签页指最后创建或最后被激活的""" + return self.get_tab(self.tab_ids[0]) @property def process_id(self): @@ -148,32 +148,51 @@ class ChromiumPage(ChromiumBase): """ return get_pdf(self, path, name, kwargs) if as_pdf else get_mhtml(self, path, name) - def get_tab(self, id_or_num=None): - """获取一个标签页对象 - :param id_or_num: 要获取的标签页id或序号,为None时获取当前tab,序号从1开始,可传入负数获取倒数第几个,不是视觉排列顺序,而是激活顺序 - :return: 标签页对象 + def get_tab(self, id_or_num=None, title=None, url=None, tab_type=None, 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对象 """ - with self._lock: + if id_or_num is not None: if isinstance(id_or_num, str): - return ChromiumTab(self, id_or_num) + id_or_num = id_or_num elif isinstance(id_or_num, int): - return ChromiumTab(self, self.tabs[id_or_num - 1 if id_or_num > 0 else id_or_num]) - elif id_or_num is None: - return ChromiumTab(self, self.tab_id) + id_or_num = self.tab_ids[id_or_num - 1 if id_or_num > 0 else id_or_num] elif isinstance(id_or_num, ChromiumTab): - return id_or_num - else: - raise TypeError(f'id_or_num需传入tab id或序号,非{id_or_num}。') + return id_or_num.tab_id if as_id else id_or_num - def find_tabs(self, title=None, url=None, tab_type=None, single=True): - """查找符合条件的tab,返回它们的id组成的列表 - :param title: 要匹配title的文本 - :param url: 要匹配url的文本 - :param tab_type: tab类型,可用列表输入多个 - :param single: 是否返回首个结果的id,为False返回所有信息 - :return: tab id或tab列表 + elif title == url == tab_type is None: + id_or_num = self.tab_id + + else: + id_or_num = self._browser.find_tabs(title, url, tab_type) + if id_or_num: + id_or_num = id_or_num[0] + else: + return None + + if as_id: + return id_or_num + + with self._lock: + return ChromiumTab(self, id_or_num) + + def get_tabs(self, title=None, url=None, tab_type=None, 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.find_tabs(title, url, tab_type, single) + if as_id: + return [tab['id'] for tab in self._browser.find_tabs(title, url, tab_type)] + with self._lock: + return [ChromiumTab(self, tab['id']) for tab in self._browser.find_tabs(title, url, tab_type)] def new_tab(self, url=None, new_window=False, background=False, new_context=False): """新建一个标签页 @@ -219,7 +238,7 @@ class ChromiumPage(ChromiumBase): :param others: 是否关闭指定标签页之外的 :return: None """ - all_tabs = set(self.tabs) + all_tabs = set(self.tab_ids) if isinstance(tabs_or_ids, str): tabs = {tabs_or_ids} elif isinstance(tabs_or_ids, ChromiumTab): @@ -269,6 +288,22 @@ class ChromiumPage(ChromiumBase): """ self.close_tabs(tabs_or_ids, True) + @property + def tabs(self): + """返回所有标签页id组成的列表""" + return self.browser.tab_ids + + def find_tabs(self, title=None, url=None, tab_type=None, single=True): + """查找符合条件的tab,返回它们组成的列表 + :param title: 要匹配title的文本 + :param url: 要匹配url的文本 + :param tab_type: tab类型,可用列表输入多个 + :param single: 是否返回首个结果的id,为False返回所有信息 + :return: tab id或tab列表 + """ + r = self._browser.find_tabs(title, url, tab_type) + return r[0]['id'] if r and single else r + def handle_options(addr_or_opts): """设置浏览器启动属性 diff --git a/DrissionPage/_pages/chromium_page.pyi b/DrissionPage/_pages/chromium_page.pyi index 4a031ac..ad5cda9 100644 --- a/DrissionPage/_pages/chromium_page.pyi +++ b/DrissionPage/_pages/chromium_page.pyi @@ -51,13 +51,13 @@ class ChromiumPage(ChromiumBase): def tabs_count(self) -> int: ... @property - def tabs(self) -> List[str]: ... + def tab_ids(self) -> List[str]: ... @property def wait(self) -> PageWaiter: ... @property - def latest_tab(self) -> str: ... + def latest_tab(self) -> Union[ChromiumTab, ChromiumPage]: ... @property def process_id(self) -> Optional[int]: ... @@ -86,10 +86,18 @@ class ChromiumPage(ChromiumBase): generateTaggedPDF: bool = ..., generateDocumentOutline: bool = ...) -> Union[bytes, str]: ... - def get_tab(self, tab_id: Union[str, ChromiumTab, int] = None) -> ChromiumTab: ... + def get_tab(self, + id_or_num: Union[str, ChromiumTab, int] = None, + title: str = None, + url: str = None, + tab_type: Union[str, list, tuple] = None, + as_id: bool = False) -> Union[ChromiumTab, str, None]: ... - def find_tabs(self, title: str = None, url: str = None, - tab_type: Union[str, list, tuple] = None, single: bool = True) -> Union[str, List[str]]: ... + def get_tabs(self, + title: str = None, + url: str = None, + tab_type: Union[str, list, tuple] = None, + as_id: bool = False) -> Union[List[ChromiumTab], List[str]]: ... def new_tab(self, url: str = None, new_window: bool = False, background: bool = False, new_context: bool = False) -> ChromiumTab: ... diff --git a/DrissionPage/_pages/web_page.py b/DrissionPage/_pages/web_page.py index 1e9cb6c..8253e40 100644 --- a/DrissionPage/_pages/web_page.py +++ b/DrissionPage/_pages/web_page.py @@ -308,21 +308,51 @@ class WebPage(SessionPage, ChromiumPage, BasePage): elif self._mode == 'd': return super(SessionPage, self).cookies(as_dict, all_domains, all_info) - def get_tab(self, id_or_num=None): - """获取一个标签页对象 - :param id_or_num: 要获取的标签页id或序号,为None时获取当前tab,序号不是视觉排列顺序,而是激活顺序 - :return: 标签页对象 + def get_tab(self, id_or_num=None, title=None, url=None, tab_type=None, 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: WebPageTab对象 """ - if isinstance(id_or_num, str): - return WebPageTab(self, id_or_num) - elif isinstance(id_or_num, int): - return WebPageTab(self, self.tabs[id_or_num]) - elif id_or_num is None: - return WebPageTab(self, self.tab_id) - elif isinstance(id_or_num, WebPageTab): - return id_or_num + if id_or_num is not None: + if isinstance(id_or_num, str): + id_or_num = id_or_num + elif isinstance(id_or_num, int): + id_or_num = self.tab_ids[id_or_num - 1 if id_or_num > 0 else id_or_num] + elif isinstance(id_or_num, WebPageTab): + return id_or_num.tab_id if as_id else id_or_num + + elif title == url == tab_type is None: + id_or_num = self.tab_id + else: - raise TypeError(f'id_or_num需传入tab id或序号,非{id_or_num}。') + id_or_num = self._browser.find_tabs(title, url, tab_type) + if id_or_num: + id_or_num = id_or_num[0] + else: + return None + + if as_id: + return id_or_num + + with self._lock: + return WebPageTab(self, id_or_num) + + def get_tabs(self, title=None, url=None, tab_type=None, 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对象组成的列表 + """ + if as_id: + return [tab['id'] for tab in self._browser.find_tabs(title, url, tab_type)] + with self._lock: + return [WebPageTab(self, tab['id']) for tab in self._browser.find_tabs(title, url, tab_type)] def new_tab(self, url=None, new_window=False, background=False, new_context=False): """新建一个标签页 diff --git a/DrissionPage/_pages/web_page.pyi b/DrissionPage/_pages/web_page.pyi index 8ee57bd..bca5147 100644 --- a/DrissionPage/_pages/web_page.pyi +++ b/DrissionPage/_pages/web_page.pyi @@ -127,7 +127,18 @@ class WebPage(SessionPage, ChromiumPage, BasePage): all_domains: bool = False, all_info: bool = False) -> Union[dict, list]: ... - def get_tab(self, id_or_num: Union[str, WebPageTab, int] = None) -> WebPageTab: ... + def get_tab(self, + id_or_num: Union[str, WebPageTab, int] = None, + title: str = None, + url: str = None, + tab_type: Union[str, list, tuple] = None, + as_id: bool = False) -> Union[WebPageTab, str, None]: ... + + def get_tabs(self, + title: str = None, + url: str = None, + tab_type: Union[str, list, tuple] = None, + as_id: bool = False) -> Union[List[WebPageTab], List[str]]: ... def new_tab(self, url: str = None, @@ -162,6 +173,9 @@ class WebPage(SessionPage, ChromiumPage, BasePage): verify: Any | None = ..., cert: Any | None = ...) -> Union[bool, Response]: ... + @property + def latest_tab(self) -> Union[WebPageTab, WebPage]: ... + @property def set(self) -> WebPageSetter: ... diff --git a/DrissionPage/_units/setter.pyi b/DrissionPage/_units/setter.pyi index 4a974bf..ce9e6d2 100644 --- a/DrissionPage/_units/setter.pyi +++ b/DrissionPage/_units/setter.pyi @@ -70,7 +70,7 @@ class ChromiumBaseSetter(BasePageSetter): class TabSetter(ChromiumBaseSetter): _owner: ChromiumTab = ... - def __init__(self, owner: Union[ChromiumTab, WebPage]): ... + def __init__(self, owner: Union[ChromiumTab, WebPageTab, WebPage, ChromiumPage]): ... @property def window(self) -> WindowSetter: ...