增加find()方法;元素增加timeout属性;优化NoneElement相关逻辑

This commit is contained in:
g1879 2024-09-06 07:16:44 +08:00
parent ad78edabec
commit f2218cf0d3
20 changed files with 96 additions and 50 deletions

View File

@ -16,7 +16,7 @@ from requests import Session
from .._configs.session_options import SessionOptions from .._configs.session_options import SessionOptions
from .._elements.none_element import NoneElement 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.locator import get_loc
from .._functions.settings import Settings from .._functions.settings import Settings
from .._functions.web import format_html from .._functions.web import format_html
@ -35,6 +35,13 @@ class BaseParser(object):
def eles(self, locator, timeout=None): def eles(self, locator, timeout=None):
return self._ele(locator, timeout, index=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 @property
def html(self): def html(self):
@ -49,7 +56,7 @@ class BaseParser(object):
def _ele(self, locator, timeout=None, index=1, raise_err=None, method=None): def _ele(self, locator, timeout=None, index=1, raise_err=None, method=None):
pass 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 pass
@ -68,16 +75,22 @@ class BaseElement(BaseParser):
def _ele(self, locator, timeout=None, index=1, relative=False, raise_err=None, method=None): def _ele(self, locator, timeout=None, index=1, relative=False, raise_err=None, method=None):
if hasattr(locator, '_type'): if hasattr(locator, '_type'):
return locator return locator
if timeout is None:
timeout = self.timeout
r = self._find_elements(locator, timeout=timeout, index=index, relative=relative, raise_err=raise_err) r = self._find_elements(locator, timeout=timeout, index=index, relative=relative, raise_err=raise_err)
if r or isinstance(r, list): if r or isinstance(r, list):
return r return r
if Settings.raise_when_ele_not_found or raise_err is True: 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.method = method
r.args = {'locator': locator, 'index': index} r.args = {'locator': locator, 'index': index, 'timeout': timeout}
return r return r
@property
def timeout(self):
return self.owner.timeout
# ----------------以下属性或方法由后代实现---------------- # ----------------以下属性或方法由后代实现----------------
@property @property
def tag(self): def tag(self):
@ -235,7 +248,7 @@ class DrissionElement(BaseElement):
def _get_ele_path(self, mode): def _get_ele_path(self, mode):
return '' 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 pass
@ -327,14 +340,15 @@ class BasePage(BaseParser):
def _ele(self, locator, timeout=None, index=1, raise_err=None, method=None): def _ele(self, locator, timeout=None, index=1, raise_err=None, method=None):
if not locator: if not locator:
raise ElementNotFoundError(None, method, {'locator': 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) r = self._find_elements(locator, timeout=timeout, index=index, raise_err=raise_err)
if r or isinstance(r, list): if r or isinstance(r, list):
return r return r
if Settings.raise_when_ele_not_found or raise_err is True: 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.method = method
r.args = {'locator': locator, 'index': index} r.args = {'locator': locator, 'index': index, 'timeout': timeout}
return r return r

View File

@ -6,13 +6,14 @@
@License : BSD 3-Clause. @License : BSD 3-Clause.
""" """
from abc import abstractmethod 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 DownloadKit import DownloadKit
from requests import Session from requests import Session
from requests.structures import CaseInsensitiveDict from requests.structures import CaseInsensitiveDict
from .._configs.session_options import SessionOptions from .._configs.session_options import SessionOptions
from .._elements.chromium_element import ChromiumElement
from .._elements.none_element import NoneElement from .._elements.none_element import NoneElement
from .._elements.session_element import SessionElement from .._elements.session_element import SessionElement
from .._functions.elements import SessionElementsList from .._functions.elements import SessionElementsList
@ -34,6 +35,21 @@ class BaseParser(object):
def eles(self, locator: Union[Tuple[str, str], str], timeout=None): ... 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: 多个定位符组成的dictfirst_only为False返回列表否则为元素无结果的返回False
"""
...
# ----------------以下属性或方法待后代实现---------------- # ----------------以下属性或方法待后代实现----------------
@property @property
def html(self) -> str: ... def html(self) -> str: ...
@ -53,7 +69,7 @@ class BaseParser(object):
def _find_elements(self, def _find_elements(self,
locator: Union[Tuple[str, str], str], locator: Union[Tuple[str, str], str],
timeout: float = None, timeout: float,
index: Optional[int] = 1, index: Optional[int] = 1,
relative: bool = False, relative: bool = False,
raise_err: bool = None): ... raise_err: bool = None): ...
@ -64,6 +80,11 @@ class BaseElement(BaseParser):
def __init__(self, owner: BasePage = None): ... def __init__(self, owner: BasePage = None): ...
@property
def timeout(self) -> float:
"""返回其查找元素时超时时间"""
...
# ----------------以下属性或方法由后代实现---------------- # ----------------以下属性或方法由后代实现----------------
@property @property
def tag(self) -> str: ... def tag(self) -> str: ...

View File

@ -428,7 +428,7 @@ class ChromiumElement(DrissionElement):
return (make_session_ele(self, locator, index=None) return (make_session_ele(self, locator, index=None)
if self.ele(locator, timeout=timeout) else SessionElementsList()) 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) return find_in_chromium_ele(self, locator, index, timeout, relative=relative)
def style(self, style, pseudo_ele=''): def style(self, style, pseudo_ele=''):
@ -851,7 +851,7 @@ class ShadowRoot(BaseElement):
return (make_session_ele(self, locator, index=None) return (make_session_ele(self, locator, index=None)
if self.ele(locator, timeout=timeout) else SessionElementsList()) 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) loc = get_loc(locator, css_mode=False)
if loc[0] == 'css selector' and str(loc[1]).startswith(':root'): if loc[0] == 'css selector' and str(loc[1]).startswith(':root'):
loc = loc[0], loc[1][5:] 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) r = make_chromium_eles(self.owner, _ids=node_ids, index=index, is_obj_id=False)
return None if r is False else r return None if r is False else r
timeout = timeout if timeout is not None else self.owner.timeout
end_time = perf_counter() + timeout end_time = perf_counter() + timeout
result = do_find() result = do_find()
while result is None and perf_counter() <= end_time: while result is None and perf_counter() <= end_time:

View File

@ -466,7 +466,7 @@ class ChromiumElement(DrissionElement):
def _find_elements(self, def _find_elements(self,
locator: Union[Tuple[str, str], str], locator: Union[Tuple[str, str], str],
timeout: float = None, timeout: float,
index: Optional[int] = 1, index: Optional[int] = 1,
relative: bool = False, relative: bool = False,
raise_err: bool = False) -> Union[ChromiumElement, ChromiumFrame, ChromiumElementsList]: raise_err: bool = False) -> Union[ChromiumElement, ChromiumFrame, ChromiumElementsList]:
@ -831,7 +831,7 @@ class ShadowRoot(BaseElement):
def _find_elements(self, def _find_elements(self,
locator: Union[Tuple[str, str], str], locator: Union[Tuple[str, str], str],
timeout: float = None, timeout: float,
index: Optional[int] = 1, index: Optional[int] = 1,
relative: bool = False, relative: bool = False,
raise_err: bool = None) -> Union[ChromiumElement, ChromiumFrame, str, ChromiumElementsList]: raise_err: bool = None) -> Union[ChromiumElement, ChromiumFrame, str, ChromiumElementsList]:

View File

@ -21,7 +21,7 @@ class NoneElement(object):
self._none_ele_value = None self._none_ele_value = None
self._none_ele_return_value = False self._none_ele_return_value = False
self.method = method self.method = method
self.args = args self.args = {} if args is None else args
self._get = None self._get = None
def __call__(self, *args, **kwargs): def __call__(self, *args, **kwargs):
@ -36,8 +36,8 @@ class NoneElement(object):
def __getattr__(self, item): def __getattr__(self, item):
if not self._none_ele_return_value: if not self._none_ele_return_value:
raise ElementNotFoundError(None, self.method, self.args) raise ElementNotFoundError(None, self.method, self.args)
elif item in ('ele', 's_ele', 'parent', 'child', 'next', 'prev', 'before', elif item in ('ele', 's_ele', 'parent', 'child', 'next', 'prev', 'before', 'east', 'north', 'south', 'west',
'after', 'get_frame', 'shadow_root', 'sr'): 'offset', 'over', 'after', 'get_frame', 'shadow_root', 'sr'):
return self return self
else: else:
if item in ('size', 'link', 'css_path', 'xpath', 'comments', 'texts', 'tag', 'html', 'inner_html', if item in ('size', 'link', 'css_path', 'xpath', 'comments', 'texts', 'tag', 'html', 'inner_html',

View File

@ -142,7 +142,7 @@ class SessionElement(DrissionElement):
def s_eles(self, locator): def s_eles(self, locator):
return self._ele(locator, index=None) 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) return make_session_ele(self, locator, index=index)
def _get_ele_path(self, mode): def _get_ele_path(self, mode):

View File

@ -269,7 +269,7 @@ class SessionElement(DrissionElement):
def _find_elements(self, def _find_elements(self,
locator: Union[Tuple[str, str], str], locator: Union[Tuple[str, str], str],
timeout: float = None, timeout: float,
index: Optional[int] = 1, index: Optional[int] = 1,
relative: bool = False, relative: bool = False,
raise_err: bool = None) -> Union[SessionElement, SessionElementsList]: raise_err: bool = None) -> Union[SessionElement, SessionElementsList]:

View File

@ -5,7 +5,7 @@
@Copyright: (c) 2024 by g1879, Inc. All Rights Reserved. @Copyright: (c) 2024 by g1879, Inc. All Rights Reserved.
@License : BSD 3-Clause. @License : BSD 3-Clause.
""" """
from time import perf_counter from time import perf_counter, sleep
from .locator import is_loc from .locator import is_loc
from .._elements.none_element import NoneElement 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): 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 end_time = perf_counter() + timeout
while perf_counter() <= end_time: while perf_counter() <= end_time:
for loc in locators: for loc in locators:
if res[loc] is not False: if res[loc]:
continue continue
ele = owner._ele(loc, timeout=0, raise_err=False, index=1 if first_ele else None) ele = owner._ele(loc, timeout=0, raise_err=False, index=1 if first_ele else None, method='find()')
if ele:
res[loc] = ele res[loc] = ele
if any_one: if ele and any_one:
return res return res
if False not in res.values(): if all(res.values()):
break return res
sleep(.05)
return res return res

View File

@ -5,7 +5,7 @@
@Copyright: (c) 2024 by g1879, Inc. All Rights Reserved. @Copyright: (c) 2024 by g1879, Inc. All Rights Reserved.
@License : BSD 3-Clause. @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 .._base.base import BaseParser
from .._elements.chromium_element import ChromiumElement 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, owner: BaseParser,
any_one: bool = False, any_one: bool = False,
first_ele: bool = True, 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 """传入多个定位符获取多个ele
:param locators: 定位符组成的列表 :param locators: 定位符组成的列表
:param owner: 页面或元素对象 :param owner: 页面或元素对象
:param any_one: 是否找到任何一个即返回 :param any_one: 是否找到任何一个即返回
:param first_ele: 每个定位符是否只获取第一个元素 :param first_ele: 每个定位符是否只获取第一个元素
:param timeout: 超时时间 :param timeout: 超时时间
:return: 多个定位符组成的dict :return: 多个定位符组成的dictfirst_only为False返回列表否则为元素无结果的返回False
""" """
... ...

View File

@ -425,7 +425,8 @@ class ChromiumBase(BasePage):
return self._ele(locator, timeout=timeout, index=None) return self._ele(locator, timeout=timeout, index=None)
def s_ele(self, locator=None, index=1, timeout=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) if locator and not self.wait.eles_loaded(locator, timeout=timeout)
else make_session_ele(self, locator, index=index, method='s_ele()')) 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) return (make_session_ele(self, locator, index=None)
if self.wait.eles_loaded(locator, timeout=timeout) else SessionElementsList()) 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)): if isinstance(locator, (str, tuple)):
loc = get_loc(locator)[1] loc = get_loc(locator)[1]
elif locator._type in ('ChromiumElement', 'ChromiumFrame'): elif locator._type in ('ChromiumElement', 'ChromiumFrame'):
@ -442,7 +443,6 @@ class ChromiumBase(BasePage):
raise ValueError('locator参数只能是tuple、str、ChromiumElement类型。') raise ValueError('locator参数只能是tuple、str、ChromiumElement类型。')
self.wait.doc_loaded() self.wait.doc_loaded()
timeout = timeout if timeout is not None else self.timeout
end_time = perf_counter() + timeout end_time = perf_counter() + timeout
search_ids = [] search_ids = []

