From 609b8b06dfaa820567bb0a793d8cdfdf557eef24 Mon Sep 17 00:00:00 2001 From: g1879 Date: Mon, 20 Feb 2023 17:11:46 +0800 Subject: [PATCH] =?UTF-8?q?=E6=89=BE=E4=B8=8D=E5=88=B0=E5=85=83=E7=B4=A0?= =?UTF-8?q?=E6=97=B6=E5=8F=AF=E6=8A=9B=E5=87=BA=E5=BC=82=E5=B8=B8=EF=BC=8C?= =?UTF-8?q?=E5=BE=85=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DrissionPage/base.py | 69 ++++++++++++++++++++++++++----- DrissionPage/base.pyi | 26 ++++++++---- DrissionPage/chromium_base.py | 12 +++--- DrissionPage/chromium_base.pyi | 4 +- DrissionPage/chromium_element.py | 51 ++++++++++++++++------- DrissionPage/chromium_element.pyi | 11 ++--- DrissionPage/chromium_frame.py | 24 ++++------- DrissionPage/chromium_frame.pyi | 5 +-- DrissionPage/common/constants.py | 4 ++ DrissionPage/easy_set.py | 9 ++++ DrissionPage/easy_set.pyi | 3 ++ DrissionPage/session_element.py | 3 +- DrissionPage/session_element.pyi | 9 ++-- DrissionPage/session_page.py | 8 ++-- DrissionPage/session_page.pyi | 7 ++-- DrissionPage/web_page.py | 8 ++-- DrissionPage/web_page.pyi | 5 +-- 17 files changed, 172 insertions(+), 86 deletions(-) diff --git a/DrissionPage/base.py b/DrissionPage/base.py index c67bdb4..c77fccf 100644 --- a/DrissionPage/base.py +++ b/DrissionPage/base.py @@ -7,6 +7,8 @@ from abc import abstractmethod from re import sub from urllib.parse import quote +from .common.constants import Settings, NoneElement +from .common.errors import ElementNotFoundError from .common.web import format_html from .common.locator import get_loc @@ -34,8 +36,11 @@ class BaseParser(object): def s_eles(self, loc_or_str): pass + def _ele(self, loc_or_ele, timeout=None, single=True, raise_err=None): + pass + @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 @@ -50,10 +55,6 @@ class BaseElement(BaseParser): def tag(self): return - @abstractmethod - def _ele(self, loc_or_str, timeout=None, single=True, relative=False): - pass - def parent(self, level_or_loc=1): pass @@ -69,6 +70,18 @@ class BaseElement(BaseParser): def nexts(self): 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): """DriverElement、ChromiumElement 和 SessionElement的基类 @@ -125,7 +138,7 @@ class DrissionElement(BaseElement): else: 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): """返回前面的一个兄弟元素,可用查询语法筛选,可指定返回筛选结果的第几个 @@ -135,7 +148,12 @@ class DrissionElement(BaseElement): :return: 兄弟元素 """ 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): """返回后面的一个兄弟元素,可用查询语法筛选,可指定返回筛选结果的第几个 @@ -145,7 +163,12 @@ class DrissionElement(BaseElement): :return: 兄弟元素 """ 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): """返回前面的一个兄弟元素,可用查询语法筛选,可指定返回筛选结果的第几个 @@ -155,7 +178,12 @@ class DrissionElement(BaseElement): :return: 本元素前面的某个元素或节点 """ 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): """返回后面的一个兄弟元素,可用查询语法筛选,可指定返回筛选结果的第几个 @@ -165,7 +193,12 @@ class DrissionElement(BaseElement): :return: 本元素后面的某个元素或节点 """ 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): """返回前面全部兄弟元素或节点组成的列表,可用查询语法筛选 @@ -271,7 +304,7 @@ class BasePage(BaseParser): @property def title(self): """返回网页title""" - ele = self.ele('xpath://title') + ele = self._ele('xpath://title', raise_err=False) return ele.text if ele else None @property @@ -322,3 +355,17 @@ class BasePage(BaseParser): @abstractmethod def get(self, url, show_errmsg=False, retry=None, interval=None): 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 diff --git a/DrissionPage/base.pyi b/DrissionPage/base.pyi index 1f12e80..17533c5 100644 --- a/DrissionPage/base.pyi +++ b/DrissionPage/base.pyi @@ -6,6 +6,8 @@ from abc import abstractmethod from typing import Union, Tuple, List +from .common.constants import NoneElement + class BaseParser(object): @@ -23,8 +25,10 @@ class BaseParser(object): 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 - 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): @@ -36,9 +40,12 @@ class BaseElement(BaseParser): @property def tag(self) -> str: ... - @abstractmethod 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): ... @@ -76,22 +83,22 @@ class DrissionElement(BaseElement): def prev(self, index: int = 1, filter_loc: Union[tuple, str] = '', - timeout: float = 0) -> Union[DrissionElement, str, None]: ... + timeout: float = 0) -> Union[DrissionElement, str, NoneElement]: ... def next(self, index: int = 1, filter_loc: Union[tuple, str] = '', - timeout: float = 0) -> Union[DrissionElement, str, None]: ... + timeout: float = 0) -> Union[DrissionElement, str, NoneElement]: ... def before(self, index: int = 1, filter_loc: Union[tuple, str] = '', - timeout: float = None) -> Union[DrissionElement, str, None]: ... + timeout: float = None) -> Union[DrissionElement, str, NoneElement]: ... def after(self, index: int = 1, filter_loc: Union[tuple, str] = '', - timeout: float = None) -> Union[DrissionElement, str, None]: ... + timeout: float = None) -> Union[DrissionElement, str, NoneElement]: ... def prevs(self, filter_loc: Union[tuple, str] = '', @@ -173,3 +180,8 @@ class BasePage(BaseParser): show_errmsg: bool = False, retry: int = 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): ... diff --git a/DrissionPage/chromium_base.py b/DrissionPage/chromium_base.py index 24df257..f9e7d2c 100644 --- a/DrissionPage/chromium_base.py +++ b/DrissionPage/chromium_base.py @@ -16,7 +16,7 @@ from .chromium_element import ChromiumWaiter, ChromiumScroll, ChromiumElement, r ChromiumElementWaiter from .common.constants import HANDLE_ALERT_METHOD, ERROR, NoneElement from .common.errors import ContextLossError, ElementLossError, AlertExistsError, CallMethodError, TabClosedError, \ - NoRectError, ElementNotFoundError + NoRectError from .common.locator import get_loc from .common.tools import get_usable_path from .common.web import cookies_to_tuple @@ -452,19 +452,19 @@ class ChromiumBase(BasePage): """ 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 timeout: 查找超时时间 :param single: 是否只返回第一个 + :param relative: WebPage用的表示是否相对定位的参数 + :param raise_err: 找不到元素是是否抛出异常,为None时根据全局设置 :return: ChromiumElement对象或元素对象组成的列表 """ if isinstance(loc_or_ele, (str, tuple)): loc = get_loc(loc_or_ele)[1] elif isinstance(loc_or_ele, ChromiumElement) or str(type(loc_or_ele)).endswith(".ChromiumFrame'>"): return loc_or_ele - elif not loc_or_ele: - raise ElementNotFoundError else: raise ValueError('loc_or_str参数只能是tuple、str、ChromiumElement类型。') @@ -568,7 +568,7 @@ class ChromiumBase(BasePage): """ if not loc_or_ele: return - ele = self._ele(loc_or_ele) + ele = self._ele(loc_or_ele, raise_err=False) if ele: self.run_cdp('DOM.removeNode', nodeId=ele.ids.node_id) @@ -938,7 +938,7 @@ class ChromiumPageScroll(ChromiumScroll): :return: 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"});') x, y = ele.location try: diff --git a/DrissionPage/chromium_base.pyi b/DrissionPage/chromium_base.pyi index 974285a..44cb06a 100644 --- a/DrissionPage/chromium_base.pyi +++ b/DrissionPage/chromium_base.pyi @@ -149,9 +149,9 @@ class ChromiumBase(BasePage): 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], - 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]]]: ... def refresh(self, ignore_cache: bool = False) -> None: ... diff --git a/DrissionPage/chromium_element.py b/DrissionPage/chromium_element.py index d90761c..aa3a3cd 100644 --- a/DrissionPage/chromium_element.py +++ b/DrissionPage/chromium_element.py @@ -10,8 +10,8 @@ from time import perf_counter, sleep from warnings import warn from .base import DrissionElement, BaseElement -from .common.constants import FRAME_ELEMENT, NoneElement -from .common.errors import ContextLossError, ElementLossError, JavaScriptError, NoRectError +from .common.constants import FRAME_ELEMENT, NoneElement, Settings +from .common.errors import ContextLossError, ElementLossError, JavaScriptError, NoRectError, ElementNotFoundError from .common.keys import keys_to_typing, keyDescriptionForString, keyDefinitions 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 @@ -375,11 +375,13 @@ class ChromiumElement(DrissionElement): return make_session_ele(self.inner_html, 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 timeout: 查找元素超时时间 :param single: True则返回第一个,False则返回全部 + :param relative: WebPage用的表示是否相对定位的参数 + :param raise_err: 找不到元素是是否抛出异常,为None时根据全局设置 :return: ChromiumElement对象或文本、属性或其组成的列表 """ return find_in_chromium_ele(self, loc_or_str, single, timeout, relative=relative) @@ -901,7 +903,7 @@ class ChromiumShadowRootElement(BaseElement): else: 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): """返回后面的一个兄弟元素,可用查询语法筛选,可指定返回筛选结果的第几个 @@ -910,7 +912,12 @@ class ChromiumShadowRootElement(BaseElement): :return: ChromiumElement对象 """ 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): """返回前面的一个兄弟元素,可用查询语法筛选,可指定返回筛选结果的第几个 @@ -919,7 +926,12 @@ class ChromiumShadowRootElement(BaseElement): :return: 本元素前面的某个元素或节点 """ 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): """返回后面的一个兄弟元素,可用查询语法筛选,可指定返回筛选结果的第几个 @@ -928,7 +940,12 @@ class ChromiumShadowRootElement(BaseElement): :return: 本元素后面的某个元素或节点 """ 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=''): """返回后面所有兄弟元素或节点组成的列表 @@ -941,7 +958,7 @@ class ChromiumShadowRootElement(BaseElement): loc = loc[1].lstrip('./') 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=''): """返回后面全部兄弟元素或节点组成的列表,可用查询语法筛选 @@ -954,7 +971,7 @@ class ChromiumShadowRootElement(BaseElement): loc = loc[1].lstrip('./') 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=''): """返回前面全部兄弟元素或节点组成的列表,可用查询语法筛选 @@ -964,7 +981,7 @@ class ChromiumShadowRootElement(BaseElement): eles1 = self.nexts(filter_loc) loc = get_loc(filter_loc, True)[1].lstrip('./') 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): """返回当前元素下级符合条件的第一个元素 @@ -996,11 +1013,13 @@ class ChromiumShadowRootElement(BaseElement): """ 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 timeout: 查找元素超时时间 :param single: True则返回第一个,False则返回全部 + :param relative: WebPage用的表示是否相对定位的参数 + :param raise_err: 找不到元素是是否抛出异常,为None时根据全局设置 :return: ChromiumElement对象或其组成的列表 """ loc = get_loc(loc_or_str) @@ -1914,11 +1933,11 @@ class ChromiumSelect(object): def do_select(): 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': - 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': - 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: raise ValueError('para_type参数只能传入"text"、"value"或"index"。') @@ -2031,7 +2050,7 @@ class ChromiumElementWaiter(object): if not self.loc_or_ele.states.is_alive: 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: return True @@ -2055,7 +2074,7 @@ class ChromiumElementWaiter(object): :param mode: 等待模式 :return: 是否等待成功 """ - target = self.driver(self.loc_or_ele) + target = self.driver._ele(self.loc_or_ele, raise_err=False) if not target: return None diff --git a/DrissionPage/chromium_element.pyi b/DrissionPage/chromium_element.pyi index 4e6723a..b2eb340 100644 --- a/DrissionPage/chromium_element.pyi +++ b/DrissionPage/chromium_element.pyi @@ -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 _ele(self, - loc_or_str: Union[Tuple[str, str], str], - timeout: float = None, single: bool = True, relative: bool = False) \ + def _find_elements(self, loc_or_str: Union[Tuple[str, str], str], timeout: float = None, + single: bool = True, relative: bool = False, raise_err: bool = False) \ -> Union[ChromiumElement, ChromiumFrame, str, NoneElement, 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 _ele(self, - loc_or_str: Union[Tuple[str, str], str], - timeout: float = None, - single: bool = True, relative: bool = False) \ + def _find_elements(self, loc_or_str: Union[Tuple[str, str], str], timeout: float = None, + single: bool = True, relative: bool = False, raise_err: bool = None) \ -> Union[ ChromiumElement, ChromiumFrame, NoneElement, str, List[Union[ChromiumElement, ChromiumFrame, str]]]: ... diff --git a/DrissionPage/chromium_frame.py b/DrissionPage/chromium_frame.py index a3e7fdc..6adff46 100644 --- a/DrissionPage/chromium_frame.py +++ b/DrissionPage/chromium_frame.py @@ -9,7 +9,6 @@ from warnings import warn from .chromium_base import ChromiumBase, ChromiumPageScroll, ChromiumBaseSetter from .chromium_element import ChromiumElement -from .common.errors import ElementNotFoundError class ChromiumFrame(ChromiumBase): @@ -180,7 +179,8 @@ class ChromiumFrame(ChromiumBase): def title(self): """返回页面title""" 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 def cookies(self): @@ -406,21 +406,21 @@ class ChromiumFrame(ChromiumBase): else: 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内查找单个元素 :param loc_or_ele: 定位符或元素对象 :param timeout: 查找超时时间 + :param single: True则返回第一个,False则返回全部 + :param relative: WebPage用的表示是否相对定位的参数 + :param raise_err: 找不到元素是是否抛出异常,为None时根据全局设置 :return: ChromiumElement对象 """ - if not loc_or_ele: - raise ElementNotFoundError - if isinstance(loc_or_ele, ChromiumElement): return loc_or_ele 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): """尝试连接,重试若干次 @@ -559,14 +559,8 @@ class ChromiumFrameScroll(ChromiumPageScroll): :param loc_or_ele: 元素的定位信息,可以是loc元组,或查询字符串 :return: None """ - ele = loc_or_ele if isinstance(loc_or_ele, ChromiumElement) else self._driver.ele(loc_or_ele) - try: - 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) + ele = loc_or_ele if isinstance(loc_or_ele, ChromiumElement) else self._driver._ele(loc_or_ele) + ele.run_js('this.scrollIntoView({behavior: "auto", block: "center", inline: "center"});') class ChromiumFrameSetter(ChromiumBaseSetter): diff --git a/DrissionPage/chromium_frame.pyi b/DrissionPage/chromium_frame.pyi index ba3d181..7d8037d 100644 --- a/DrissionPage/chromium_frame.pyi +++ b/DrissionPage/chromium_frame.pyi @@ -150,9 +150,8 @@ class ChromiumFrame(ChromiumBase): filter_loc: Union[tuple, str] = ..., timeout: float = ...) -> List[Union[ChromiumElement, ChromiumFrame, str]]: ... - def _ele(self, - loc_or_ele: Union[Tuple[str, str], str, ChromiumElement, ChromiumFrame], - timeout: float = None, single: bool = True, relative: bool = False) \ + def _find_elements(self, loc_or_ele: Union[Tuple[str, str], str, ChromiumElement, ChromiumFrame], + timeout: float = None, single: bool = True, relative: bool = False, raise_err: bool=None) \ -> Union[ChromiumElement, ChromiumFrame, None, List[Union[ChromiumElement, ChromiumFrame]]]: ... def _d_connect(self, diff --git a/DrissionPage/common/constants.py b/DrissionPage/common/constants.py index 250322e..e906d25 100644 --- a/DrissionPage/common/constants.py +++ b/DrissionPage/common/constants.py @@ -6,6 +6,10 @@ FRAME_ELEMENT = ('iframe', 'frame') ERROR = 'error' +class Settings(object): + raise_ele_not_found = False + + class NoneElement(object): _instance = None diff --git a/DrissionPage/easy_set.py b/DrissionPage/easy_set.py index b96dd22..a84ee1e 100644 --- a/DrissionPage/easy_set.py +++ b/DrissionPage/easy_set.py @@ -11,6 +11,7 @@ from typing import Union from selenium import webdriver from DrissionPage.mixpage.drission import Drission +from .common.constants import Settings from .common.tools import unzip from .configs.chromium_options import ChromiumOptions from .configs.driver_options import DriverOptions @@ -18,6 +19,14 @@ from .configs.options_manage import OptionsManager 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): """把默认ini文件复制到当前目录 :param save_name: 指定文件名,为None则命名为'dp_configs.ini' diff --git a/DrissionPage/easy_set.pyi b/DrissionPage/easy_set.pyi index 2ab8abe..fad8e17 100644 --- a/DrissionPage/easy_set.pyi +++ b/DrissionPage/easy_set.pyi @@ -7,6 +7,9 @@ from pathlib import Path 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: ... diff --git a/DrissionPage/session_element.py b/DrissionPage/session_element.py index a524207..5b46b23 100644 --- a/DrissionPage/session_element.py +++ b/DrissionPage/session_element.py @@ -213,12 +213,13 @@ class SessionElement(DrissionElement): """ 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 timeout: 不起实际作用,用于和父类对应 :param single: True则返回第一个,False则返回全部 :param relative: WebPage用的表示是否相对定位的参数 + :param raise_err: 找不到元素是是否抛出异常,为None时根据全局设置 :return: SessionElement对象 """ return make_session_ele(self, loc_or_str, single) diff --git a/DrissionPage/session_element.pyi b/DrissionPage/session_element.pyi index a844d03..311d09f 100644 --- a/DrissionPage/session_element.pyi +++ b/DrissionPage/session_element.pyi @@ -104,11 +104,13 @@ class SessionElement(DrissionElement): 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, 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: ... @@ -116,4 +118,5 @@ class SessionElement(DrissionElement): def make_session_ele(html_or_ele: Union[str, SessionElement, SessionPage, ChromiumElement, DriverElement, BaseElement, ChromiumFrame, ChromiumBase, DriverPage], 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]]]: ... diff --git a/DrissionPage/session_page.py b/DrissionPage/session_page.py index 0e14723..aa702b5 100644 --- a/DrissionPage/session_page.py +++ b/DrissionPage/session_page.py @@ -14,7 +14,6 @@ from requests.structures import CaseInsensitiveDict from tldextract import extract from .base import BasePage -from .common.errors import ElementNotFoundError from .common.web import cookie_to_dict, set_session_cookies from .configs.session_options import SessionOptions from .session_element import SessionElement, make_session_ele @@ -96,7 +95,7 @@ class SessionPage(BasePage): @property def title(self): """返回网页title""" - ele = self.ele('xpath://title') + ele = self._ele('xpath://title', raise_err=False) return ele.text if ele else None @property @@ -193,15 +192,14 @@ class SessionPage(BasePage): """ 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 timeout: 不起实际作用,用于和父类对应 :param single: True则返回第一个,False则返回全部 + :param raise_err: 找不到元素是是否抛出异常,为None时根据全局设置 :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) def get_cookies(self, as_dict=False, all_domains=False): diff --git a/DrissionPage/session_page.pyi b/DrissionPage/session_page.pyi index 916c628..ebd0dd2 100644 --- a/DrissionPage/session_page.pyi +++ b/DrissionPage/session_page.pyi @@ -102,10 +102,9 @@ class SessionPage(BasePage): def s_eles(self, loc_or_str: Union[Tuple[str, str], str]) -> List[Union[SessionElement, str]]: ... - def _ele(self, - loc_or_ele: Union[Tuple[str, str], str, SessionElement], - timeout: float = None, - single: bool = True) -> Union[SessionElement, str, NoneElement, List[Union[SessionElement, str]]]: ... + def _find_elements(self, loc_or_ele: Union[Tuple[str, str], str, SessionElement], + timeout: float = None, single: bool = True, raise_err: bool =None)\ + -> Union[SessionElement, str, NoneElement, List[Union[SessionElement, str]]]: ... def get_cookies(self, as_dict: bool = False, diff --git a/DrissionPage/web_page.py b/DrissionPage/web_page.py index c5e56a4..6ad966b 100644 --- a/DrissionPage/web_page.py +++ b/DrissionPage/web_page.py @@ -413,17 +413,19 @@ class WebPage(SessionPage, ChromiumPage, BasePage): self._response = 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 timeout: 查找元素超时时间,d模式专用 :param single: True则返回第一个,False则返回全部 + :param relative: WebPage用的表示是否相对定位的参数 + :param raise_err: 找不到元素是是否抛出异常,为None时根据全局设置 :return: 元素对象或属性、文本节点文本 """ 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': - 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): """关闭浏览器,关闭session""" diff --git a/DrissionPage/web_page.pyi b/DrissionPage/web_page.pyi index bbbc136..5924383 100644 --- a/DrissionPage/web_page.pyi +++ b/DrissionPage/web_page.pyi @@ -155,9 +155,8 @@ class WebPage(SessionPage, ChromiumPage, BasePage): @property def set(self) -> WebPageSetter: ... - def _ele(self, - loc_or_ele: Union[Tuple[str, str], str, ChromiumElement, SessionElement, ChromiumFrame], - timeout: float = None, single: bool = True, relative: bool = False) \ + def _find_elements(self, loc_or_ele: Union[Tuple[str, str], str, ChromiumElement, SessionElement, ChromiumFrame], + timeout: float = None, single: bool = True, relative: bool = False, raise_err: bool =None) \ -> Union[ChromiumElement, SessionElement, ChromiumFrame, str, None, List[Union[SessionElement, str]], List[ Union[ChromiumElement, str, ChromiumFrame]]]: ...