找不到元素时可抛出异常,待测试

This commit is contained in:
g1879 2023-02-20 17:11:46 +08:00
parent 4354f21583
commit 609b8b06df
17 changed files with 172 additions and 86 deletions

View File

@ -7,6 +7,8 @@ from abc import abstractmethod
from re import sub from re import sub
from urllib.parse import quote from urllib.parse import quote
from .common.constants import Settings, NoneElement
from .common.errors import ElementNotFoundError
from .common.web import format_html from .common.web import format_html
from .common.locator import get_loc from .common.locator import get_loc
@ -34,8 +36,11 @@ class BaseParser(object):
def s_eles(self, loc_or_str): def s_eles(self, loc_or_str):
pass pass
def _ele(self, loc_or_ele, timeout=None, single=True, raise_err=None):
pass
@abstractmethod @abstractmethod
def _ele(self, loc_or_ele, timeout=None, single=True): def _find_elements(self, loc_or_ele, timeout=None, single=True, raise_err=None):
pass pass
@ -50,10 +55,6 @@ class BaseElement(BaseParser):
def tag(self): def tag(self):
return return
@abstractmethod
def _ele(self, loc_or_str, timeout=None, single=True, relative=False):
pass
def parent(self, level_or_loc=1): def parent(self, level_or_loc=1):
pass pass
@ -69,6 +70,18 @@ class BaseElement(BaseParser):
def nexts(self): def nexts(self):
pass pass
def _ele(self, loc_or_str, timeout=None, single=True, relative=False, raise_err=None):
r = self._find_elements(loc_or_str, timeout=timeout, single=single, relative=relative, raise_err=raise_err)
if not single or raise_err is False:
return r
if not r and (Settings.raise_ele_not_found or raise_err is True):
raise ElementNotFoundError
return r
@abstractmethod
def _find_elements(self, loc_or_str, timeout=None, single=True, relative=False, raise_err=None):
pass
class DrissionElement(BaseElement): class DrissionElement(BaseElement):
"""DriverElement、ChromiumElement 和 SessionElement的基类 """DriverElement、ChromiumElement 和 SessionElement的基类
@ -125,7 +138,7 @@ class DrissionElement(BaseElement):
else: else:
raise TypeError('level_or_loc参数只能是tuple、int或str。') raise TypeError('level_or_loc参数只能是tuple、int或str。')
return self._ele(loc, timeout=0, relative=True) return self._ele(loc, timeout=0, relative=True, raise_err=False)
def prev(self, index=1, filter_loc='', timeout=0): def prev(self, index=1, filter_loc='', timeout=0):
"""返回前面的一个兄弟元素,可用查询语法筛选,可指定返回筛选结果的第几个 """返回前面的一个兄弟元素,可用查询语法筛选,可指定返回筛选结果的第几个
@ -135,7 +148,12 @@ class DrissionElement(BaseElement):
:return: 兄弟元素 :return: 兄弟元素
""" """
nodes = self._get_brothers(index, filter_loc, 'preceding', timeout=timeout) nodes = self._get_brothers(index, filter_loc, 'preceding', timeout=timeout)
return nodes[-1] if nodes else None if nodes:
return nodes[-1]
if Settings.raise_ele_not_found:
raise ElementNotFoundError
else:
return NoneElement()
def next(self, index=1, filter_loc='', timeout=0): def next(self, index=1, filter_loc='', timeout=0):
"""返回后面的一个兄弟元素,可用查询语法筛选,可指定返回筛选结果的第几个 """返回后面的一个兄弟元素,可用查询语法筛选,可指定返回筛选结果的第几个
@ -145,7 +163,12 @@ class DrissionElement(BaseElement):
:return: 兄弟元素 :return: 兄弟元素
""" """
nodes = self._get_brothers(index, filter_loc, 'following', timeout=timeout) nodes = self._get_brothers(index, filter_loc, 'following', timeout=timeout)
return nodes[0] if nodes else None if nodes:
return nodes[0]
if Settings.raise_ele_not_found:
raise ElementNotFoundError
else:
return NoneElement()
def before(self, index=1, filter_loc='', timeout=None): def before(self, index=1, filter_loc='', timeout=None):
"""返回前面的一个兄弟元素,可用查询语法筛选,可指定返回筛选结果的第几个 """返回前面的一个兄弟元素,可用查询语法筛选,可指定返回筛选结果的第几个
@ -155,7 +178,12 @@ class DrissionElement(BaseElement):
:return: 本元素前面的某个元素或节点 :return: 本元素前面的某个元素或节点
""" """
nodes = self._get_brothers(index, filter_loc, 'preceding', False, timeout=timeout) nodes = self._get_brothers(index, filter_loc, 'preceding', False, timeout=timeout)
return nodes[-1] if nodes else None if nodes:
return nodes[-1]
if Settings.raise_ele_not_found:
raise ElementNotFoundError
else:
return NoneElement()
def after(self, index=1, filter_loc='', timeout=None): def after(self, index=1, filter_loc='', timeout=None):
"""返回后面的一个兄弟元素,可用查询语法筛选,可指定返回筛选结果的第几个 """返回后面的一个兄弟元素,可用查询语法筛选,可指定返回筛选结果的第几个
@ -165,7 +193,12 @@ class DrissionElement(BaseElement):
:return: 本元素后面的某个元素或节点 :return: 本元素后面的某个元素或节点
""" """
nodes = self._get_brothers(index, filter_loc, 'following', False, timeout) nodes = self._get_brothers(index, filter_loc, 'following', False, timeout)
return nodes[0] if nodes else None if nodes:
return nodes[0]
if Settings.raise_ele_not_found:
raise ElementNotFoundError
else:
return NoneElement()
def prevs(self, filter_loc='', timeout=0): def prevs(self, filter_loc='', timeout=0):
"""返回前面全部兄弟元素或节点组成的列表,可用查询语法筛选 """返回前面全部兄弟元素或节点组成的列表,可用查询语法筛选
@ -271,7 +304,7 @@ class BasePage(BaseParser):
@property @property
def title(self): def title(self):
"""返回网页title""" """返回网页title"""
ele = self.ele('xpath://title') ele = self._ele('xpath://title', raise_err=False)
return ele.text if ele else None return ele.text if ele else None
@property @property
@ -322,3 +355,17 @@ class BasePage(BaseParser):
@abstractmethod @abstractmethod
def get(self, url, show_errmsg=False, retry=None, interval=None): def get(self, url, show_errmsg=False, retry=None, interval=None):
pass pass
def _ele(self, loc_or_ele, timeout=None, single=True, raise_err=None):
if not loc_or_ele:
raise ElementNotFoundError
r = self._find_elements(loc_or_ele, timeout=timeout, single=single, raise_err=raise_err)
if not single or raise_err is False:
return r
if not r and (Settings().raise_ele_not_found is True or raise_err is True):
raise ElementNotFoundError
return r
@abstractmethod
def _find_elements(self, loc_or_ele, timeout=None, single=True, raise_err=None):
pass

