diff --git a/DrissionPage/_functions/tools.py b/DrissionPage/_functions/tools.py index 640d0cf..81e9515 100644 --- a/DrissionPage/_functions/tools.py +++ b/DrissionPage/_functions/tools.py @@ -269,10 +269,6 @@ def raise_error(result, ignore=None): r = ElementLostError() elif error in ('connection disconnected', 'No target with given id found'): r = PageDisconnectedError() - elif error == 'timeout': - r = TimeoutError(f'超时(等待{result["timeout"]}秒)。\n错误:{result["error"]}\nmethod:{result["method"]}\nargs:' - f'{result["args"]}\n出现这个错误可能意味着程序有bug,请把错误信息和重现方法告知作者,谢谢。\n' - '报告网站:https://gitee.com/g1879/DrissionPage/issues') elif error == 'alert exists.': r = AlertExistsError() elif error in ('Node does not have a layout object', 'Could not compute box model.'): @@ -283,10 +279,12 @@ def raise_error(result, ignore=None): r = StorageError() elif error == 'Sanitizing cookie failed': r = CookieFormatError(f'cookie格式不正确:{result["args"]}') - elif result['type'] == 'call_method_error': + elif result['type'] in ('call_method_error', 'timeout'): + from DrissionPage import __version__ + from time import process_time r = CDPError(f'\n错误:{result["error"]}\nmethod:{result["method"]}\nargs:{result["args"]}\n' - f'出现这个错误可能意味着程序有bug,请把错误信息和重现方法告知作者,谢谢。' - f'\n报告网站:https://gitee.com/g1879/DrissionPage/issues') + f'版本:{__version__}\n运行时间:{process_time()}\n出现这个错误可能意味着程序有bug,请把错误信息和重现方法' + '告知作者,谢谢。\n报告网站:https://gitee.com/g1879/DrissionPage/issues') else: r = RuntimeError(result) diff --git a/DrissionPage/_pages/chromium_base.py b/DrissionPage/_pages/chromium_base.py index 3920137..d1eadd0 100644 --- a/DrissionPage/_pages/chromium_base.py +++ b/DrissionPage/_pages/chromium_base.py @@ -58,6 +58,7 @@ class ChromiumBase(BasePage): self._doc_got = False # 用于在LoadEventFired和FrameStoppedLoading间标记是否已获取doc self._download_path = None self._load_end_time = 0 + self._init_jss = [] if not hasattr(self, '_listener'): self._listener = None @@ -492,7 +493,7 @@ class ChromiumBase(BasePage): :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 @@ -796,6 +797,30 @@ class ChromiumBase(BasePage): 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, js): + """添加初始化脚本,在页面加载任何脚本前执行 + :param js: js文本 + :return: 添加的脚本的id + """ + js_id = self.run_cdp('Page.addScriptToEvaluateOnNewDocument', source=js, + includeCommandLineAPI=True)['identifier'] + self._init_jss.append(js_id) + return js_id + + def remove_init_js(self, js_id=None): + """删除初始化脚本,js_id传入None时删除所有 + :param js_id: 脚本的id + :return: None + """ + if js_id is None: + for js_id in self._init_jss: + self.run_cdp('Page.removeScriptToEvaluateOnNewDocument', identifier=js_id) + self._init_jss.clear() + + elif js_id in self._init_jss: + self.run_cdp('Page.removeScriptToEvaluateOnNewDocument', identifier=js_id) + self._init_jss.remove(js_id) + def clear_cache(self, session_storage=True, local_storage=True, cache=True, cookies=True): """清除缓存,可选要清除的项 :param session_storage: 是否清除sessionStorage diff --git a/DrissionPage/_pages/chromium_base.pyi b/DrissionPage/_pages/chromium_base.pyi index 4ed83cb..5e107c4 100644 --- a/DrissionPage/_pages/chromium_base.pyi +++ b/DrissionPage/_pages/chromium_base.pyi @@ -58,6 +58,7 @@ class ChromiumBase(BasePage): 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 = ... @@ -214,6 +215,10 @@ class ChromiumBase(BasePage): def get_local_storage(self, item: str = None) -> Union[str, dict, None]: ... + def add_init_js(self, js: str) -> str: ... + + def remove_init_js(self, js_id: str = None) -> 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[int, int] = None, right_bottom: Tuple[int, int] = None) -> Union[str, bytes]: ... diff --git a/DrissionPage/_units/cookies_setter.py b/DrissionPage/_units/cookies_setter.py index e22878a..3eda66a 100644 --- a/DrissionPage/_units/cookies_setter.py +++ b/DrissionPage/_units/cookies_setter.py @@ -66,3 +66,38 @@ class SessionCookiesSetter(object): def clear(self): """清除cookies""" self._page.session.cookies.clear() + + +class WebPageCookiesSetter(CookiesSetter, SessionCookiesSetter): + + def __call__(self, cookies): + """设置多个cookie,注意不要传入单个 + :param cookies: cookies信息 + :return: None + """ + if self._page.mode == 'd' and self._page._has_driver: + super().__call__(cookies) + elif self._page.mode == 's' and self._page._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._page.mode == 'd' and self._page._has_driver: + super().remove(name, url, domain, path) + elif self._page.mode == 's' and self._page._has_session: + if url or domain or path: + raise AttributeError('url、domain、path参数只有d模式下有效。') + super(CookiesSetter, self).remove(name) + + def clear(self): + """清除cookies""" + if self._page.mode == 'd' and self._page._has_driver: + super().clear() + elif self._page.mode == 's' and self._page._has_session: + super(CookiesSetter, self).clear() diff --git a/DrissionPage/_units/cookies_setter.pyi b/DrissionPage/_units/cookies_setter.pyi index 4bfc3e9..f1b5877 100644 --- a/DrissionPage/_units/cookies_setter.pyi +++ b/DrissionPage/_units/cookies_setter.pyi @@ -4,13 +4,16 @@ from typing import Union from requests.cookies import RequestsCookieJar -from .._pages.session_page import SessionPage from .._pages.chromium_base import ChromiumBase +from .._pages.chromium_tab import WebPageTab +from .._pages.session_page import SessionPage +from .._pages.web_page import WebPage class CookiesSetter(object): - def __init__(self, page: ChromiumBase): - self._page: ChromiumBase = ... + _page: ChromiumBase + + def __init__(self, page: ChromiumBase): ... def __call__(self, cookies: Union[RequestsCookieJar, Cookie, list, tuple, str, dict]) -> None: ... @@ -20,11 +23,24 @@ class CookiesSetter(object): class SessionCookiesSetter(object): - def __init__(self, page: SessionPage): - self._page: SessionPage = ... + _page: SessionPage + + def __init__(self, page: SessionPage): ... def __call__(self, cookies: Union[RequestsCookieJar, Cookie, list, tuple, str, dict]) -> None: ... def remove(self, name: str) -> None: ... def clear(self) -> None: ... + + +class WebPageCookiesSetter(CookiesSetter, SessionCookiesSetter): + _page: Union[WebPage, WebPageTab] + + def __init__(self, page: SessionPage): ... + + def __call__(self, cookies: Union[RequestsCookieJar, Cookie, list, tuple, str, dict]) -> None: ... + + def remove(self, name: str, url: str = None, domain: str = None, path: str = None) -> None: ... + + def clear(self) -> None: ... diff --git a/DrissionPage/_units/rect.py b/DrissionPage/_units/rect.py index 93ac879..ac1a8a9 100644 --- a/DrissionPage/_units/rect.py +++ b/DrissionPage/_units/rect.py @@ -30,7 +30,8 @@ class ElementRect(object): @property def size(self): """返回元素大小,格式(宽, 高)""" - border = self._ele.page.run_cdp('DOM.getBoxModel', backendNodeId=self._ele._backend_id)['model']['border'] + border = self._ele.page.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 @@ -98,7 +99,8 @@ class ElementRect(object): :param quad: 方框类型,margin border padding :return: 四个角坐标 """ - return self._ele.page.run_cdp('DOM.getBoxModel', backendNodeId=self._ele._backend_id)['model'][quad] + return self._ele.page.run_cdp('DOM.getBoxModel', backendNodeId=self._ele._backend_id, + nodeId=self._ele._node_id, objectId=self._ele._obj_id)['model'][quad] def _get_page_coord(self, x, y): """根据视口坐标获取绝对坐标""" diff --git a/DrissionPage/_units/setter.py b/DrissionPage/_units/setter.py index 683ee10..8f8b1e1 100644 --- a/DrissionPage/_units/setter.py +++ b/DrissionPage/_units/setter.py @@ -7,10 +7,9 @@ from pathlib import Path from requests.structures import CaseInsensitiveDict -from .cookies_setter import SessionCookiesSetter, CookiesSetter +from .cookies_setter import SessionCookiesSetter, CookiesSetter, WebPageCookiesSetter from .._functions.tools import show_or_hide_browser -__ERROR__ = 'error' class BasePageSetter(object): def __init__(self, page): @@ -199,19 +198,6 @@ class TabSetter(ChromiumBaseSetter): """使标签页处于最前面""" self._page.browser.activate_tab(self._page.tab_id) - def add_init_script(self, script: str, raise_error=True): - '''添加初始化脚本,在页面加载任何脚本前执行 - :param script: js文本 - :return: identifier 添加的脚本的标识符,失败时返回False,或raise Error - ''' - result = self.driver.run('Page.addScriptToEvaluateOnNewDocument', source=script) - if not result or __ERROR__ not in result: - return result['identifier'] - else: - if raise_error: - raise_error(str(result)) - return False - class ChromiumPageSetter(TabSetter): @@ -384,15 +370,12 @@ class WebPageSetter(ChromiumPageSetter): self._session_setter = SessionPageSetter(self._page) self._chromium_setter = ChromiumPageSetter(self._page) - def cookies(self, cookies): - """添加cookies信息到浏览器或session对象 - :param cookies: 可以接收`CookieJar`、`list`、`tuple`、`str`、`dict`格式的`cookies` - :return: None - """ - if self._page.mode == 'd' and self._page._has_driver: - self._chromium_setter.cookies(cookies) - elif self._page.mode == 's' and self._page._has_session: - self._session_setter.cookies(cookies) + @property + def cookies(self): + """返回用于设置cookies的对象""" + if self._cookies_setter is None: + self._cookies_setter = WebPageCookiesSetter(self._page) + return self._cookies_setter def headers(self, headers) -> None: """设置固定发送的headers @@ -418,15 +401,12 @@ class WebPageTabSetter(TabSetter): self._session_setter = SessionPageSetter(self._page) self._chromium_setter = ChromiumBaseSetter(self._page) - def cookies(self, cookies): - """添加多个cookies信息到浏览器或session对象,注意不要传入单个 - :param cookies: 可以接收`CookieJar`、`list`、`tuple`、`str`、`dict`格式的`cookies` - :return: None - """ - if self._page.mode == 'd' and self._page._has_driver: - self._chromium_setter.cookies(cookies) - elif self._page.mode == 's' and self._page._has_session: - self._session_setter.cookies(cookies) + @property + def cookies(self): + """返回用于设置cookies的对象""" + if self._cookies_setter is None: + self._cookies_setter = WebPageCookiesSetter(self._page) + return self._cookies_setter def headers(self, headers) -> None: """设置固定发送的headers diff --git a/DrissionPage/_units/setter.pyi b/DrissionPage/_units/setter.pyi index 415decb..0ac2f98 100644 --- a/DrissionPage/_units/setter.pyi +++ b/DrissionPage/_units/setter.pyi @@ -9,7 +9,7 @@ from typing import Union, Tuple, Literal, Any, Optional from requests.adapters import HTTPAdapter from requests.auth import HTTPBasicAuth -from .cookies_setter import SessionCookiesSetter, CookiesSetter +from .cookies_setter import SessionCookiesSetter, CookiesSetter, WebPageCookiesSetter from .scroller import PageScroller from .._base.base import BasePage from .._elements.chromium_element import ChromiumElement @@ -143,7 +143,8 @@ class WebPageSetter(ChromiumPageSetter): def headers(self, headers: dict) -> None: ... - def cookies(self, cookies) -> None: ... + @property + def cookies(self) -> WebPageCookiesSetter: ... class WebPageTabSetter(TabSetter): @@ -155,7 +156,8 @@ class WebPageTabSetter(TabSetter): def headers(self, headers: dict) -> None: ... - def cookies(self, cookies) -> None: ... + @property + def cookies(self) -> WebPageCookiesSetter: ... class ChromiumElementSetter(object): diff --git a/DrissionPage/_units/waiter.py b/DrissionPage/_units/waiter.py index 3fed08e..84a6676 100644 --- a/DrissionPage/_units/waiter.py +++ b/DrissionPage/_units/waiter.py @@ -412,7 +412,7 @@ class ElementWaiter(object): while perf_counter() < end_time: sleep(gap) - if self._ele.rect.size == size and location == self._ele.rect.location: + if self._ele.rect.size == size and self._ele.rect.location == location: return True size = self._ele.rect.size location = self._ele.rect.location