From f2218cf0d3f6457bcf6c7cdce4036c5160a6b356 Mon Sep 17 00:00:00 2001 From: g1879 Date: Fri, 6 Sep 2024 07:16:44 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0find()=E6=96=B9=E6=B3=95?= =?UTF-8?q?=EF=BC=9B=E5=85=83=E7=B4=A0=E5=A2=9E=E5=8A=A0timeout=E5=B1=9E?= =?UTF-8?q?=E6=80=A7=EF=BC=9B=E4=BC=98=E5=8C=96NoneElement=E7=9B=B8?= =?UTF-8?q?=E5=85=B3=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DrissionPage/_base/base.py | 30 +++++++++++++------ DrissionPage/_base/base.pyi | 25 ++++++++++++++-- DrissionPage/_elements/chromium_element.py | 5 ++-- DrissionPage/_elements/chromium_element.pyi | 4 +-- DrissionPage/_elements/none_element.py | 6 ++-- DrissionPage/_elements/session_element.py | 2 +- DrissionPage/_elements/session_element.pyi | 2 +- DrissionPage/_functions/elements.py | 32 ++++++++++++++------- DrissionPage/_functions/elements.pyi | 9 +++--- DrissionPage/_pages/chromium_base.py | 6 ++-- DrissionPage/_pages/chromium_base.pyi | 2 +- DrissionPage/_pages/chromium_frame.py | 2 +- DrissionPage/_pages/chromium_frame.pyi | 2 +- DrissionPage/_pages/mix_tab.py | 4 +-- DrissionPage/_pages/mix_tab.pyi | 2 +- DrissionPage/_pages/session_page.py | 2 +- DrissionPage/_pages/session_page.pyi | 2 +- DrissionPage/_pages/web_page.py | 4 +-- DrissionPage/_pages/web_page.pyi | 2 +- DrissionPage/common.py | 3 +- 20 files changed, 96 insertions(+), 50 deletions(-) diff --git a/DrissionPage/_base/base.py b/DrissionPage/_base/base.py index b547126..84d976c 100644 --- a/DrissionPage/_base/base.py +++ b/DrissionPage/_base/base.py @@ -16,7 +16,7 @@ from requests import Session from .._configs.session_options import SessionOptions from .._elements.none_element import NoneElement -from .._functions.elements import get_frame +from .._functions.elements import get_frame, get_eles from .._functions.locator import get_loc from .._functions.settings import Settings from .._functions.web import format_html @@ -35,6 +35,13 @@ class BaseParser(object): def eles(self, locator, timeout=None): return self._ele(locator, timeout, index=None) + def find(self, locators, any_one=False, first_ele=True, timeout=None): + if 'Session' in self._type: + timeout = 0 + if timeout is None: + timeout = self.timeout + return get_eles(locators, self, any_one, first_ele, timeout) + # ----------------以下属性或方法待后代实现---------------- @property def html(self): @@ -49,7 +56,7 @@ class BaseParser(object): def _ele(self, locator, timeout=None, index=1, raise_err=None, method=None): pass - def _find_elements(self, locator, timeout=None, index=1, relative=False, raise_err=None): + def _find_elements(self, locator, timeout, index=1, relative=False, raise_err=None): pass @@ -68,16 +75,22 @@ class BaseElement(BaseParser): def _ele(self, locator, timeout=None, index=1, relative=False, raise_err=None, method=None): if hasattr(locator, '_type'): return locator + if timeout is None: + timeout = self.timeout r = self._find_elements(locator, timeout=timeout, index=index, relative=relative, raise_err=raise_err) if r or isinstance(r, list): return r if Settings.raise_when_ele_not_found or raise_err is True: - raise ElementNotFoundError(None, method, {'locator': locator, 'index': index}) + raise ElementNotFoundError(None, method, {'locator': locator, 'index': index, 'timeout': timeout}) r.method = method - r.args = {'locator': locator, 'index': index} + r.args = {'locator': locator, 'index': index, 'timeout': timeout} return r + @property + def timeout(self): + return self.owner.timeout + # ----------------以下属性或方法由后代实现---------------- @property def tag(self): @@ -235,7 +248,7 @@ class DrissionElement(BaseElement): def _get_ele_path(self, mode): return '' - def _find_elements(self, locator, timeout=None, index=1, relative=False, raise_err=None): + def _find_elements(self, locator, timeout, index=1, relative=False, raise_err=None): pass @@ -327,14 +340,15 @@ class BasePage(BaseParser): def _ele(self, locator, timeout=None, index=1, raise_err=None, method=None): if not locator: raise ElementNotFoundError(None, method, {'locator': locator}) + if timeout is None: + timeout = self.timeout r = self._find_elements(locator, timeout=timeout, index=index, raise_err=raise_err) - if r or isinstance(r, list): return r if Settings.raise_when_ele_not_found or raise_err is True: - raise ElementNotFoundError(None, method, {'locator': locator, 'index': index}) + raise ElementNotFoundError(None, method, {'locator': locator, 'index': index, 'timeout': timeout}) r.method = method - r.args = {'locator': locator, 'index': index} + r.args = {'locator': locator, 'index': index, 'timeout': timeout} return r diff --git a/DrissionPage/_base/base.pyi b/DrissionPage/_base/base.pyi index c6b501c..a3aaf6d 100644 --- a/DrissionPage/_base/base.pyi +++ b/DrissionPage/_base/base.pyi @@ -6,13 +6,14 @@ @License : BSD 3-Clause. """ from abc import abstractmethod -from typing import Union, Tuple, List, Any, Optional +from typing import Union, Tuple, List, Any, Optional, Dict from DownloadKit import DownloadKit from requests import Session from requests.structures import CaseInsensitiveDict from .._configs.session_options import SessionOptions +from .._elements.chromium_element import ChromiumElement from .._elements.none_element import NoneElement from .._elements.session_element import SessionElement from .._functions.elements import SessionElementsList @@ -34,6 +35,21 @@ class BaseParser(object): def eles(self, locator: Union[Tuple[str, str], str], timeout=None): ... + def find(self, + locators: Union[str, List[str], tuple], + any_one: bool = False, + first_ele: bool = True, + timeout: float = None) -> Union[Dict[str, ChromiumElement], Dict[str, SessionElement], + Dict[str, List[ChromiumElement]], Dict[str, List[SessionElement]]]: + """传入多个定位符,获取多个ele + :param locators: 定位符组成的列表 + :param any_one: 是否任何一个定位符找到结果即返回 + :param first_ele: 每个定位符是否只获取第一个元素 + :param timeout: 超时时间(秒) + :return: 多个定位符组成的dict,first_only为False返回列表,否则为元素,无结果的返回False + """ + ... + # ----------------以下属性或方法待后代实现---------------- @property def html(self) -> str: ... @@ -53,7 +69,7 @@ class BaseParser(object): def _find_elements(self, locator: Union[Tuple[str, str], str], - timeout: float = None, + timeout: float, index: Optional[int] = 1, relative: bool = False, raise_err: bool = None): ... @@ -64,6 +80,11 @@ class BaseElement(BaseParser): def __init__(self, owner: BasePage = None): ... + @property + def timeout(self) -> float: + """返回其查找元素时超时时间""" + ... + # ----------------以下属性或方法由后代实现---------------- @property def tag(self) -> str: ... diff --git a/DrissionPage/_elements/chromium_element.py b/DrissionPage/_elements/chromium_element.py index a6c85df..74aa7de 100644 --- a/DrissionPage/_elements/chromium_element.py +++ b/DrissionPage/_elements/chromium_element.py @@ -428,7 +428,7 @@ class ChromiumElement(DrissionElement): return (make_session_ele(self, locator, index=None) if self.ele(locator, timeout=timeout) else SessionElementsList()) - def _find_elements(self, locator, timeout=None, index=1, relative=False, raise_err=None): + def _find_elements(self, locator, timeout, index=1, relative=False, raise_err=None): return find_in_chromium_ele(self, locator, index, timeout, relative=relative) def style(self, style, pseudo_ele=''): @@ -851,7 +851,7 @@ class ShadowRoot(BaseElement): return (make_session_ele(self, locator, index=None) if self.ele(locator, timeout=timeout) else SessionElementsList()) - def _find_elements(self, locator, timeout=None, index=1, relative=False, raise_err=None): + def _find_elements(self, locator, timeout, index=1, relative=False, raise_err=None): loc = get_loc(locator, css_mode=False) if loc[0] == 'css selector' and str(loc[1]).startswith(':root'): loc = loc[0], loc[1][5:] @@ -901,7 +901,6 @@ class ShadowRoot(BaseElement): r = make_chromium_eles(self.owner, _ids=node_ids, index=index, is_obj_id=False) return None if r is False else r - timeout = timeout if timeout is not None else self.owner.timeout end_time = perf_counter() + timeout result = do_find() while result is None and perf_counter() <= end_time: diff --git a/DrissionPage/_elements/chromium_element.pyi b/DrissionPage/_elements/chromium_element.pyi index ec49a4f..09ab107 100644 --- a/DrissionPage/_elements/chromium_element.pyi +++ b/DrissionPage/_elements/chromium_element.pyi @@ -466,7 +466,7 @@ class ChromiumElement(DrissionElement): def _find_elements(self, locator: Union[Tuple[str, str], str], - timeout: float = None, + timeout: float, index: Optional[int] = 1, relative: bool = False, raise_err: bool = False) -> Union[ChromiumElement, ChromiumFrame, ChromiumElementsList]: @@ -831,7 +831,7 @@ class ShadowRoot(BaseElement): def _find_elements(self, locator: Union[Tuple[str, str], str], - timeout: float = None, + timeout: float, index: Optional[int] = 1, relative: bool = False, raise_err: bool = None) -> Union[ChromiumElement, ChromiumFrame, str, ChromiumElementsList]: diff --git a/DrissionPage/_elements/none_element.py b/DrissionPage/_elements/none_element.py index cbbfe8c..33bef46 100644 --- a/DrissionPage/_elements/none_element.py +++ b/DrissionPage/_elements/none_element.py @@ -21,7 +21,7 @@ class NoneElement(object): self._none_ele_value = None self._none_ele_return_value = False self.method = method - self.args = args + self.args = {} if args is None else args self._get = None def __call__(self, *args, **kwargs): @@ -36,8 +36,8 @@ class NoneElement(object): def __getattr__(self, item): if not self._none_ele_return_value: raise ElementNotFoundError(None, self.method, self.args) - elif item in ('ele', 's_ele', 'parent', 'child', 'next', 'prev', 'before', - 'after', 'get_frame', 'shadow_root', 'sr'): + elif item in ('ele', 's_ele', 'parent', 'child', 'next', 'prev', 'before', 'east', 'north', 'south', 'west', + 'offset', 'over', 'after', 'get_frame', 'shadow_root', 'sr'): return self else: if item in ('size', 'link', 'css_path', 'xpath', 'comments', 'texts', 'tag', 'html', 'inner_html', diff --git a/DrissionPage/_elements/session_element.py b/DrissionPage/_elements/session_element.py index 4234036..5930a5b 100644 --- a/DrissionPage/_elements/session_element.py +++ b/DrissionPage/_elements/session_element.py @@ -142,7 +142,7 @@ class SessionElement(DrissionElement): def s_eles(self, locator): return self._ele(locator, index=None) - def _find_elements(self, locator, timeout=None, index=1, relative=False, raise_err=None): + def _find_elements(self, locator, timeout, index=1, relative=False, raise_err=None): return make_session_ele(self, locator, index=index) def _get_ele_path(self, mode): diff --git a/DrissionPage/_elements/session_element.pyi b/DrissionPage/_elements/session_element.pyi index b5478bd..b883540 100644 --- a/DrissionPage/_elements/session_element.pyi +++ b/DrissionPage/_elements/session_element.pyi @@ -269,7 +269,7 @@ class SessionElement(DrissionElement): def _find_elements(self, locator: Union[Tuple[str, str], str], - timeout: float = None, + timeout: float, index: Optional[int] = 1, relative: bool = False, raise_err: bool = None) -> Union[SessionElement, SessionElementsList]: diff --git a/DrissionPage/_functions/elements.py b/DrissionPage/_functions/elements.py index c28f66c..a0e8942 100644 --- a/DrissionPage/_functions/elements.py +++ b/DrissionPage/_functions/elements.py @@ -5,7 +5,7 @@ @Copyright: (c) 2024 by g1879, Inc. All Rights Reserved. @License : BSD 3-Clause. """ -from time import perf_counter +from time import perf_counter, sleep from .locator import is_loc from .._elements.none_element import NoneElement @@ -263,19 +263,31 @@ class Getter(object): def get_eles(locators, owner, any_one=False, first_ele=True, timeout=10): - res = {loc: False for loc in locators} + if isinstance(locators, str): + locators = (locators,) + res = {loc: None for loc in locators} + + if timeout == 0: + for loc in locators: + ele = owner._ele(loc, timeout=0, raise_err=False, index=1 if first_ele else None, method='find()') + res[loc] = ele + if ele and any_one: + return res + return res + end_time = perf_counter() + timeout while perf_counter() <= end_time: for loc in locators: - if res[loc] is not False: + if res[loc]: continue - ele = owner._ele(loc, timeout=0, raise_err=False, index=1 if first_ele else None) - if ele: - res[loc] = ele - if any_one: - return res - if False not in res.values(): - break + ele = owner._ele(loc, timeout=0, raise_err=False, index=1 if first_ele else None, method='find()') + res[loc] = ele + if ele and any_one: + return res + if all(res.values()): + return res + sleep(.05) + return res diff --git a/DrissionPage/_functions/elements.pyi b/DrissionPage/_functions/elements.pyi index aaeeea4..c7ae7e2 100644 --- a/DrissionPage/_functions/elements.pyi +++ b/DrissionPage/_functions/elements.pyi @@ -5,7 +5,7 @@ @Copyright: (c) 2024 by g1879, Inc. All Rights Reserved. @License : BSD 3-Clause. """ -from typing import Union, List, Optional, Iterable +from typing import Union, List, Optional, Iterable, Dict from .._base.base import BaseParser from .._elements.chromium_element import ChromiumElement @@ -551,18 +551,19 @@ class Getter(object): ... -def get_eles(locators: Union[List[str], tuple], +def get_eles(locators: Union[str, List[str], tuple], owner: BaseParser, any_one: bool = False, first_ele: bool = True, - timeout: float = 10) -> dict: + timeout: float = 10) -> Union[Dict[str, ChromiumElement], Dict[str, SessionElement], +Dict[str, List[ChromiumElement]], Dict[str, List[SessionElement]]]: """传入多个定位符,获取多个ele :param locators: 定位符组成的列表 :param owner: 页面或元素对象 :param any_one: 是否找到任何一个即返回 :param first_ele: 每个定位符是否只获取第一个元素 :param timeout: 超时时间(秒) - :return: 多个定位符组成的dict + :return: 多个定位符组成的dict,first_only为False返回列表,否则为元素,无结果的返回False """ ... diff --git a/DrissionPage/_pages/chromium_base.py b/DrissionPage/_pages/chromium_base.py index fe5873b..29813c3 100644 --- a/DrissionPage/_pages/chromium_base.py +++ b/DrissionPage/_pages/chromium_base.py @@ -425,7 +425,8 @@ class ChromiumBase(BasePage): return self._ele(locator, timeout=timeout, index=None) def s_ele(self, locator=None, index=1, timeout=None): - return (NoneElement(self, method='s_ele()', args={'locator': locator, 'index': index}) + timeout = self.timeout if timeout is None else timeout + return (NoneElement(self, method='s_ele()', args={'locator': locator, 'index': index, 'timeout': timeout}) if locator and not self.wait.eles_loaded(locator, timeout=timeout) else make_session_ele(self, locator, index=index, method='s_ele()')) @@ -433,7 +434,7 @@ class ChromiumBase(BasePage): return (make_session_ele(self, locator, index=None) if self.wait.eles_loaded(locator, timeout=timeout) else SessionElementsList()) - def _find_elements(self, locator, timeout=None, index=1, relative=False, raise_err=None): + def _find_elements(self, locator, timeout, index=1, relative=False, raise_err=None): if isinstance(locator, (str, tuple)): loc = get_loc(locator)[1] elif locator._type in ('ChromiumElement', 'ChromiumFrame'): @@ -442,7 +443,6 @@ class ChromiumBase(BasePage): raise ValueError('locator参数只能是tuple、str、ChromiumElement类型。') self.wait.doc_loaded() - timeout = timeout if timeout is not None else self.timeout end_time = perf_counter() + timeout search_ids = [] diff --git a/DrissionPage/_pages/chromium_base.pyi b/DrissionPage/_pages/chromium_base.pyi index 8f34819..335f5ee 100644 --- a/DrissionPage/_pages/chromium_base.pyi +++ b/DrissionPage/_pages/chromium_base.pyi @@ -423,7 +423,7 @@ class ChromiumBase(BasePage): def _find_elements(self, locator: Union[Tuple[str, str], str, ChromiumElement, ChromiumFrame], - timeout: float = None, + timeout: float, index: Optional[int] = 1, relative: bool = False, raise_err: bool = None) -> Union[ChromiumElement, ChromiumFrame, ChromiumElementsList]: diff --git a/DrissionPage/_pages/chromium_frame.py b/DrissionPage/_pages/chromium_frame.py index bd668d2..2e7a243 100644 --- a/DrissionPage/_pages/chromium_frame.py +++ b/DrissionPage/_pages/chromium_frame.py @@ -438,7 +438,7 @@ class ChromiumFrame(ChromiumBase): self.tab.remove_ele(new_ele) return r - def _find_elements(self, locator, timeout=None, index=1, relative=False, raise_err=None): + def _find_elements(self, locator, timeout, index=1, relative=False, raise_err=None): if isinstance(locator, ChromiumElement): return locator self.wait.doc_loaded() diff --git a/DrissionPage/_pages/chromium_frame.pyi b/DrissionPage/_pages/chromium_frame.pyi index e9e31fd..19c695d 100644 --- a/DrissionPage/_pages/chromium_frame.pyi +++ b/DrissionPage/_pages/chromium_frame.pyi @@ -426,7 +426,7 @@ class ChromiumFrame(ChromiumBase): def _find_elements(self, locator: Union[Tuple[str, str], str, ChromiumElement, ChromiumFrame], - timeout: float = None, + timeout: float, index: Optional[int] = 1, relative: bool = False, raise_err: bool = None) -> Union[ChromiumElement, ChromiumFrame, None, ChromiumElementsList]: diff --git a/DrissionPage/_pages/mix_tab.py b/DrissionPage/_pages/mix_tab.py index 28f2360..2b374c3 100644 --- a/DrissionPage/_pages/mix_tab.py +++ b/DrissionPage/_pages/mix_tab.py @@ -182,9 +182,9 @@ class MixTab(SessionPage, ChromiumTab, BasePage): if self._response is not None: self._response.close() - def _find_elements(self, locator, timeout=None, index=1, relative=False, raise_err=None): + def _find_elements(self, locator, timeout, index=1, relative=False, raise_err=None): return super(SessionPage, self)._find_elements(locator, timeout=timeout, index=index, relative=relative) \ - if self._d_mode else super()._find_elements(locator, index=index) + if self._d_mode else super()._find_elements(locator, index=index, timeout=timeout) def _set_session_options(self, session_or_options=None): if session_or_options is None: diff --git a/DrissionPage/_pages/mix_tab.pyi b/DrissionPage/_pages/mix_tab.pyi index 20a281d..5c9d6be 100644 --- a/DrissionPage/_pages/mix_tab.pyi +++ b/DrissionPage/_pages/mix_tab.pyi @@ -279,7 +279,7 @@ class MixTab(SessionPage, ChromiumTab): def _find_elements(self, locator: Union[Tuple[str, str], str, ChromiumElement, SessionElement, ChromiumFrame], - timeout: float = None, + timeout: float, index: Optional[int] = 1, relative: bool = False, raise_err: bool = None) \ diff --git a/DrissionPage/_pages/session_page.py b/DrissionPage/_pages/session_page.py index d85e87e..c3ee1fa 100644 --- a/DrissionPage/_pages/session_page.py +++ b/DrissionPage/_pages/session_page.py @@ -146,7 +146,7 @@ class SessionPage(BasePage): def s_eles(self, locator): return self._ele(locator, index=None) - def _find_elements(self, locator, timeout=None, index=1, relative=True, raise_err=None): + def _find_elements(self, locator, timeout, index=1, relative=True, raise_err=None): return locator if isinstance(locator, SessionElement) else make_session_ele(self, locator, index=index) def cookies(self, all_domains=False, all_info=False): diff --git a/DrissionPage/_pages/session_page.pyi b/DrissionPage/_pages/session_page.pyi index f620528..1658528 100644 --- a/DrissionPage/_pages/session_page.pyi +++ b/DrissionPage/_pages/session_page.pyi @@ -241,7 +241,7 @@ class SessionPage(BasePage): def _find_elements(self, locator: Union[Tuple[str, str], str, SessionElement], - timeout: float = None, + timeout: float, index: Optional[int] = 1, relative: bool = True, raise_err: bool = None) -> Union[SessionElement, SessionElementsList]: diff --git a/DrissionPage/_pages/web_page.py b/DrissionPage/_pages/web_page.py index 25eb2a6..d8003fe 100644 --- a/DrissionPage/_pages/web_page.py +++ b/DrissionPage/_pages/web_page.py @@ -237,10 +237,10 @@ class WebPage(SessionPage, ChromiumPage, BasePage): if self._response is not None: self._response.close() - def _find_elements(self, locator, timeout=None, index=1, relative=False, raise_err=None): + def _find_elements(self, locator, timeout, index=1, relative=False, raise_err=None): if self._d_mode: return super(SessionPage, self)._find_elements(locator, timeout=timeout, index=index, relative=relative) - return super()._find_elements(locator, index=index) + return super()._find_elements(locator, index=index, timeout=timeout) def quit(self, timeout=5, force=True, del_data=False): if self._has_session: diff --git a/DrissionPage/_pages/web_page.pyi b/DrissionPage/_pages/web_page.pyi index 2feb3b6..97815c2 100644 --- a/DrissionPage/_pages/web_page.pyi +++ b/DrissionPage/_pages/web_page.pyi @@ -350,7 +350,7 @@ class WebPage(SessionPage, ChromiumPage, BasePage): def _find_elements(self, locator: Union[Tuple[str, str], str, ChromiumElement, SessionElement, ChromiumFrame], - timeout: float = None, + timeout: float, index: Optional[int] = 1, relative: bool = False, raise_err: bool = None) -> Union[ diff --git a/DrissionPage/common.py b/DrissionPage/common.py index d7f8c38..a412f8c 100644 --- a/DrissionPage/common.py +++ b/DrissionPage/common.py @@ -8,7 +8,6 @@ from ._base.chromium import Chromium from ._elements.session_element import make_session_ele from ._functions.by import By -from ._functions.elements import get_eles from ._functions.keys import Keys from ._functions.settings import Settings from ._functions.tools import wait_until, configs_to_here @@ -16,7 +15,7 @@ from ._functions.web import get_blob, tree from ._units.actions import Actions __all__ = ['make_session_ele', 'Actions', 'Keys', 'By', 'Settings', 'wait_until', 'configs_to_here', 'get_blob', - 'tree', 'from_selenium', 'from_playwright', 'get_eles'] + 'tree', 'from_selenium', 'from_playwright'] def from_selenium(driver):