增加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 .._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

View File

@ -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: 多个定位符组成的dictfirst_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: ...

View File

@ -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:

View File

@ -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]:

View File

@ -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',

View File

@ -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):

View File

@ -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]:

View File

@ -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

View File

@ -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: 多个定位符组成的dictfirst_only为False返回列表否则为元素无结果的返回False
"""
...

View File

@ -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 = []

View File

@ -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]:

View File

@ -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()

View File

@ -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]:

View File

@ -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:

View File

@ -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) \

View File

@ -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):

View File

@ -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]:

View File

@ -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:

View File

@ -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[

View File

@ -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):