View File

@ -423,7 +423,7 @@ class ChromiumBase(BasePage):
def _find_elements(self, def _find_elements(self,
locator: Union[Tuple[str, str], str, ChromiumElement, ChromiumFrame], locator: Union[Tuple[str, str], str, ChromiumElement, ChromiumFrame],
timeout: float = None, timeout: float,
index: Optional[int] = 1, index: Optional[int] = 1,
relative: bool = False, relative: bool = False,
raise_err: bool = None) -> Union[ChromiumElement, ChromiumFrame, ChromiumElementsList]: raise_err: bool = None) -> Union[ChromiumElement, ChromiumFrame, ChromiumElementsList]:

View File

@ -438,7 +438,7 @@ class ChromiumFrame(ChromiumBase):
self.tab.remove_ele(new_ele) self.tab.remove_ele(new_ele)
return r 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): if isinstance(locator, ChromiumElement):
return locator return locator
self.wait.doc_loaded() self.wait.doc_loaded()

View File

@ -426,7 +426,7 @@ class ChromiumFrame(ChromiumBase):
def _find_elements(self, def _find_elements(self,
locator: Union[Tuple[str, str], str, ChromiumElement, ChromiumFrame], locator: Union[Tuple[str, str], str, ChromiumElement, ChromiumFrame],
timeout: float = None, timeout: float,
index: Optional[int] = 1, index: Optional[int] = 1,
relative: bool = False, relative: bool = False,
raise_err: bool = None) -> Union[ChromiumElement, ChromiumFrame, None, ChromiumElementsList]: raise_err: bool = None) -> Union[ChromiumElement, ChromiumFrame, None, ChromiumElementsList]:

View File

@ -182,9 +182,9 @@ class MixTab(SessionPage, ChromiumTab, BasePage):
if self._response is not None: if self._response is not None:
self._response.close() 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) \ 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): def _set_session_options(self, session_or_options=None):
if session_or_options is None: if session_or_options is None:

View File

@ -279,7 +279,7 @@ class MixTab(SessionPage, ChromiumTab):
def _find_elements(self, def _find_elements(self,
locator: Union[Tuple[str, str], str, ChromiumElement, SessionElement, ChromiumFrame], locator: Union[Tuple[str, str], str, ChromiumElement, SessionElement, ChromiumFrame],
timeout: float = None, timeout: float,
index: Optional[int] = 1, index: Optional[int] = 1,
relative: bool = False, relative: bool = False,
raise_err: bool = None) \ raise_err: bool = None) \

View File

@ -146,7 +146,7 @@ class SessionPage(BasePage):
def s_eles(self, locator): def s_eles(self, locator):
return self._ele(locator, index=None) 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) return locator if isinstance(locator, SessionElement) else make_session_ele(self, locator, index=index)
def cookies(self, all_domains=False, all_info=False): def cookies(self, all_domains=False, all_info=False):

View File

@ -241,7 +241,7 @@ class SessionPage(BasePage):
def _find_elements(self, def _find_elements(self,
locator: Union[Tuple[str, str], str, SessionElement], locator: Union[Tuple[str, str], str, SessionElement],
timeout: float = None, timeout: float,
index: Optional[int] = 1, index: Optional[int] = 1,
relative: bool = True, relative: bool = True,
raise_err: bool = None) -> Union[SessionElement, SessionElementsList]: raise_err: bool = None) -> Union[SessionElement, SessionElementsList]:

View File

@ -237,10 +237,10 @@ class WebPage(SessionPage, ChromiumPage, BasePage):
if self._response is not None: if self._response is not None:
self._response.close() 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: if self._d_mode:
return super(SessionPage, self)._find_elements(locator, timeout=timeout, index=index, relative=relative) 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): def quit(self, timeout=5, force=True, del_data=False):
if self._has_session: if self._has_session:

View File

@ -350,7 +350,7 @@ class WebPage(SessionPage, ChromiumPage, BasePage):
def _find_elements(self, def _find_elements(self,
locator: Union[Tuple[str, str], str, ChromiumElement, SessionElement, ChromiumFrame], locator: Union[Tuple[str, str], str, ChromiumElement, SessionElement, ChromiumFrame],
timeout: float = None, timeout: float,
index: Optional[int] = 1, index: Optional[int] = 1,
relative: bool = False, relative: bool = False,
raise_err: bool = None) -> Union[ raise_err: bool = None) -> Union[

View File

@ -8,7 +8,6 @@
from ._base.chromium import Chromium from ._base.chromium import Chromium
from ._elements.session_element import make_session_ele from ._elements.session_element import make_session_ele
from ._functions.by import By from ._functions.by import By
from ._functions.elements import get_eles
from ._functions.keys import Keys from ._functions.keys import Keys
from ._functions.settings import Settings from ._functions.settings import Settings
from ._functions.tools import wait_until, configs_to_here 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 from ._units.actions import Actions
__all__ = ['make_session_ele', 'Actions', 'Keys', 'By', 'Settings', 'wait_until', 'configs_to_here', 'get_blob', __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): def from_selenium(driver):