View File

@ -6,6 +6,8 @@
from abc import abstractmethod from abc import abstractmethod
from typing import Union, Tuple, List from typing import Union, Tuple, List
from .common.constants import NoneElement
class BaseParser(object): class BaseParser(object):
@ -23,8 +25,10 @@ class BaseParser(object):
def s_eles(self, loc_or_str: Union[Tuple[str, str], str]): ... def s_eles(self, loc_or_str: Union[Tuple[str, str], str]): ...
def _ele(self, loc_or_ele, timeout: float = None, single: bool = True, raise_err: bool = None): ...
@abstractmethod @abstractmethod
def _ele(self, loc_or_ele, timeout: float = None, single: bool = True): ... def _find_elements(self, loc_or_ele, timeout: float = None, single: bool = True, raise_err: bool = None): ...
class BaseElement(BaseParser): class BaseElement(BaseParser):
@ -36,9 +40,12 @@ class BaseElement(BaseParser):
@property @property
def tag(self) -> str: ... def tag(self) -> str: ...
@abstractmethod
def _ele(self, loc_or_str: Union[Tuple[str, str], str], timeout: float = None, single: bool = True, def _ele(self, loc_or_str: Union[Tuple[str, str], str], timeout: float = None, single: bool = True,
relative: bool = False): ... relative: bool = False, raise_err: bool = None): ...
@abstractmethod
def _find_elements(self, loc_or_str, timeout: float = None, single: bool = True, relative: bool = False,
raise_err: bool = None): ...
def parent(self, level_or_loc: Union[tuple, str, int] = 1): ... def parent(self, level_or_loc: Union[tuple, str, int] = 1): ...
@ -76,22 +83,22 @@ class DrissionElement(BaseElement):
def prev(self, def prev(self,
index: int = 1, index: int = 1,
filter_loc: Union[tuple, str] = '', filter_loc: Union[tuple, str] = '',
timeout: float = 0) -> Union[DrissionElement, str, None]: ... timeout: float = 0) -> Union[DrissionElement, str, NoneElement]: ...
def next(self, def next(self,
index: int = 1, index: int = 1,
filter_loc: Union[tuple, str] = '', filter_loc: Union[tuple, str] = '',
timeout: float = 0) -> Union[DrissionElement, str, None]: ... timeout: float = 0) -> Union[DrissionElement, str, NoneElement]: ...
def before(self, def before(self,
index: int = 1, index: int = 1,
filter_loc: Union[tuple, str] = '', filter_loc: Union[tuple, str] = '',
timeout: float = None) -> Union[DrissionElement, str, None]: ... timeout: float = None) -> Union[DrissionElement, str, NoneElement]: ...
def after(self, def after(self,
index: int = 1, index: int = 1,
filter_loc: Union[tuple, str] = '', filter_loc: Union[tuple, str] = '',
timeout: float = None) -> Union[DrissionElement, str, None]: ... timeout: float = None) -> Union[DrissionElement, str, NoneElement]: ...
def prevs(self, def prevs(self,
filter_loc: Union[tuple, str] = '', filter_loc: Union[tuple, str] = '',
@ -173,3 +180,8 @@ class BasePage(BaseParser):
show_errmsg: bool = False, show_errmsg: bool = False,
retry: int = None, retry: int = None,
interval: float = None): ... interval: float = None): ...
def _ele(self, loc_or_ele, timeout: float = None, single: bool = True, raise_err: bool = None): ...
@abstractmethod
def _find_elements(self, loc_or_ele, timeout: float = None, single: bool = True, raise_err: bool = None): ...

