diff --git a/DrissionPage/_base/base.py b/DrissionPage/_base/base.py index eea2c3e..993699e 100644 --- a/DrissionPage/_base/base.py +++ b/DrissionPage/_base/base.py @@ -10,9 +10,10 @@ from urllib.parse import quote from DownloadKit import DownloadKit -from .._commons.constants import Settings, NoneElement +from .._commons.constants import Settings from .._commons.locator import get_loc from .._commons.web import format_html +from .._elements.none_element import NoneElement from ..errors import ElementNotFoundError @@ -23,7 +24,7 @@ class BaseParser(object): return self.ele(loc_or_str) def ele(self, loc_or_ele, timeout=None): - return self._ele(loc_or_ele, timeout, True) + return self._ele(loc_or_ele, timeout, True, method='ele()') def eles(self, loc_or_str, timeout=None): return self._ele(loc_or_str, timeout, False) @@ -39,7 +40,7 @@ class BaseParser(object): def s_eles(self, loc_or_str): pass - def _ele(self, loc_or_ele, timeout=None, single=True, raise_err=None): + def _ele(self, loc_or_ele, timeout=None, single=True, raise_err=None, method=None): pass @abstractmethod @@ -67,12 +68,16 @@ class BaseElement(BaseParser): def nexts(self): pass - def _ele(self, loc_or_str, timeout=None, single=True, relative=False, raise_err=None): + def _ele(self, loc_or_str, timeout=None, single=True, relative=False, raise_err=None, method=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: + if not single: return r - if not r and (Settings.raise_when_ele_not_found or raise_err is True): - raise ElementNotFoundError + if isinstance(r, NoneElement): + if Settings.raise_when_ele_not_found or raise_err is True: + raise ElementNotFoundError(None, method, {'loc_or_str': loc_or_str}) + else: + r.method = method + r.args = {'loc_or_str': loc_or_str} return r @abstractmethod @@ -136,7 +141,7 @@ class DrissionElement(BaseElement): else: raise TypeError('level_or_loc参数只能是tuple、int或str。') - return self._ele(loc, timeout=0, relative=True, raise_err=False) + return self._ele(loc, timeout=0, relative=True, raise_err=False, method='parent()') def child(self, filter_loc='', index=1, timeout=None, ele_only=True): """返回直接子元素元素或节点组成的列表,可用查询语法筛选 @@ -152,17 +157,19 @@ class DrissionElement(BaseElement): nodes = self.children(filter_loc=filter_loc, timeout=timeout, ele_only=ele_only) if not nodes: if Settings.raise_when_ele_not_found: - raise ElementNotFoundError + raise ElementNotFoundError(None, 'child()', + {'filter_loc': filter_loc, 'index': index, 'ele_only': ele_only}) else: - return NoneElement() + return NoneElement('child()', {'filter_loc': filter_loc, 'index': index, 'ele_only': ele_only}) try: return nodes[index - 1] except IndexError: if Settings.raise_when_ele_not_found: - raise ElementNotFoundError + raise ElementNotFoundError(None, 'child()', + {'filter_loc': filter_loc, 'index': index, 'ele_only': ele_only}) else: - return NoneElement() + return NoneElement('child()', {'filter_loc': filter_loc, 'index': index, 'ele_only': ele_only}) def prev(self, filter_loc='', index=1, timeout=0, ele_only=True): """返回前面的一个兄弟元素,可用查询语法筛选,可指定返回筛选结果的第几个 @@ -179,9 +186,10 @@ class DrissionElement(BaseElement): if nodes: return nodes[-1] if Settings.raise_when_ele_not_found: - raise ElementNotFoundError + raise ElementNotFoundError(None, 'prev()', + {'filter_loc': filter_loc, 'index': index, 'ele_only': ele_only}) else: - return NoneElement() + return NoneElement('prev()', {'filter_loc': filter_loc, 'index': index, 'ele_only': ele_only}) def next(self, filter_loc='', index=1, timeout=0, ele_only=True): """返回后面的一个兄弟元素,可用查询语法筛选,可指定返回筛选结果的第几个 @@ -198,9 +206,10 @@ class DrissionElement(BaseElement): if nodes: return nodes[0] if Settings.raise_when_ele_not_found: - raise ElementNotFoundError + raise ElementNotFoundError(None, 'next()', + {'filter_loc': filter_loc, 'index': index, 'ele_only': ele_only}) else: - return NoneElement() + return NoneElement('next()', {'filter_loc': filter_loc, 'index': index, 'ele_only': ele_only}) def before(self, filter_loc='', index=1, timeout=None, ele_only=True): """返回前面的一个兄弟元素,可用查询语法筛选,可指定返回筛选结果的第几个 @@ -217,9 +226,10 @@ class DrissionElement(BaseElement): if nodes: return nodes[-1] if Settings.raise_when_ele_not_found: - raise ElementNotFoundError + raise ElementNotFoundError(None, 'before()', + {'filter_loc': filter_loc, 'index': index, 'ele_only': ele_only}) else: - return NoneElement() + return NoneElement('before()', {'filter_loc': filter_loc, 'index': index, 'ele_only': ele_only}) def after(self, filter_loc='', index=1, timeout=None, ele_only=True): """返回后面的一个兄弟元素,可用查询语法筛选,可指定返回筛选结果的第几个 @@ -236,9 +246,10 @@ class DrissionElement(BaseElement): if nodes: return nodes[0] if Settings.raise_when_ele_not_found: - raise ElementNotFoundError + raise ElementNotFoundError(None, 'after()', + {'filter_loc': filter_loc, 'index': index, 'ele_only': ele_only}) else: - return NoneElement() + return NoneElement('after()', {'filter_loc': filter_loc, 'index': index, 'ele_only': ele_only}) def children(self, filter_loc='', timeout=None, ele_only=True): """返回直接子元素元素或节点组成的列表,可用查询语法筛选 @@ -372,7 +383,7 @@ class BasePage(BaseParser): @property def title(self): """返回网页title""" - ele = self._ele('xpath://title', raise_err=False) + ele = self._ele('xpath://title', raise_err=False, method='title') return ele.text if ele else None @property @@ -430,7 +441,7 @@ class BasePage(BaseParser): @property def user_agent(self): - pass + return @abstractmethod def get_cookies(self, as_dict=False, all_info=False): @@ -440,16 +451,20 @@ class BasePage(BaseParser): 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): + def _ele(self, loc_or_ele, timeout=None, single=True, raise_err=None, method=None): if not loc_or_ele: - raise ElementNotFoundError + raise ElementNotFoundError(None, method, {'loc_or_str': loc_or_ele}) r = self._find_elements(loc_or_ele, timeout=timeout, single=single, raise_err=raise_err) - if not single or raise_err is False: + if not single: return r - if not r and (Settings.raise_when_ele_not_found is True or raise_err is True): - raise ElementNotFoundError + if isinstance(r, NoneElement): + if Settings.raise_when_ele_not_found or raise_err is True: + raise ElementNotFoundError(None, method, {'loc_or_str': loc_or_ele}) + else: + r.method = method + r.args = {'loc_or_str': loc_or_ele} return r @abstractmethod diff --git a/DrissionPage/_base/base.pyi b/DrissionPage/_base/base.pyi index 2b9228c..20b793e 100644 --- a/DrissionPage/_base/base.pyi +++ b/DrissionPage/_base/base.pyi @@ -8,7 +8,7 @@ from typing import Union, Tuple, List from DownloadKit import DownloadKit -from .._commons.constants import NoneElement +from .._elements.none_element import NoneElement class BaseParser(object): @@ -27,7 +27,8 @@ 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): ... + def _ele(self, loc_or_ele, timeout: float = None, single: bool = True, + raise_err: bool = None, method: str = None): ... @abstractmethod def _find_elements(self, loc_or_ele, timeout: float = None, single: bool = True, raise_err: bool = None): ... @@ -43,7 +44,7 @@ class BaseElement(BaseParser): def tag(self) -> str: ... def _ele(self, loc_or_str: Union[Tuple[str, str], str], timeout: float = None, single: bool = True, - relative: bool = False, raise_err: bool = None): ... + relative: bool = False, raise_err: bool = None, method: str = None): ... @abstractmethod def _find_elements(self, loc_or_str, timeout: float = None, single: bool = True, relative: bool = False, @@ -208,7 +209,8 @@ class BasePage(BaseParser): retry: int = None, interval: float = None): ... - def _ele(self, loc_or_ele, timeout: float = None, single: bool = True, raise_err: bool = None): ... + def _ele(self, loc_or_ele, timeout: float = None, single: bool = True, + raise_err: bool = None, method: str = None): ... @abstractmethod def _find_elements(self, loc_or_ele, timeout: float = None, single: bool = True, raise_err: bool = None): ... diff --git a/DrissionPage/_commons/constants.py b/DrissionPage/_commons/constants.py index a1c8054..4208282 100644 --- a/DrissionPage/_commons/constants.py +++ b/DrissionPage/_commons/constants.py @@ -3,8 +3,6 @@ @Author : g1879 @Contact : g1879@qq.com """ -from ..errors import ElementNotFoundError - FRAME_ELEMENT = ('iframe', 'frame') ERROR = 'error' @@ -13,28 +11,4 @@ class Settings(object): raise_when_ele_not_found = False raise_when_click_failed = False raise_when_wait_failed = False - - -class NoneElement(object): - _instance = None - - def __new__(cls): - if not cls._instance: - cls._instance = super(NoneElement, cls).__new__(cls) - return cls._instance - - def __call__(self, *args, **kwargs): - raise ElementNotFoundError - - def __getattr__(self, item): - raise ElementNotFoundError - - def __eq__(self, other): - if other is None: - return True - - def __bool__(self): - return False - - def __repr__(self): - return 'None' + NoneElement_value = None diff --git a/DrissionPage/_commons/locator.py b/DrissionPage/_commons/locator.py index 3e9662b..393559b 100644 --- a/DrissionPage/_commons/locator.py +++ b/DrissionPage/_commons/locator.py @@ -7,6 +7,12 @@ from re import split from .by import By +def is_loc(text): + """返回text是否定位符""" + return text.startswith(('.', '#', '@', 't:', 't=', 'tag:', 'tag=', 'tx:', 'tx=', 'tx^', 'tx$', 'text:', 'text=', + 'text^', 'text$', 'xpath:', 'xpath=', 'x:', 'x=', 'css:', 'css=', 'c:', 'c=')) + + def get_loc(loc, translate_css=False): """接收本库定位语法或selenium定位元组,转换为标准定位元组,可翻译css selector为xpath :param loc: 本库定位语法或selenium定位元组 diff --git a/DrissionPage/_commons/locator.pyi b/DrissionPage/_commons/locator.pyi index 1038890..ec6a426 100644 --- a/DrissionPage/_commons/locator.pyi +++ b/DrissionPage/_commons/locator.pyi @@ -6,6 +6,9 @@ from typing import Union +def is_loc(text:str) -> bool: ... + + def get_loc(loc: Union[tuple, str], translate_css: bool = False) -> tuple: ... diff --git a/DrissionPage/_elements/chromium_element.py b/DrissionPage/_elements/chromium_element.py index e70bb8d..3e1bc4e 100644 --- a/DrissionPage/_elements/chromium_element.py +++ b/DrissionPage/_elements/chromium_element.py @@ -7,9 +7,10 @@ from os.path import basename, sep from pathlib import Path from time import perf_counter, sleep +from .none_element import NoneElement from .session_element import make_session_ele from .._base.base import DrissionElement, BaseElement -from .._commons.constants import FRAME_ELEMENT, NoneElement, Settings +from .._commons.constants import FRAME_ELEMENT, Settings from .._commons.keys import keys_to_typing, keyDescriptionForString, keyDefinitions from .._commons.locator import get_loc from .._commons.tools import get_usable_path @@ -386,7 +387,7 @@ class ChromiumElement(DrissionElement): :param timeout: 查找元素超时时间,默认与元素所在页面等待时间一致 :return: ChromiumElement对象或属性、文本 """ - return self._ele(loc_or_str, timeout) + return self._ele(loc_or_str, timeout, method='ele()') def eles(self, loc_or_str, timeout=None): """返回当前元素下级所有符合条件的子元素、属性或节点文本 @@ -402,8 +403,16 @@ class ChromiumElement(DrissionElement): :return: SessionElement对象或属性、文本 """ if self.tag in FRAME_ELEMENT: - return make_session_ele(self.inner_html, loc_or_str) - return make_session_ele(self, loc_or_str) + r = make_session_ele(self.inner_html, loc_or_str) + else: + r = make_session_ele(self, loc_or_str) + if isinstance(r, NoneElement): + if Settings.raise_when_ele_not_found: + raise ElementNotFoundError(None, 's_ele()', {'loc_or_str': loc_or_str}) + else: + r.method = 's_ele()' + r.args = {'loc_or_str': loc_or_str} + return r def s_eles(self, loc_or_str=None): """查找所有符合条件的元素,以SessionElement列表形式返回 @@ -847,7 +856,7 @@ class ChromiumShadowRoot(BaseElement): else: raise TypeError('level_or_loc参数只能是tuple、int或str。') - return self.parent_ele._ele(loc, timeout=0, relative=True, raise_err=False) + return self.parent_ele._ele(loc, timeout=0, relative=True, raise_err=False, method='parent()') def child(self, filter_loc='', index=1): """返回直接子元素元素或节点组成的列表,可用查询语法筛选 @@ -858,17 +867,17 @@ class ChromiumShadowRoot(BaseElement): nodes = self.children(filter_loc=filter_loc) if not nodes: if Settings.raise_when_ele_not_found: - raise ElementNotFoundError + raise ElementNotFoundError(None, 'child()', {'filter_loc': filter_loc, 'index': index}) else: - return NoneElement() + return NoneElement('child()', {'filter_loc': filter_loc, 'index': index}) try: return nodes[index - 1] except IndexError: if Settings.raise_when_ele_not_found: - raise ElementNotFoundError + raise ElementNotFoundError(None, 'child()', {'filter_loc': filter_loc, 'index': index}) else: - return NoneElement() + return NoneElement('child()', {'filter_loc': filter_loc, 'index': index}) def next(self, filter_loc='', index=1): """返回当前元素后面一个符合条件的同级元素,可用查询语法筛选,可指定返回筛选结果的第几个 @@ -880,9 +889,9 @@ class ChromiumShadowRoot(BaseElement): if nodes: return nodes[index - 1] if Settings.raise_when_ele_not_found: - raise ElementNotFoundError + raise ElementNotFoundError(None, 'next()', {'filter_loc': filter_loc, 'index': index}) else: - return NoneElement() + return NoneElement('next()', {'filter_loc': filter_loc, 'index': index}) def before(self, filter_loc='', index=1): """返回文档中当前元素前面符合条件的第一个元素,可用查询语法筛选,可指定返回筛选结果的第几个 @@ -895,9 +904,9 @@ class ChromiumShadowRoot(BaseElement): if nodes: return nodes[index - 1] if Settings.raise_when_ele_not_found: - raise ElementNotFoundError + raise ElementNotFoundError(None, 'before()', {'filter_loc': filter_loc, 'index': index}) else: - return NoneElement() + return NoneElement('before()', {'filter_loc': filter_loc, 'index': index}) def after(self, filter_loc='', index=1): """返回文档中此当前元素后面符合条件的第一个元素,可用查询语法筛选,可指定返回筛选结果的第几个 @@ -910,9 +919,9 @@ class ChromiumShadowRoot(BaseElement): if nodes: return nodes[index - 1] if Settings.raise_when_ele_not_found: - raise ElementNotFoundError + raise ElementNotFoundError(None, 'after()', {'filter_loc': filter_loc, 'index': index}) else: - return NoneElement() + return NoneElement('after()', {'filter_loc': filter_loc, 'index': index}) def children(self, filter_loc=''): """返回当前元素符合条件的直接子元素或节点组成的列表,可用查询语法筛选 @@ -974,7 +983,7 @@ class ChromiumShadowRoot(BaseElement): :param timeout: 查找元素超时时间,默认与元素所在页面等待时间一致 :return: ChromiumElement对象 """ - return self._ele(loc_or_str, timeout) + return self._ele(loc_or_str, timeout, method='ele()') def eles(self, loc_or_str, timeout=None): """返回当前元素下级所有符合条件的子元素 @@ -989,7 +998,11 @@ class ChromiumShadowRoot(BaseElement): :param loc_or_str: 元素的定位信息,可以是loc元组,或查询字符串 :return: SessionElement对象或属性、文本 """ - return make_session_ele(self, loc_or_str) + r = make_session_ele(self, loc_or_str) + if isinstance(r, NoneElement): + r.method = 's_ele()' + r.args = {'loc_or_str': loc_or_str} + return r def s_eles(self, loc_or_str): """查找所有符合条件的元素以SessionElement列表形式返回,处理复杂页面时效率很高 diff --git a/DrissionPage/_elements/chromium_element.pyi b/DrissionPage/_elements/chromium_element.pyi index 04bd049..9bb0cb4 100644 --- a/DrissionPage/_elements/chromium_element.pyi +++ b/DrissionPage/_elements/chromium_element.pyi @@ -6,8 +6,8 @@ from pathlib import Path from typing import Union, Tuple, List, Any +from .none_element import NoneElement from .._base.base import DrissionElement, BaseElement -from .._commons.constants import NoneElement from .._elements.session_element import SessionElement from .._pages.chromium_base import ChromiumBase from .._pages.chromium_frame import ChromiumFrame diff --git a/DrissionPage/_elements/none_element.py b/DrissionPage/_elements/none_element.py new file mode 100644 index 0000000..ceb43ce --- /dev/null +++ b/DrissionPage/_elements/none_element.py @@ -0,0 +1,42 @@ +# -*- coding:utf-8 -*- +""" +@Author : g1879 +@Contact : g1879@qq.com +""" +from .._commons.constants import Settings +from errors import ElementNotFoundError + + +class NoneElement(object): + def __init__(self, method=None, args=None): + self.method = method + self.args = args + + def __call__(self, *args, **kwargs): + if Settings.NoneElement_value is None: + raise ElementNotFoundError(None, self.method, self.args) + else: + return self + + def __getattr__(self, item): + if Settings.NoneElement_value is None: + raise ElementNotFoundError(None, self.method, self.args) + elif item in ('ele', 's_ele', 'parent', 'child', 'next', 'prev', 'before', + 'after', 'get_frame', 'shadow_root', 'sr'): + return self + else: + if item in ('size', 'link', 'css_path', 'xpath', 'comments', 'texts', 'tag', 'html', 'inner_html', + 'attrs', 'text', 'raw_text'): + return Settings.NoneElement_value + else: + raise ElementNotFoundError(None, self.method, self.args) + + def __eq__(self, other): + if other is None: + return True + + def __bool__(self): + return False + + def __repr__(self): + return 'None' diff --git a/DrissionPage/_elements/session_element.py b/DrissionPage/_elements/session_element.py index a3d74f5..177ae96 100644 --- a/DrissionPage/_elements/session_element.py +++ b/DrissionPage/_elements/session_element.py @@ -9,8 +9,8 @@ from re import match, DOTALL from lxml.etree import tostring from lxml.html import HtmlElement, fromstring +from .none_element import NoneElement from .._base.base import DrissionElement, BasePage, BaseElement -from .._commons.constants import NoneElement from .._commons.locator import get_loc from .._commons.web import get_ele_txt, make_absolute_link @@ -221,7 +221,7 @@ class SessionElement(DrissionElement): :param timeout: 不起实际作用 :return: SessionElement对象或属性、文本 """ - return self._ele(loc_or_str) + return self._ele(loc_or_str, method='ele()') def eles(self, loc_or_str, timeout=None): """返回当前元素下级所有符合条件的子元素、属性或节点文本 @@ -236,7 +236,7 @@ class SessionElement(DrissionElement): :param loc_or_str: 元素的定位信息,可以是loc元组,或查询字符串 :return: SessionElement对象或属性、文本 """ - return self._ele(loc_or_str) + return self._ele(loc_or_str, method='s_ele()') def s_eles(self, loc_or_str): """返回当前元素下级所有符合条件的子元素、属性或节点文本 diff --git a/DrissionPage/_elements/session_element.pyi b/DrissionPage/_elements/session_element.pyi index 6d3efc9..40a8909 100644 --- a/DrissionPage/_elements/session_element.pyi +++ b/DrissionPage/_elements/session_element.pyi @@ -7,8 +7,8 @@ from typing import Union, List, Tuple from lxml.html import HtmlElement +from .none_element import NoneElement from .._base.base import DrissionElement, BaseElement -from .._commons.constants import NoneElement from .._elements.chromium_element import ChromiumElement from .._pages.chromium_base import ChromiumBase from .._pages.chromium_frame import ChromiumFrame diff --git a/DrissionPage/_pages/chromium_base.py b/DrissionPage/_pages/chromium_base.py index a345f4f..34b6ac9 100644 --- a/DrissionPage/_pages/chromium_base.py +++ b/DrissionPage/_pages/chromium_base.py @@ -11,11 +11,12 @@ from threading import Thread from time import perf_counter, sleep from .._base.base import BasePage -from .._commons.constants import ERROR, NoneElement -from .._commons.locator import get_loc +from .._commons.constants import ERROR, Settings +from .._commons.locator import get_loc, is_loc from .._commons.tools import get_usable_path from .._commons.web import location_in_viewport from .._elements.chromium_element import ChromiumElement, run_js, make_chromium_ele +from .._elements.none_element import NoneElement from .._elements.session_element import make_session_ele from .._units.action_chains import ActionChains from .._units.network_listener import NetworkListener @@ -26,7 +27,7 @@ from .._units.setter import ChromiumBaseSetter from .._units.states import PageStates from .._units.waiter import BaseWaiter from ..errors import (ContextLossError, ElementLossError, CDPError, PageClosedError, NoRectError, AlertExistsError, - GetDocumentError) + GetDocumentError, ElementNotFoundError) class ChromiumBase(BasePage): @@ -540,7 +541,7 @@ class ChromiumBase(BasePage): :param timeout: 查找超时时间 :return: ChromiumElement对象 """ - return self._ele(loc_or_ele, timeout=timeout) + return self._ele(loc_or_ele, timeout=timeout, method='ele()') def eles(self, loc_or_str, timeout=None): """获取所有符合条件的元素对象 @@ -555,7 +556,14 @@ class ChromiumBase(BasePage): :param loc_or_ele: 元素的定位信息,可以是loc元组,或查询字符串 :return: SessionElement对象或属性、文本 """ - return make_session_ele(self, loc_or_ele) + r = make_session_ele(self, loc_or_ele) + if isinstance(r, NoneElement): + if Settings.raise_when_ele_not_found: + raise ElementNotFoundError(None, 's_ele()', {'loc_or_ele': loc_or_ele}) + else: + r.method = 's_ele()' + r.args = {'loc_or_ele': loc_or_ele} + return r def s_eles(self, loc_or_str): """查找所有符合条件的元素以SessionElement列表形式返回 @@ -714,34 +722,39 @@ class ChromiumBase(BasePage): :return: ChromiumFrame对象 """ if isinstance(loc_ind_ele, str): - if not loc_ind_ele.startswith(('.', '#', '@', 't:', 't=', 'tag:', 'tag=', 'tx:', 'tx=', 'tx^', 'tx$', - 'text:', 'text=', 'text^', 'text$', 'xpath:', 'xpath=', 'x:', 'x=', 'css:', - 'css=', 'c:', 'c=')): - loc_ind_ele = f'xpath://*[(name()="iframe" or name()="frame") and ' \ + if not is_loc(loc_ind_ele): + xpath = f'xpath://*[(name()="iframe" or name()="frame") and ' \ f'(@name="{loc_ind_ele}" or @id="{loc_ind_ele}")]' - ele = self._ele(loc_ind_ele, timeout=timeout) + else: + xpath = loc_ind_ele + ele = self._ele(xpath, timeout=timeout) if ele and not str(type(ele)).endswith(".ChromiumFrame'>"): raise TypeError('该定位符不是指向frame元素。') - return ele + r = ele elif isinstance(loc_ind_ele, tuple): ele = self._ele(loc_ind_ele, timeout=timeout) if ele and not str(type(ele)).endswith(".ChromiumFrame'>"): raise TypeError('该定位符不是指向frame元素。') - return ele + r = ele elif isinstance(loc_ind_ele, int): if loc_ind_ele < 1: raise ValueError('序号必须大于0。') xpath = f'xpath:(//*[name()="frame" or name()="iframe"])[{loc_ind_ele}]' - return self._ele(xpath, timeout=timeout) + r = self._ele(xpath, timeout=timeout) elif str(type(loc_ind_ele)).endswith(".ChromiumFrame'>"): - return loc_ind_ele + r = loc_ind_ele else: raise TypeError('必须传入定位符、iframe序号、id、name、ChromiumFrame对象其中之一。') + if isinstance(r, NoneElement): + r.method = 'get_frame()' + r.args = {'loc_ind_ele': loc_ind_ele} + return r + def get_frames(self, loc=None, timeout=None): """获取所有符合条件的frame对象 :param loc: 定位符,为None时返回所有 diff --git a/DrissionPage/_pages/chromium_base.pyi b/DrissionPage/_pages/chromium_base.pyi index 37f9225..772d54b 100644 --- a/DrissionPage/_pages/chromium_base.pyi +++ b/DrissionPage/_pages/chromium_base.pyi @@ -6,17 +6,17 @@ from pathlib import Path from typing import Union, Tuple, List, Any, Optional -from .._units.rect import TabRect from .._base.base import BasePage from .._base.browser import Browser from .._base.chromium_driver import ChromiumDriver -from .._commons.constants import NoneElement from .._elements.chromium_element import ChromiumElement +from .._elements.none_element import NoneElement from .._elements.session_element import SessionElement from .._pages.chromium_frame import ChromiumFrame from .._pages.chromium_page import ChromiumPage from .._units.action_chains import ActionChains from .._units.network_listener import NetworkListener +from .._units.rect import TabRect from .._units.screencast import Screencast from .._units.scroller import Scroller, PageScroller from .._units.setter import ChromiumBaseSetter diff --git a/DrissionPage/_pages/session_page.py b/DrissionPage/_pages/session_page.py index e135e3c..bd595d0 100644 --- a/DrissionPage/_pages/session_page.py +++ b/DrissionPage/_pages/session_page.py @@ -137,7 +137,7 @@ class SessionPage(BasePage): :param timeout: 不起实际作用,用于和ChromiumElement对应,便于无差别调用 :return: SessionElement对象或属性、文本 """ - return self._ele(loc_or_ele) + return self._ele(loc_or_ele, method='ele()') def eles(self, loc_or_str, timeout=None): """返回页面中所有符合条件的元素、属性或节点文本 @@ -152,7 +152,7 @@ class SessionPage(BasePage): :param loc_or_ele: 元素的定位信息,可以是元素对象,loc元组,或查询字符串 :return: SessionElement对象或属性、文本 """ - return make_session_ele(self.html) if loc_or_ele is None else self._ele(loc_or_ele) + return make_session_ele(self.html) if loc_or_ele is None else self._ele(loc_or_ele, method='s_ele()') def s_eles(self, loc_or_str): """返回页面中符合条件的所有元素、属性或节点文本 diff --git a/DrissionPage/_pages/session_page.pyi b/DrissionPage/_pages/session_page.pyi index 98d4e91..4ae4164 100644 --- a/DrissionPage/_pages/session_page.pyi +++ b/DrissionPage/_pages/session_page.pyi @@ -9,8 +9,8 @@ from requests import Session, Response from requests.structures import CaseInsensitiveDict from .._base.base import BasePage -from .._commons.constants import NoneElement from .._configs.session_options import SessionOptions +from .._elements.none_element import NoneElement from .._elements.session_element import SessionElement from .._units.setter import SessionPageSetter diff --git a/DrissionPage/errors.py b/DrissionPage/errors.py index ba515cb..88bb001 100644 --- a/DrissionPage/errors.py +++ b/DrissionPage/errors.py @@ -9,13 +9,26 @@ class BaseError(Exception): _info = None def __init__(self, ErrorInfo=None): - super().__init__(self) # 初始化父类 self._info = ErrorInfo or self._info def __str__(self): return self._info +class ElementNotFoundError(BaseError): + _info = '\n没有找到元素。' + + def __init__(self, ErrorInfo=None, method=None, arguments=None): + super().__init__(ErrorInfo=ErrorInfo) + self.method = method + self.arguments = arguments + + def __str__(self): + method = f'\nmethod: {self.method}' if self.method else '' + arguments = f'\nargs: {self.arguments}' if self.arguments else '' + return f'{self._info}{method}{arguments}' + + class AlertExistsError(BaseError): _info = '存在未处理的提示框。' @@ -36,10 +49,6 @@ class PageClosedError(BaseError): _info = '页面已关闭。' -class ElementNotFoundError(BaseError): - _info = '没有找到元素。' - - class JavaScriptError(BaseError): _info = 'JavaScript运行错误。'