From c000bec82656a47099a3b4f798e4f87e3a21dffd Mon Sep 17 00:00:00 2001 From: g1879 Date: Fri, 3 Mar 2023 15:00:37 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0NoResourceError=EF=BC=9Bclick?= =?UTF-8?q?()=E5=88=A0=E9=99=A4retry=E5=92=8Ctimeout=E5=8F=82=E6=95=B0?= =?UTF-8?q?=EF=BC=9Bget=5Fsrc()=E5=92=8Csave()=E5=A2=9E=E5=8A=A0timeout?= =?UTF-8?q?=E5=8F=82=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DrissionPage/chromium_base.py | 7 +- DrissionPage/chromium_base.pyi | 19 +++-- DrissionPage/chromium_driver.pyi | 2 +- DrissionPage/chromium_element.py | 87 +++++++++-------------- DrissionPage/chromium_element.pyi | 26 ++++--- DrissionPage/chromium_page.pyi | 4 +- DrissionPage/configs/chromium_options.pyi | 4 +- DrissionPage/configs/session_options.pyi | 4 +- DrissionPage/errors.py | 4 ++ DrissionPage/mixpage/session_page.pyi | 2 +- DrissionPage/session_page.pyi | 2 +- 11 files changed, 73 insertions(+), 88 deletions(-) diff --git a/DrissionPage/chromium_base.py b/DrissionPage/chromium_base.py index c8adb96..0867264 100644 --- a/DrissionPage/chromium_base.py +++ b/DrissionPage/chromium_base.py @@ -930,7 +930,7 @@ class ChromiumBaseWaiter(object): :param timeout: 超时时间,为None时使用页面timeout属性 :return: 是否等待成功 """ - return self._loading(timeout=timeout) + return self._loading(timeout=timeout, gap=.002) def load_complete(self, timeout=None): """等待页面开始加载 @@ -944,10 +944,11 @@ class ChromiumBaseWaiter(object): while self._driver._upload_list: sleep(.01) - def _loading(self, timeout=None, start=True): + def _loading(self, timeout=None, start=True, gap=.01): """等待页面开始加载或加载完成 :param timeout: 超时时间,为None时使用页面timeout属性 :param start: 等待开始还是结束 + :param gap: 间隔秒数 :return: 是否等待成功 """ if timeout != 0: @@ -956,7 +957,7 @@ class ChromiumBaseWaiter(object): while perf_counter() < end_time: if self._driver.is_loading == start: return True - sleep(.01) + sleep(gap) return False diff --git a/DrissionPage/chromium_base.pyi b/DrissionPage/chromium_base.pyi index 41585ac..7d0d60a 100644 --- a/DrissionPage/chromium_base.pyi +++ b/DrissionPage/chromium_base.pyi @@ -13,7 +13,7 @@ from requests.cookies import RequestsCookieJar from .commons.constants import NoneElement from .base import BasePage from .chromium_driver import ChromiumDriver -from .chromium_element import ChromiumElement, ChromiumScroll, ChromiumWaiter +from .chromium_element import ChromiumElement, ChromiumScroll from .chromium_frame import ChromiumFrame from .session_element import SessionElement @@ -193,21 +193,21 @@ class ChromiumBase(BasePage): timeout: float = None) -> Union[bool, None]: ... -class ChromiumBaseWaiter(ChromiumWaiter): +class ChromiumBaseWaiter(object): def __init__(self, page: ChromiumBase): self._driver: ChromiumBase = ... - def ele_delete(self, loc_or_ele: Union[str, tuple, ChromiumElement], timeout: Union[int, float]=None)->bool:... + def ele_delete(self, loc_or_ele: Union[str, tuple, ChromiumElement], timeout: float = None) -> bool: ... - def ele_display(self, loc_or_ele: Union[str, tuple, ChromiumElement], timeout: Union[int, float]=None)->bool:... + def ele_display(self, loc_or_ele: Union[str, tuple, ChromiumElement], timeout: float = None) -> bool: ... - def ele_hidden(self, loc_or_ele: Union[str, tuple, ChromiumElement], timeout: Union[int, float]=None)->bool:... + def ele_hidden(self, loc_or_ele: Union[str, tuple, ChromiumElement], timeout: float = None) -> bool: ... - def _loading(self, timeout: Union[int, float] = None, start: bool = True) -> bool: ... + def _loading(self, timeout: float = None, start: bool = True, gap: float = .01) -> bool: ... - def load_start(self, timeout: Union[int, float] = None) -> bool: ... + def load_start(self, timeout: float = None) -> bool: ... - def load_complete(self, timeout: Union[int, float] = None) -> bool: ... + def load_complete(self, timeout: float = None) -> bool: ... def upload_paths_inputted(self) -> None: ... @@ -225,8 +225,7 @@ class ChromiumBaseSetter(object): @property def load_strategy(self) -> PageLoadStrategy: ... - def timeouts(self, implicit: Union[int, float] = None, page_load: Union[int, float] = None, - script: Union[int, float] = None): ... + def timeouts(self, implicit: float = None, page_load: float = None, script: float = None): ... def user_agent(self, ua: str, platform: str = None) -> None: ... diff --git a/DrissionPage/chromium_driver.pyi b/DrissionPage/chromium_driver.pyi index 77c2a9f..f43118a 100644 --- a/DrissionPage/chromium_driver.pyi +++ b/DrissionPage/chromium_driver.pyi @@ -39,7 +39,7 @@ class ChromiumDriver(object): def __init__(self, tab_id: str, tab_type: str, address: str): ... - def _send(self, message: dict, timeout: Union[int, float] = None) -> dict: ... + def _send(self, message: dict, timeout: float = None) -> dict: ... def _recv_loop(self) -> None: ... diff --git a/DrissionPage/chromium_element.py b/DrissionPage/chromium_element.py index f755866..54b8161 100644 --- a/DrissionPage/chromium_element.py +++ b/DrissionPage/chromium_element.py @@ -15,7 +15,7 @@ from .commons.keys import keys_to_typing, keyDescriptionForString, keyDefinition from .commons.locator import get_loc from .commons.web import make_absolute_link, get_ele_txt, format_html, is_js_func, location_in_viewport, offset_scroll from .errors import ContextLossError, ElementLossError, JavaScriptError, NoRectError, ElementNotFoundError, \ - CallMethodError + CallMethodError, NoResourceError from .session_element import make_session_ele @@ -401,26 +401,39 @@ class ChromiumElement(DrissionElement): js = f'return window.getComputedStyle(this{pseudo_ele}).getPropertyValue("{style}");' return self.run_js(js) - def get_src(self): - """返回元素src资源,base64的会转为bytes返回,其它返回str""" + def get_src(self, timeout=None): + """返回元素src资源,base64的会转为bytes返回,其它返回str + :param timeout: 等待资源加载的超时时间 + :return: 资源内容 + """ src = self.prop('currentSrc') if not src: return None + timeout = self.page.timeout if timeout is None else timeout + if self.tag == 'img': # 等待图片加载完成 js = ('return this.complete && typeof this.naturalWidth != "undefined" ' '&& this.naturalWidth > 0 && typeof this.naturalHeight != "undefined" ' '&& this.naturalHeight > 0') - end_time = perf_counter() + self.page.timeout + end_time = perf_counter() + timeout while not self.run_js(js) and perf_counter() < end_time: sleep(.1) node = self.page.run_cdp('DOM.describeNode', backendNodeId=self._backend_id)['node'] frame = node.get('frameId', None) frame = frame or self.page.tab_id - try: - result = self.page.run_cdp('Page.getResourceContent', frameId=frame, url=src) - except Exception: + + result = None + end_time = perf_counter() + timeout + while perf_counter() < end_time: + try: + result = self.page.run_cdp('Page.getResourceContent', frameId=frame, url=src) + except CallMethodError: + pass + sleep(.1) + + if not result: return None if result['base64Encoded']: @@ -430,15 +443,16 @@ class ChromiumElement(DrissionElement): data = result['content'] return data - def save(self, path=None, rename=None): + def save(self, path=None, rename=None, timeout=None): """保存图片或其它有src属性的元素的资源 :param path: 文件保存路径,为None时保存到当前文件夹 :param rename: 文件名称,为None时从资源url获取 + :param timeout: 等待资源加载的超时时间 :return: None """ - data = self.get_src() + data = self.get_src(timeout=timeout) if not data: - raise TypeError('该元素无可保存的内容或保存失败。') + raise NoResourceError path = path or '.' rename = rename or basename(self.prop('currentSrc')) @@ -1615,61 +1629,30 @@ class Click(object): """ self._ele = ele - def __call__(self, by_js=None, retry=False, timeout=.2, wait_loading=0): + def __call__(self, by_js=None, wait_loading=0): """点击元素 - 如果遇到遮挡,会重新尝试点击直到超时,若都失败就改用js点击 - :param by_js: 是否用js点击,为True时直接用js点击,为False时重试失败也不会改用js - :param retry: 遇到其它元素遮挡时,是否重试 - :param timeout: 尝试点击的超时时间,不指定则使用父页面的超时时间,retry为True时才生效 + 如果遇到遮挡,可选择是否用js点击 + :param by_js: 是否用js点击,为None时先用模拟点击,遇到遮挡改用js,为True时直接用js点击,为False时只用模拟点击 :param wait_loading: 等待页面进入加载状态超时时间 :return: 是否点击成功 """ - return self.left(by_js, retry, timeout, wait_loading) + return self.left(by_js, wait_loading) - def left(self, by_js=None, retry=False, timeout=.2, wait_loading=0): + def left(self, by_js=None, wait_loading=0): """点击元素 - 如果遇到遮挡,会重新尝试点击直到超时,若都失败就改用js点击 - :param by_js: 是否用js点击,为True时直接用js点击,为False时重试失败也不会改用js - :param retry: 遇到其它元素遮挡时,是否重试 - :param timeout: 尝试点击的超时时间,不指定则使用父页面的超时时间,retry为True时才生效 + 如果遇到遮挡,可选择是否用js点击 + :param by_js: 是否用js点击,为None时先用模拟点击,遇到遮挡改用js,为True时直接用js点击,为False时只用模拟点击 :param wait_loading: 等待页面进入加载状态超时时间 :return: 是否点击成功 """ - - def do_it(cx, cy, lx, ly): - """无遮挡返回True,有遮挡返回False,无元素返回None""" - try: - r = self._ele.page.run_cdp('DOM.getNodeForLocation', x=lx, y=ly) - except CallMethodError: - return None - - if retry and r.get('backendNodeId') != self._ele.ids.backend_id: - return False - - self._click(cx, cy) - return True - if not by_js: try: self._ele.page.scroll.to_see(self._ele) - if self._ele.states.is_in_viewport: + if self._ele.states.is_in_viewport and not self._ele.states.is_covered: client_x, client_y = self._ele.locations.viewport_click_point - if client_x: - loc_x, loc_y = self._ele.locations.click_point - - click = do_it(client_x, client_y, loc_x, loc_y) - if click: - self._ele.page.wait.load_start(wait_loading) - return True - - timeout = timeout if timeout is not None else self._ele.page.timeout - end_time = perf_counter() + timeout - while click is False and perf_counter() < end_time: - click = do_it(client_x, client_y, loc_x, loc_y) - - if click is not None: - self._ele.page.wait.load_start(wait_loading) - return True + self._click(client_x, client_y) + self._ele.page.wait.load_start(wait_loading) + return True except NoRectError: by_js = True diff --git a/DrissionPage/chromium_element.pyi b/DrissionPage/chromium_element.pyi index 925ca48..d43b1aa 100644 --- a/DrissionPage/chromium_element.pyi +++ b/DrissionPage/chromium_element.pyi @@ -30,7 +30,7 @@ class ChromiumElement(DrissionElement): self._scroll: ChromiumScroll = ... self._click: Click = ... self._select: ChromiumSelect = ... - self._wait: ChromiumWaiter = ... + self._wait: ChromiumElementWaiter = ... self._locations: Locations = ... self._set: ChromiumElementSetter = ... self._states: ChromiumElementStates = ... @@ -167,9 +167,9 @@ class ChromiumElement(DrissionElement): def style(self, style: str, pseudo_ele: str = '') -> str: ... - def get_src(self) -> Union[bytes, str, None]: ... + def get_src(self, timeout: float = None) -> Union[bytes, str, None]: ... - def save(self, path: [str, bool] = None, rename: str = None) -> None: ... + def save(self, path: [str, bool] = None, rename: str = None, timeout: float = None) -> None: ... def get_screenshot(self, path: [str, Path] = None, as_bytes: [bool, str] = None) -> Union[str, bytes]: ... @@ -430,11 +430,9 @@ class Click(object): def __init__(self, ele: ChromiumElement): self._ele: ChromiumElement = ... - def __call__(self, by_js: bool = None, retry: bool = False, timeout: float = 0.2, - wait_loading: Union[bool, float] = 0) -> bool: ... + def __call__(self, by_js: bool = None, wait_loading: Union[bool, float] = 0) -> bool: ... - def left(self, by_js: bool = None, retry: bool = False, timeout: float = 0.2, - wait_loading: Union[bool, float] = 0) -> bool: ... + def left(self, by_js: bool = None, wait_loading: Union[bool, float] = 0) -> bool: ... def right(self): ... @@ -531,19 +529,19 @@ class ChromiumElementWaiter(object): self._loc_or_ele: Union[str, tuple, ChromiumElement] = ... self._driver: Union[ChromiumPage, ChromiumPage] = ... - def delete(self, timeout: Union[int, float] = None) -> bool: ... + def delete(self, timeout: float = None) -> bool: ... - def display(self, timeout: Union[int, float] = None) -> bool: ... + def display(self, timeout: float = None) -> bool: ... - def hidden(self, timeout: Union[int, float] = None) -> bool: ... + def hidden(self, timeout: float = None) -> bool: ... - def _covered(self, mode: bool = False, timeout: Union[int, float] = None) -> bool: ... + def _covered(self, mode: bool = False, timeout: float = None) -> bool: ... - def covered(self, timeout: Union[int, float] = None) -> bool: ... + def covered(self, timeout: float = None) -> bool: ... - def not_covered(self, timeout: Union[int, float] = None) -> bool: ... + def not_covered(self, timeout: float = None) -> bool: ... - def _wait_ele(self, mode: str, timeout: Union[int, float] = None) -> Union[None, bool]: ... + def _wait_ele(self, mode: str, timeout: float = None) -> Union[None, bool]: ... class Pseudo(object): diff --git a/DrissionPage/chromium_page.pyi b/DrissionPage/chromium_page.pyi index f54bd9a..aa44e5b 100644 --- a/DrissionPage/chromium_page.pyi +++ b/DrissionPage/chromium_page.pyi @@ -109,7 +109,7 @@ class ChromiumPage(ChromiumBase): class ChromiumPageWaiter(ChromiumBaseWaiter): _driver: ChromiumPage = ... - def download_begin(self, timeout: Union[int, float] = None) -> bool: ... + def download_begin(self, timeout: float = None) -> bool: ... class ChromiumTabRect(object): @@ -163,7 +163,7 @@ class ChromiumDownloadSetter(DownloadSetter): def by_DownloadKit(self) -> None: ... - def wait_download_begin(self, timeout: Union[int, float] = None) -> bool: ... + def wait_download_begin(self, timeout: float = None) -> bool: ... def _cookies_to_session(self) -> None: ... diff --git a/DrissionPage/configs/chromium_options.pyi b/DrissionPage/configs/chromium_options.pyi index af7fc80..16e4f76 100644 --- a/DrissionPage/configs/chromium_options.pyi +++ b/DrissionPage/configs/chromium_options.pyi @@ -75,8 +75,8 @@ class ChromiumOptions(object): def remove_pref_from_file(self, arg: str) -> ChromiumOptions: ... - def set_timeouts(self, implicit: Union[int, float] = None, pageLoad: Union[int, float] = None, - script: Union[int, float] = None) -> ChromiumOptions: ... + def set_timeouts(self, implicit: float = None, pageLoad: float = None, + script: float = None) -> ChromiumOptions: ... def set_user(self, user: str = 'Default') -> ChromiumOptions: ... diff --git a/DrissionPage/configs/session_options.pyi b/DrissionPage/configs/session_options.pyi index 30e7eaa..3c0ae72 100644 --- a/DrissionPage/configs/session_options.pyi +++ b/DrissionPage/configs/session_options.pyi @@ -37,9 +37,9 @@ class SessionOptions(object): def set_paths(self, download_path: Union[str, Path]) -> SessionOptions: ... @property - def timeout(self) -> Union[int, float]: ... + def timeout(self) -> float: ... - def set_timeout(self, second: Union[int, float]) -> SessionOptions: ... + def set_timeout(self, second: float) -> SessionOptions: ... @property def headers(self) -> dict: ... diff --git a/DrissionPage/errors.py b/DrissionPage/errors.py index d72c325..20805ee 100644 --- a/DrissionPage/errors.py +++ b/DrissionPage/errors.py @@ -46,3 +46,7 @@ class NoRectError(BaseError): class BrowserConnectError(BaseError): _info = '浏览器连接失败。' + + +class NoResourceError(BaseError): + _info = '该元素无可保存的内容或保存失败。' diff --git a/DrissionPage/mixpage/session_page.pyi b/DrissionPage/mixpage/session_page.pyi index ab72a36..95011aa 100644 --- a/DrissionPage/mixpage/session_page.pyi +++ b/DrissionPage/mixpage/session_page.pyi @@ -170,7 +170,7 @@ class SessionPageSetter(object): def __init__(self, page: SessionPage): self._page: SessionPage = ... - def timeout(self, second: Union[int, float]) -> None: ... + def timeout(self, second: float) -> None: ... def cookies(self, cookies: Union[RequestsCookieJar, list, tuple, str, dict]) -> None: ... diff --git a/DrissionPage/session_page.pyi b/DrissionPage/session_page.pyi index f6d9299..a4c04cd 100644 --- a/DrissionPage/session_page.pyi +++ b/DrissionPage/session_page.pyi @@ -164,7 +164,7 @@ class SessionPageSetter(object): def __init__(self, page: SessionPage): self._page: SessionPage = ... - def timeout(self, second: Union[int, float]) -> None: ... + def timeout(self, second: float) -> None: ... def cookies(self, cookies: Union[RequestsCookieJar, list, tuple, str, dict]) -> None: ...