View File

@ -16,7 +16,7 @@ from .chromium_element import ChromiumWaiter, ChromiumScroll, ChromiumElement, r
ChromiumElementWaiter ChromiumElementWaiter
from .common.constants import HANDLE_ALERT_METHOD, ERROR, NoneElement from .common.constants import HANDLE_ALERT_METHOD, ERROR, NoneElement
from .common.errors import ContextLossError, ElementLossError, AlertExistsError, CallMethodError, TabClosedError, \ from .common.errors import ContextLossError, ElementLossError, AlertExistsError, CallMethodError, TabClosedError, \
NoRectError, ElementNotFoundError NoRectError
from .common.locator import get_loc from .common.locator import get_loc
from .common.tools import get_usable_path from .common.tools import get_usable_path
from .common.web import cookies_to_tuple from .common.web import cookies_to_tuple
@ -452,19 +452,19 @@ class ChromiumBase(BasePage):
""" """
return make_session_ele(self, loc_or_str, single=False) return make_session_ele(self, loc_or_str, single=False)
def _ele(self, loc_or_ele, timeout=None, single=True, relative=False): def _find_elements(self, loc_or_ele, timeout=None, single=True, relative=False, raise_err=None):
"""执行元素查找 """执行元素查找
:param loc_or_ele: 定位符或元素对象 :param loc_or_ele: 定位符或元素对象
:param timeout: 查找超时时间 :param timeout: 查找超时时间
:param single: 是否只返回第一个 :param single: 是否只返回第一个
:param relative: WebPage用的表示是否相对定位的参数
:param raise_err: 找不到元素是是否抛出异常为None时根据全局设置
:return: ChromiumElement对象或元素对象组成的列表 :return: ChromiumElement对象或元素对象组成的列表
""" """
if isinstance(loc_or_ele, (str, tuple)): if isinstance(loc_or_ele, (str, tuple)):
loc = get_loc(loc_or_ele)[1] loc = get_loc(loc_or_ele)[1]
elif isinstance(loc_or_ele, ChromiumElement) or str(type(loc_or_ele)).endswith(".ChromiumFrame'>"): elif isinstance(loc_or_ele, ChromiumElement) or str(type(loc_or_ele)).endswith(".ChromiumFrame'>"):
return loc_or_ele return loc_or_ele
elif not loc_or_ele:
raise ElementNotFoundError
else: else:
raise ValueError('loc_or_str参数只能是tuple、str、ChromiumElement类型。') raise ValueError('loc_or_str参数只能是tuple、str、ChromiumElement类型。')
@ -568,7 +568,7 @@ class ChromiumBase(BasePage):
""" """
if not loc_or_ele: if not loc_or_ele:
return return
ele = self._ele(loc_or_ele) ele = self._ele(loc_or_ele, raise_err=False)
if ele: if ele:
self.run_cdp('DOM.removeNode', nodeId=ele.ids.node_id) self.run_cdp('DOM.removeNode', nodeId=ele.ids.node_id)
@ -938,7 +938,7 @@ class ChromiumPageScroll(ChromiumScroll):
:return: None :return: None
""" """
ID = None ID = None
ele = self._driver.ele(loc_or_ele) ele = self._driver._ele(loc_or_ele)
ele.run_js('this.scrollIntoView({behavior: "auto", block: "nearest", inline: "nearest"});') ele.run_js('this.scrollIntoView({behavior: "auto", block: "nearest", inline: "nearest"});')
x, y = ele.location x, y = ele.location
try: try:

View File

@ -149,9 +149,9 @@ class ChromiumBase(BasePage):
def s_eles(self, loc_or_str: Union[Tuple[str, str], str]) -> List[Union[SessionElement, str]]: ... def s_eles(self, loc_or_str: Union[Tuple[str, str], str]) -> List[Union[SessionElement, str]]: ...
def _ele(self, def _find_elements(self,
loc_or_ele: Union[Tuple[str, str], str, ChromiumElement, ChromiumFrame], loc_or_ele: Union[Tuple[str, str], str, ChromiumElement, ChromiumFrame],
timeout: float = None, single: bool = True, relative: bool = False) \ timeout: float = None, single: bool = True, relative: bool = False, raise_err:bool=None) \
-> Union[ChromiumElement, ChromiumFrame, NoneElement, List[Union[ChromiumElement, ChromiumFrame]]]: ... -> Union[ChromiumElement, ChromiumFrame, NoneElement, List[Union[ChromiumElement, ChromiumFrame]]]: ...
def refresh(self, ignore_cache: bool = False) -> None: ... def refresh(self, ignore_cache: bool = False) -> None: ...

View File

@ -10,8 +10,8 @@ from time import perf_counter, sleep
from warnings import warn from warnings import warn
from .base import DrissionElement, BaseElement from .base import DrissionElement, BaseElement
from .common.constants import FRAME_ELEMENT, NoneElement from .common.constants import FRAME_ELEMENT, NoneElement, Settings
from .common.errors import ContextLossError, ElementLossError, JavaScriptError, NoRectError from .common.errors import ContextLossError, ElementLossError, JavaScriptError, NoRectError, ElementNotFoundError
from .common.keys import keys_to_typing, keyDescriptionForString, keyDefinitions from .common.keys import keys_to_typing, keyDescriptionForString, keyDefinitions
from .common.locator import get_loc from .common.locator import get_loc
from .common.web import make_absolute_link, get_ele_txt, format_html, is_js_func, location_in_viewport, offset_scroll from .common.web import make_absolute_link, get_ele_txt, format_html, is_js_func, location_in_viewport, offset_scroll
@ -375,11 +375,13 @@ class ChromiumElement(DrissionElement):
return make_session_ele(self.inner_html, loc_or_str, single=False) return make_session_ele(self.inner_html, loc_or_str, single=False)
return make_session_ele(self, loc_or_str, single=False) return make_session_ele(self, loc_or_str, single=False)
def _ele(self, loc_or_str, timeout=None, single=True, relative=False): def _find_elements(self, loc_or_str, timeout=None, single=True, relative=False, raise_err=None):
"""返回当前元素下级符合条件的子元素、属性或节点文本,默认返回第一个 """返回当前元素下级符合条件的子元素、属性或节点文本,默认返回第一个
:param loc_or_str: 元素的定位信息可以是loc元组或查询字符串 :param loc_or_str: 元素的定位信息可以是loc元组或查询字符串
:param timeout: 查找元素超时时间 :param timeout: 查找元素超时时间
:param single: True则返回第一个False则返回全部 :param single: True则返回第一个False则返回全部
:param relative: WebPage用的表示是否相对定位的参数
:param raise_err: 找不到元素是是否抛出异常为None时根据全局设置
:return: ChromiumElement对象或文本属性或其组成的列表 :return: ChromiumElement对象或文本属性或其组成的列表
""" """
return find_in_chromium_ele(self, loc_or_str, single, timeout, relative=relative) return find_in_chromium_ele(self, loc_or_str, single, timeout, relative=relative)
@ -901,7 +903,7 @@ class ChromiumShadowRootElement(BaseElement):
else: else:
raise TypeError('level_or_loc参数只能是tuple、int或str。') raise TypeError('level_or_loc参数只能是tuple、int或str。')
return self.parent_ele._ele(loc, timeout=0, relative=True) return self.parent_ele._ele(loc, timeout=0, relative=True, raise_err=False)
def next(self, filter_loc='', index=1): def next(self, filter_loc='', index=1):
"""返回后面的一个兄弟元素,可用查询语法筛选,可指定返回筛选结果的第几个 """返回后面的一个兄弟元素,可用查询语法筛选,可指定返回筛选结果的第几个
@ -910,7 +912,12 @@ class ChromiumShadowRootElement(BaseElement):
:return: ChromiumElement对象 :return: ChromiumElement对象
""" """
nodes = self.nexts(filter_loc=filter_loc) nodes = self.nexts(filter_loc=filter_loc)
return nodes[index - 1] if nodes else None if nodes:
return nodes[index - 1]
if Settings.raise_ele_not_found:
raise ElementNotFoundError
else:
return NoneElement()
def before(self, filter_loc='', index=1): def before(self, filter_loc='', index=1):
"""返回前面的一个兄弟元素,可用查询语法筛选,可指定返回筛选结果的第几个 """返回前面的一个兄弟元素,可用查询语法筛选,可指定返回筛选结果的第几个
@ -919,7 +926,12 @@ class ChromiumShadowRootElement(BaseElement):
:return: 本元素前面的某个元素或节点 :return: 本元素前面的某个元素或节点
""" """
nodes = self.befores(filter_loc=filter_loc) nodes = self.befores(filter_loc=filter_loc)
return nodes[index - 1] if nodes else None if nodes:
return nodes[index - 1]
if Settings.raise_ele_not_found:
raise ElementNotFoundError
else:
return NoneElement()
def after(self, filter_loc='', index=1): def after(self, filter_loc='', index=1):
"""返回后面的一个兄弟元素,可用查询语法筛选,可指定返回筛选结果的第几个 """返回后面的一个兄弟元素,可用查询语法筛选,可指定返回筛选结果的第几个
@ -928,7 +940,12 @@ class ChromiumShadowRootElement(BaseElement):
:return: 本元素后面的某个元素或节点 :return: 本元素后面的某个元素或节点
""" """
nodes = self.afters(filter_loc=filter_loc) nodes = self.afters(filter_loc=filter_loc)
return nodes[index - 1] if nodes else None if nodes:
return nodes[index - 1]
if Settings.raise_ele_not_found:
raise ElementNotFoundError
else:
return NoneElement()
def nexts(self, filter_loc=''): def nexts(self, filter_loc=''):
"""返回后面所有兄弟元素或节点组成的列表 """返回后面所有兄弟元素或节点组成的列表
@ -941,7 +958,7 @@ class ChromiumShadowRootElement(BaseElement):
loc = loc[1].lstrip('./') loc = loc[1].lstrip('./')
xpath = f'xpath:./{loc}' xpath = f'xpath:./{loc}'
return self.parent_ele._ele(xpath, timeout=0.1, single=False, relative=True) return self.parent_ele._ele(xpath, single=False, relative=True)
def befores(self, filter_loc=''): def befores(self, filter_loc=''):
"""返回后面全部兄弟元素或节点组成的列表,可用查询语法筛选 """返回后面全部兄弟元素或节点组成的列表,可用查询语法筛选
@ -954,7 +971,7 @@ class ChromiumShadowRootElement(BaseElement):
loc = loc[1].lstrip('./') loc = loc[1].lstrip('./')
xpath = f'xpath:./preceding::{loc}' xpath = f'xpath:./preceding::{loc}'
return self.parent_ele._ele(xpath, timeout=0.1, single=False, relative=True) return self.parent_ele._ele(xpath, single=False, relative=True)
def afters(self, filter_loc=''): def afters(self, filter_loc=''):
"""返回前面全部兄弟元素或节点组成的列表,可用查询语法筛选 """返回前面全部兄弟元素或节点组成的列表,可用查询语法筛选
@ -964,7 +981,7 @@ class ChromiumShadowRootElement(BaseElement):
eles1 = self.nexts(filter_loc) eles1 = self.nexts(filter_loc)
loc = get_loc(filter_loc, True)[1].lstrip('./') loc = get_loc(filter_loc, True)[1].lstrip('./')
xpath = f'xpath:./following::{loc}' xpath = f'xpath:./following::{loc}'
return eles1 + self.parent_ele._ele(xpath, timeout=0.1, single=False, relative=True) return eles1 + self.parent_ele._ele(xpath, single=False, relative=True)
def ele(self, loc_or_str, timeout=None): def ele(self, loc_or_str, timeout=None):
"""返回当前元素下级符合条件的第一个元素 """返回当前元素下级符合条件的第一个元素
@ -996,11 +1013,13 @@ class ChromiumShadowRootElement(BaseElement):
""" """
return make_session_ele(self, loc_or_str, single=False) return make_session_ele(self, loc_or_str, single=False)
def _ele(self, loc_or_str, timeout=None, single=True, relative=False): def _find_elements(self, loc_or_str, timeout=None, single=True, relative=False, raise_err=None):
"""返回当前元素下级符合条件的子元素、属性或节点文本,默认返回第一个 """返回当前元素下级符合条件的子元素、属性或节点文本,默认返回第一个
:param loc_or_str: 元素的定位信息可以是loc元组或查询字符串 :param loc_or_str: 元素的定位信息可以是loc元组或查询字符串
:param timeout: 查找元素超时时间 :param timeout: 查找元素超时时间
:param single: True则返回第一个False则返回全部 :param single: True则返回第一个False则返回全部
:param relative: WebPage用的表示是否相对定位的参数
:param raise_err: 找不到元素是是否抛出异常为None时根据全局设置
:return: ChromiumElement对象或其组成的列表 :return: ChromiumElement对象或其组成的列表
""" """
loc = get_loc(loc_or_str) loc = get_loc(loc_or_str)
@ -1914,11 +1933,11 @@ class ChromiumSelect(object):
def do_select(): def do_select():
if para_type == 'text': if para_type == 'text':
ele = self._ele(f'tx={text_value_index}', timeout=0) ele = self._ele._ele(f'tx={text_value_index}', timeout=0, raise_err=False)
elif para_type == 'value': elif para_type == 'value':
ele = self._ele(f'@value={text_value_index}', timeout=0) ele = self._ele._ele(f'@value={text_value_index}', timeout=0, raise_err=False)
elif para_type == 'index': elif para_type == 'index':
ele = self._ele(f'x:.//option[{int(text_value_index)}]', timeout=0) ele = self._ele._ele(f'x:.//option[{int(text_value_index)}]', timeout=0, raise_err=False)
else: else:
raise ValueError('para_type参数只能传入"text""value""index"') raise ValueError('para_type参数只能传入"text""value""index"')
@ -2031,7 +2050,7 @@ class ChromiumElementWaiter(object):
if not self.loc_or_ele.states.is_alive: if not self.loc_or_ele.states.is_alive:
return True return True
ele = self.driver(self.loc_or_ele, timeout=.5) ele = self.driver._ele(self.loc_or_ele, timeout=.5, raise_err=False)
if not ele: if not ele:
return True return True
@ -2055,7 +2074,7 @@ class ChromiumElementWaiter(object):
:param mode: 等待模式 :param mode: 等待模式
:return: 是否等待成功 :return: 是否等待成功
""" """
target = self.driver(self.loc_or_ele) target = self.driver._ele(self.loc_or_ele, raise_err=False)
if not target: if not target:
return None return None

View File

@ -160,9 +160,8 @@ class ChromiumElement(DrissionElement):
def s_eles(self, loc_or_str: Union[Tuple[str, str], str] = None) -> List[Union[SessionElement, str]]: ... def s_eles(self, loc_or_str: Union[Tuple[str, str], str] = None) -> List[Union[SessionElement, str]]: ...
def _ele(self, def _find_elements(self, loc_or_str: Union[Tuple[str, str], str], timeout: float = None,
loc_or_str: Union[Tuple[str, str], str], single: bool = True, relative: bool = False, raise_err: bool = False) \
timeout: float = None, single: bool = True, relative: bool = False) \
-> Union[ChromiumElement, ChromiumFrame, str, NoneElement, -> Union[ChromiumElement, ChromiumFrame, str, NoneElement,
List[Union[ChromiumElement, ChromiumFrame, str]]]: ... List[Union[ChromiumElement, ChromiumFrame, str]]]: ...
@ -289,10 +288,8 @@ class ChromiumShadowRootElement(BaseElement):
def s_eles(self, loc_or_str: Union[Tuple[str, str], str]) -> List[Union[SessionElement, str]]: ... def s_eles(self, loc_or_str: Union[Tuple[str, str], str]) -> List[Union[SessionElement, str]]: ...
def _ele(self, def _find_elements(self, loc_or_str: Union[Tuple[str, str], str], timeout: float = None,
loc_or_str: Union[Tuple[str, str], str], single: bool = True, relative: bool = False, raise_err: bool = None) \
timeout: float = None,
single: bool = True, relative: bool = False) \
-> Union[ -> Union[
ChromiumElement, ChromiumFrame, NoneElement, str, List[Union[ChromiumElement, ChromiumFrame, str]]]: ... ChromiumElement, ChromiumFrame, NoneElement, str, List[Union[ChromiumElement, ChromiumFrame, str]]]: ...

View File

@ -9,7 +9,6 @@ from warnings import warn
from .chromium_base import ChromiumBase, ChromiumPageScroll, ChromiumBaseSetter from .chromium_base import ChromiumBase, ChromiumPageScroll, ChromiumBaseSetter
from .chromium_element import ChromiumElement from .chromium_element import ChromiumElement
from .common.errors import ElementNotFoundError
class ChromiumFrame(ChromiumBase): class ChromiumFrame(ChromiumBase):
@ -180,7 +179,8 @@ class ChromiumFrame(ChromiumBase):
def title(self): def title(self):
"""返回页面title""" """返回页面title"""
self._check_ok() self._check_ok()
return self.ele('t:title').text r = self._ele('t:title', raise_err=False)
return r.text if r else None
@property @property
def cookies(self): def cookies(self):
@ -406,21 +406,21 @@ class ChromiumFrame(ChromiumBase):
else: else:
raise RuntimeError('暂未实现对异域iframe内元素截图功能。') raise RuntimeError('暂未实现对异域iframe内元素截图功能。')
def _ele(self, loc_or_ele, timeout=None, single=True, relative=False): def _find_elements(self, loc_or_ele, timeout=None, single=True, relative=False, raise_err=None):
"""在frame内查找单个元素 """在frame内查找单个元素
:param loc_or_ele: 定位符或元素对象 :param loc_or_ele: 定位符或元素对象
:param timeout: 查找超时时间 :param timeout: 查找超时时间
:param single: True则返回第一个False则返回全部
:param relative: WebPage用的表示是否相对定位的参数
:param raise_err: 找不到元素是是否抛出异常为None时根据全局设置
:return: ChromiumElement对象 :return: ChromiumElement对象
""" """
if not loc_or_ele:
raise ElementNotFoundError
if isinstance(loc_or_ele, ChromiumElement): if isinstance(loc_or_ele, ChromiumElement):
return loc_or_ele return loc_or_ele
self.wait.load_complete() self.wait.load_complete()
return self.doc_ele.ele(loc_or_ele, timeout) if single else self.doc_ele.eles(loc_or_ele, timeout) return self.doc_ele._ele(loc_or_ele, timeout, raise_err=raise_err) if single else self.doc_ele.eles(loc_or_ele, timeout)
def _d_connect(self, to_url, times=0, interval=1, show_errmsg=False, timeout=None): def _d_connect(self, to_url, times=0, interval=1, show_errmsg=False, timeout=None):
"""尝试连接,重试若干次 """尝试连接,重试若干次
@ -559,14 +559,8 @@ class ChromiumFrameScroll(ChromiumPageScroll):
:param loc_or_ele: 元素的定位信息可以是loc元组或查询字符串 :param loc_or_ele: 元素的定位信息可以是loc元组或查询字符串
:return: None :return: None
""" """
ele = loc_or_ele if isinstance(loc_or_ele, ChromiumElement) else self._driver.ele(loc_or_ele) ele = loc_or_ele if isinstance(loc_or_ele, ChromiumElement) else self._driver._ele(loc_or_ele)
try: ele.run_js('this.scrollIntoView({behavior: "auto", block: "center", inline: "center"});')
self._driver.page.run_cdp('DOM.scrollIntoViewIfNeeded', nodeId=ele.ids.node_id)
except Exception:
ele.run_js("this.scrollIntoView();")
# if not ele.is_in_viewport:
# offset_scroll(ele, 0, 0)
class ChromiumFrameSetter(ChromiumBaseSetter): class ChromiumFrameSetter(ChromiumBaseSetter):

View File

@ -150,9 +150,8 @@ class ChromiumFrame(ChromiumBase):
filter_loc: Union[tuple, str] = ..., filter_loc: Union[tuple, str] = ...,
timeout: float = ...) -> List[Union[ChromiumElement, ChromiumFrame, str]]: ... timeout: float = ...) -> List[Union[ChromiumElement, ChromiumFrame, str]]: ...
def _ele(self, def _find_elements(self, loc_or_ele: Union[Tuple[str, str], str, ChromiumElement, ChromiumFrame],
loc_or_ele: Union[Tuple[str, str], str, ChromiumElement, ChromiumFrame], timeout: float = None, single: bool = True, relative: bool = False, raise_err: bool=None) \
timeout: float = None, single: bool = True, relative: bool = False) \
-> Union[ChromiumElement, ChromiumFrame, None, List[Union[ChromiumElement, ChromiumFrame]]]: ... -> Union[ChromiumElement, ChromiumFrame, None, List[Union[ChromiumElement, ChromiumFrame]]]: ...
def _d_connect(self, def _d_connect(self,

View File

@ -6,6 +6,10 @@ FRAME_ELEMENT = ('iframe', 'frame')
ERROR = 'error' ERROR = 'error'
class Settings(object):
raise_ele_not_found = False
class NoneElement(object): class NoneElement(object):
_instance = None _instance = None

View File

@ -11,6 +11,7 @@ from typing import Union
from selenium import webdriver from selenium import webdriver
from DrissionPage.mixpage.drission import Drission from DrissionPage.mixpage.drission import Drission
from .common.constants import Settings
from .common.tools import unzip from .common.tools import unzip
from .configs.chromium_options import ChromiumOptions from .configs.chromium_options import ChromiumOptions
from .configs.driver_options import DriverOptions from .configs.driver_options import DriverOptions
@ -18,6 +19,14 @@ from .configs.options_manage import OptionsManager
from .session_page import SessionPage from .session_page import SessionPage
def raise_when_ele_not_found(on_off=True):
"""设置全局变量,找不到元素时是否抛出异常
:param on_off: True False
:return: None
"""
Settings.raise_ele_not_found = on_off
def configs_to_here(save_name=None): def configs_to_here(save_name=None):
"""把默认ini文件复制到当前目录 """把默认ini文件复制到当前目录
:param save_name: 指定文件名为None则命名为'dp_configs.ini' :param save_name: 指定文件名为None则命名为'dp_configs.ini'

View File

@ -7,6 +7,9 @@ from pathlib import Path
from typing import Union from typing import Union
def raise_when_ele_not_found(on_off: bool = True) -> None: ...
def configs_to_here(file_name: Union[Path, str] = None) -> None: ... def configs_to_here(file_name: Union[Path, str] = None) -> None: ...

View File

@ -213,12 +213,13 @@ class SessionElement(DrissionElement):
""" """
return self._ele(loc_or_str, single=False) return self._ele(loc_or_str, single=False)
def _ele(self, loc_or_str, timeout=None, single=True, relative=False): def _find_elements(self, loc_or_str, timeout=None, single=True, relative=False, raise_err=None):
"""返回当前元素下级符合条件的子元素、属性或节点文本,默认返回第一个 """返回当前元素下级符合条件的子元素、属性或节点文本,默认返回第一个
:param loc_or_str: 元素的定位信息可以是loc元组或查询字符串 :param loc_or_str: 元素的定位信息可以是loc元组或查询字符串
:param timeout: 不起实际作用用于和父类对应 :param timeout: 不起实际作用用于和父类对应
:param single: True则返回第一个False则返回全部 :param single: True则返回第一个False则返回全部
:param relative: WebPage用的表示是否相对定位的参数 :param relative: WebPage用的表示是否相对定位的参数
:param raise_err: 找不到元素是是否抛出异常为None时根据全局设置
:return: SessionElement对象 :return: SessionElement对象
""" """
return make_session_ele(self, loc_or_str, single) return make_session_ele(self, loc_or_str, single)

View File

@ -104,11 +104,13 @@ class SessionElement(DrissionElement):
def s_eles(self, def s_eles(self,
loc_or_str: Union[Tuple[str, str], str]) -> List[Union['SessionElement', str]]: ... loc_or_str: Union[Tuple[str, str], str]) -> List[Union['SessionElement', str]]: ...
def _ele(self, def _find_elements(self,
loc_or_str: Union[Tuple[str, str], str], loc_or_str: Union[Tuple[str, str], str],
timeout: float = None, timeout: float = None,
single: bool = True, single: bool = True,
relative: bool = False) -> Union['SessionElement', str, NoneElement, List[Union['SessionElement', str]]]: ... relative: bool = False,
raise_err: bool = None) \
-> Union['SessionElement', str, NoneElement, List[Union['SessionElement', str]]]: ...
def _get_ele_path(self, mode: str) -> str: ... def _get_ele_path(self, mode: str) -> str: ...
@ -116,4 +118,5 @@ class SessionElement(DrissionElement):
def make_session_ele(html_or_ele: Union[str, SessionElement, SessionPage, ChromiumElement, DriverElement, BaseElement, def make_session_ele(html_or_ele: Union[str, SessionElement, SessionPage, ChromiumElement, DriverElement, BaseElement,
ChromiumFrame, ChromiumBase, DriverPage], ChromiumFrame, ChromiumBase, DriverPage],
loc: Union[str, Tuple[str, str]] = None, loc: Union[str, Tuple[str, str]] = None,
single: bool = True) -> Union[SessionElement, str, NoneElement, List[Union[SessionElement, str]]]: ... single: bool = True) -> Union[
SessionElement, str, NoneElement, List[Union[SessionElement, str]]]: ...

View File

@ -14,7 +14,6 @@ from requests.structures import CaseInsensitiveDict
from tldextract import extract from tldextract import extract
from .base import BasePage from .base import BasePage
from .common.errors import ElementNotFoundError
from .common.web import cookie_to_dict, set_session_cookies from .common.web import cookie_to_dict, set_session_cookies
from .configs.session_options import SessionOptions from .configs.session_options import SessionOptions
from .session_element import SessionElement, make_session_ele from .session_element import SessionElement, make_session_ele
@ -96,7 +95,7 @@ class SessionPage(BasePage):
@property @property
def title(self): def title(self):
"""返回网页title""" """返回网页title"""
ele = self.ele('xpath://title') ele = self._ele('xpath://title', raise_err=False)
return ele.text if ele else None return ele.text if ele else None
@property @property
@ -193,15 +192,14 @@ class SessionPage(BasePage):
""" """
return self._ele(loc_or_str, single=False) return self._ele(loc_or_str, single=False)
def _ele(self, loc_or_ele, timeout=None, single=True): def _find_elements(self, loc_or_ele, timeout=None, single=True, raise_err=None):
"""返回页面中符合条件的元素、属性或节点文本,默认返回第一个 """返回页面中符合条件的元素、属性或节点文本,默认返回第一个
:param loc_or_ele: 元素的定位信息可以是元素对象loc元组或查询字符串 :param loc_or_ele: 元素的定位信息可以是元素对象loc元组或查询字符串
:param timeout: 不起实际作用用于和父类对应 :param timeout: 不起实际作用用于和父类对应
:param single: True则返回第一个False则返回全部 :param single: True则返回第一个False则返回全部
:param raise_err: 找不到元素是是否抛出异常为None时根据全局设置
:return: SessionElement对象 :return: SessionElement对象
""" """
if not loc_or_ele:
raise ElementNotFoundError
return loc_or_ele if isinstance(loc_or_ele, SessionElement) else make_session_ele(self, loc_or_ele, single) return loc_or_ele if isinstance(loc_or_ele, SessionElement) else make_session_ele(self, loc_or_ele, single)
def get_cookies(self, as_dict=False, all_domains=False): def get_cookies(self, as_dict=False, all_domains=False):

View File

@ -102,10 +102,9 @@ class SessionPage(BasePage):
def s_eles(self, loc_or_str: Union[Tuple[str, str], str]) -> List[Union[SessionElement, str]]: ... def s_eles(self, loc_or_str: Union[Tuple[str, str], str]) -> List[Union[SessionElement, str]]: ...
def _ele(self, def _find_elements(self, loc_or_ele: Union[Tuple[str, str], str, SessionElement],
loc_or_ele: Union[Tuple[str, str], str, SessionElement], timeout: float = None, single: bool = True, raise_err: bool =None)\
timeout: float = None, -> Union[SessionElement, str, NoneElement, List[Union[SessionElement, str]]]: ...
single: bool = True) -> Union[SessionElement, str, NoneElement, List[Union[SessionElement, str]]]: ...
def get_cookies(self, def get_cookies(self,
as_dict: bool = False, as_dict: bool = False,

View File

@ -413,17 +413,19 @@ class WebPage(SessionPage, ChromiumPage, BasePage):
self._response = None self._response = None
self._has_session = None self._has_session = None
def _ele(self, loc_or_ele, timeout=None, single=True, relative=False): def _find_elements(self, loc_or_ele, timeout=None, single=True, relative=False, raise_err=None):
"""返回页面中符合条件的元素、属性或节点文本,默认返回第一个 """返回页面中符合条件的元素、属性或节点文本,默认返回第一个
:param loc_or_ele: 元素的定位信息可以是元素对象loc元组或查询字符串 :param loc_or_ele: 元素的定位信息可以是元素对象loc元组或查询字符串
:param timeout: 查找元素超时时间d模式专用 :param timeout: 查找元素超时时间d模式专用
:param single: True则返回第一个False则返回全部 :param single: True则返回第一个False则返回全部
:param relative: WebPage用的表示是否相对定位的参数
:param raise_err: 找不到元素是是否抛出异常为None时根据全局设置
:return: 元素对象或属性文本节点文本 :return: 元素对象或属性文本节点文本
""" """
if self._mode == 's': if self._mode == 's':
return super()._ele(loc_or_ele, single=single) return super()._find_elements(loc_or_ele, single=single)
elif self._mode == 'd': elif self._mode == 'd':
return super(SessionPage, self)._ele(loc_or_ele, timeout=timeout, single=single, relative=relative) return super(SessionPage, self)._find_elements(loc_or_ele, timeout=timeout, single=single, relative=relative)
def quit(self): def quit(self):
"""关闭浏览器关闭session""" """关闭浏览器关闭session"""

View File

@ -155,9 +155,8 @@ class WebPage(SessionPage, ChromiumPage, BasePage):
@property @property
def set(self) -> WebPageSetter: ... def set(self) -> WebPageSetter: ...
def _ele(self, def _find_elements(self, loc_or_ele: Union[Tuple[str, str], str, ChromiumElement, SessionElement, ChromiumFrame],
loc_or_ele: Union[Tuple[str, str], str, ChromiumElement, SessionElement, ChromiumFrame], timeout: float = None, single: bool = True, relative: bool = False, raise_err: bool =None) \
timeout: float = None, single: bool = True, relative: bool = False) \
-> Union[ChromiumElement, SessionElement, ChromiumFrame, str, None, List[Union[SessionElement, str]], List[ -> Union[ChromiumElement, SessionElement, ChromiumFrame, str, None, List[Union[SessionElement, str]], List[
Union[ChromiumElement, str, ChromiumFrame]]]: ... Union[ChromiumElement, str, ChromiumFrame]]]: ...