From 5a80707e3820acd643af556732dc93d442e58211 Mon Sep 17 00:00:00 2001 From: g1879 Date: Thu, 11 Jan 2024 00:59:47 +0800 Subject: [PATCH] =?UTF-8?q?index=E5=85=A8=E9=83=A8=E4=BB=8E1=E5=BC=80?= =?UTF-8?q?=E5=A7=8B=EF=BC=8C=E5=8F=AF=E4=BC=A0=E5=85=A5=E8=B4=9F=E6=95=B0?= =?UTF-8?q?=EF=BC=9B=E5=AE=8C=E5=96=84=E8=8E=B7=E5=8F=96=E5=85=83=E7=B4=A0?= =?UTF-8?q?=E6=94=B9=E8=BF=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DrissionPage/_base/base.py | 58 +++++--- DrissionPage/_base/base.pyi | 33 +++-- DrissionPage/_elements/chromium_element.py | 153 +++++++++----------- DrissionPage/_elements/chromium_element.pyi | 18 +-- DrissionPage/_elements/session_element.py | 24 +-- DrissionPage/_elements/session_element.pyi | 10 +- DrissionPage/_pages/chromium_base.py | 30 ++-- DrissionPage/_pages/chromium_base.pyi | 8 +- DrissionPage/_pages/chromium_frame.py | 10 +- DrissionPage/_pages/chromium_frame.pyi | 4 +- DrissionPage/_pages/chromium_page.py | 6 +- DrissionPage/_pages/chromium_tab.py | 25 ++-- DrissionPage/_pages/chromium_tab.pyi | 9 +- DrissionPage/_pages/session_page.py | 17 ++- DrissionPage/_pages/session_page.pyi | 8 +- DrissionPage/_pages/web_page.py | 22 +-- DrissionPage/_pages/web_page.pyi | 9 +- DrissionPage/_units/selector.py | 8 +- 18 files changed, 233 insertions(+), 219 deletions(-) diff --git a/DrissionPage/_base/base.py b/DrissionPage/_base/base.py index 30435b7..a5322e4 100644 --- a/DrissionPage/_base/base.py +++ b/DrissionPage/_base/base.py @@ -23,7 +23,7 @@ class BaseParser(object): def __call__(self, loc_or_str): return self.ele(loc_or_str) - def ele(self, loc_or_ele, index=0, timeout=None): + def ele(self, loc_or_ele, index=1, timeout=None): return self._ele(loc_or_ele, timeout, index=index, method='ele()') def eles(self, loc_or_str, timeout=None): @@ -40,11 +40,11 @@ class BaseParser(object): def s_eles(self, loc_or_str): pass - def _ele(self, loc_or_ele, timeout=None, index=0, raise_err=None, method=None): + def _ele(self, loc_or_ele, timeout=None, index=1, raise_err=None, method=None): pass @abstractmethod - def _find_elements(self, loc_or_ele, timeout=None, index=0, raise_err=None): + def _find_elements(self, loc_or_ele, timeout=None, index=1, raise_err=None): pass @@ -68,19 +68,28 @@ class BaseElement(BaseParser): def nexts(self): pass - def _ele(self, loc_or_str, timeout=None, index=0, relative=False, raise_err=None, method=None): + def _ele(self, loc_or_str, timeout=None, index=1, relative=False, raise_err=None, method=None): + """调用获取元素的方法 + :param loc_or_str: 定位符 + :param timeout: 超时时间(秒) + :param index: 获取第几个,从1开始,可传入负数获取倒数第几个 + :param relative: 是否相对定位 + :param raise_err: 找不到时是否抛出异常 + :param method: 调用的方法名 + :return: 元素对象或它们组成的列表 + """ r = self._find_elements(loc_or_str, 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, {'loc_or_str': loc_or_str}) + raise ElementNotFoundError(None, method, {'loc_or_str': loc_or_str, 'index': index}) r.method = method - r.args = {'loc_or_str': loc_or_str} + r.args = {'loc_or_str': loc_or_str, 'index': index} return r @abstractmethod - def _find_elements(self, loc_or_str, timeout=None, index=0, relative=False, raise_err=None): + def _find_elements(self, loc_or_str, timeout=None, index=1, relative=False, raise_err=None): pass @@ -179,7 +188,7 @@ class DrissionElement(BaseElement): :param ele_only: 是否只获取元素,为False时把文本、注释节点也纳入 :return: 兄弟元素 """ - return self._do_relative_find('prev()', 'preceding', filter_loc, index, timeout, ele_only) + return self._get_relative('prev()', 'preceding', True, filter_loc, index, timeout, ele_only) def next(self, filter_loc='', index=1, timeout=None, ele_only=True): """返回后面的一个兄弟元素,可用查询语法筛选,可指定返回筛选结果的第几个 @@ -189,7 +198,7 @@ class DrissionElement(BaseElement): :param ele_only: 是否只获取元素,为False时把文本、注释节点也纳入 :return: 兄弟元素 """ - return self._do_relative_find('next()', 'following', filter_loc, index, timeout, ele_only) + return self._get_relative('next()', 'following', True, filter_loc, index, timeout, ele_only) def before(self, filter_loc='', index=1, timeout=None, ele_only=True): """返回前面的一个兄弟元素,可用查询语法筛选,可指定返回筛选结果的第几个 @@ -199,7 +208,7 @@ class DrissionElement(BaseElement): :param ele_only: 是否只获取元素,为False时把文本、注释节点也纳入 :return: 本元素前面的某个元素或节点 """ - return self._do_relative_find('before()', 'preceding', filter_loc, index, timeout, ele_only) + return self._get_relative('before()', 'preceding', False, filter_loc, index, timeout, ele_only) def after(self, filter_loc='', index=1, timeout=None, ele_only=True): """返回后面的一个兄弟元素,可用查询语法筛选,可指定返回筛选结果的第几个 @@ -209,7 +218,7 @@ class DrissionElement(BaseElement): :param ele_only: 是否只获取元素,为False时把文本、注释节点也纳入 :return: 本元素后面的某个元素或节点 """ - return self._do_relative_find('after()', 'following', filter_loc, index, timeout, ele_only) + return self._get_relative('after()', 'following', False, filter_loc, index, timeout, ele_only) def children(self, filter_loc='', timeout=None, ele_only=True): """返回直接子元素元素或节点组成的列表,可用查询语法筛选 @@ -268,8 +277,8 @@ class DrissionElement(BaseElement): return self._get_relatives(filter_loc=filter_loc, direction='following', brother=False, timeout=timeout, ele_only=ele_only) - def _do_relative_find(self, func, direction, filter_loc='', index=1, timeout=None, ele_only=True): - """返回前面的一个兄弟元素,可用查询语法筛选,可指定返回筛选结果的第几个 + def _get_relative(self, func, direction, brother, filter_loc='', index=1, timeout=None, ele_only=True): + """获取一个亲戚元素或节点,可用查询语法筛选,可指定返回筛选结果的第几个 :param func: 方法名称 :param direction: 方向,'following' 或 'preceding' :param filter_loc: 用于筛选的查询语法 @@ -281,7 +290,7 @@ class DrissionElement(BaseElement): if isinstance(filter_loc, int): index = filter_loc filter_loc = '' - node = self._get_relatives(index, filter_loc, direction, False, timeout, ele_only) + node = self._get_relatives(index, filter_loc, direction, brother, timeout, ele_only) if node: return node if Settings.raise_when_ele_not_found: @@ -298,9 +307,6 @@ class DrissionElement(BaseElement): :param timeout: 查找等待时间(秒) :return: 元素对象或字符串 """ - if index is not None and index < 0: - raise ValueError('index必须大于等于0。') - brother = '-sibling' if brother else '' if not filter_loc: @@ -315,7 +321,7 @@ class DrissionElement(BaseElement): loc = f'xpath:./{direction}{brother}::{loc}' if index is not None: - index = index - 1 if direction == 'following' else -index + index = index if direction == 'following' else -index nodes = self._ele(loc, timeout=timeout, index=index, relative=True, raise_err=False) if isinstance(nodes, list): nodes = [e for e in nodes if not (isinstance(e, str) and sub('[ \n\t\r]', '', e) == '')] @@ -416,7 +422,15 @@ class BasePage(BaseParser): def get(self, url, show_errmsg=False, retry=None, interval=None): pass - def _ele(self, loc_or_ele, timeout=None, index=0, raise_err=None, method=None): + def _ele(self, loc_or_ele, timeout=None, index=1, raise_err=None, method=None): + """调用获取元素的方法 + :param loc_or_ele: 定位符 + :param timeout: 超时时间(秒) + :param index: 获取第几个,从1开始,可传入负数获取倒数第几个 + :param raise_err: 找不到时是否抛出异常 + :param method: 调用的方法名 + :return: 元素对象或它们组成的列表 + """ if not loc_or_ele: raise ElementNotFoundError(None, method, {'loc_or_str': loc_or_ele}) @@ -425,12 +439,12 @@ class BasePage(BaseParser): if r or isinstance(r, list): return r if Settings.raise_when_ele_not_found or raise_err is True: - raise ElementNotFoundError(None, method, {'loc_or_str': loc_or_ele}) + raise ElementNotFoundError(None, method, {'loc_or_str': loc_or_ele, 'index': index}) r.method = method - r.args = {'loc_or_str': loc_or_ele} + r.args = {'loc_or_str': loc_or_ele, 'index': index} return r @abstractmethod - def _find_elements(self, loc_or_ele, timeout=None, index=0, raise_err=None): + def _find_elements(self, loc_or_ele, timeout=None, index=1, raise_err=None): pass diff --git a/DrissionPage/_base/base.pyi b/DrissionPage/_base/base.pyi index 900a4d2..568a35e 100644 --- a/DrissionPage/_base/base.pyi +++ b/DrissionPage/_base/base.pyi @@ -15,11 +15,11 @@ from .._elements.none_element import NoneElement class BaseParser(object): - def __call__(self, loc_or_str: Union[Tuple[str, str], str], index: int = 0): ... + def __call__(self, loc_or_str: Union[Tuple[str, str], str], index: int = 1): ... def ele(self, loc_or_ele: Union[Tuple[str, str], str, BaseElement], - index: int = 0, + index: int = 1, timeout: float = None): ... def eles(self, loc_or_str: Union[Tuple[str, str], str], timeout=None): ... @@ -28,14 +28,14 @@ class BaseParser(object): @property def html(self) -> str: ... - def s_ele(self, loc_or_ele: Union[Tuple[str, str], str, BaseElement], index: int = 0): ... + def s_ele(self, loc_or_ele: Union[Tuple[str, str], str, BaseElement], index: int = 1): ... def s_eles(self, loc_or_str: Union[Tuple[str, str], str]): ... def _ele(self, loc_or_ele, timeout: float = None, - index: Optional[int] = 0, + index: Optional[int] = 1, raise_err: bool = None, method: str = None): ... @@ -43,7 +43,7 @@ class BaseParser(object): def _find_elements(self, loc_or_ele, timeout: float = None, - index: Optional[int] = 0, + index: Optional[int] = 1, raise_err: bool = None): ... @@ -59,7 +59,7 @@ class BaseElement(BaseParser): def _ele(self, loc_or_str: Union[Tuple[str, str], str], timeout: float = None, - index: Optional[int] = 0, + index: Optional[int] = 1, relative: bool = False, raise_err: bool = None, method: str = None): ... @@ -67,7 +67,7 @@ class BaseElement(BaseParser): @abstractmethod def _find_elements(self, loc_or_str, timeout: float = None, - index: Optional[int] = 0, + index: Optional[int] = 1, relative: bool = False, raise_err: bool = None): ... @@ -161,13 +161,14 @@ class DrissionElement(BaseElement): timeout: float = None, ele_only: bool = True) -> List[Union[DrissionElement, str]]: ... - def _do_relative_find(self, - func: str, - direction: str, - filter_loc: Union[tuple, str] ='', - index: int =1, - timeout: float =None, - ele_only: bool =True) -> DrissionElement: ... + def _get_relative(self, + func: str, + direction: str, + brother: bool, + filter_loc: Union[tuple, str] = '', + index: int = 1, + timeout: float = None, + ele_only: bool = True) -> DrissionElement: ... def _get_relatives(self, index: int = None, @@ -245,7 +246,7 @@ class BasePage(BaseParser): def _ele(self, loc_or_ele, timeout: float = None, - index: Optional[int] = 0, + index: Optional[int] = 1, raise_err: bool = None, method: str = None): ... @@ -253,5 +254,5 @@ class BasePage(BaseParser): def _find_elements(self, loc_or_ele, timeout: float = None, - index: Optional[int] = 0, + index: Optional[int] = 1, raise_err: bool = None): ... diff --git a/DrissionPage/_elements/chromium_element.py b/DrissionPage/_elements/chromium_element.py index ce15ee0..642121d 100644 --- a/DrissionPage/_elements/chromium_element.py +++ b/DrissionPage/_elements/chromium_element.py @@ -80,7 +80,7 @@ class ChromiumElement(DrissionElement): attrs = [f"{attr}='{attrs[attr]}'" for attr in attrs] return f'' - def __call__(self, loc_or_str, index=0, timeout=None): + def __call__(self, loc_or_str, index=1, timeout=None): """在内部查找元素 :param loc_or_str: 元素的定位信息,可以是loc元组,或查询字符串 :param timeout: 超时时间(秒) @@ -400,10 +400,10 @@ class ChromiumElement(DrissionElement): """ run_js(self, script, as_expr, 0, args) - def ele(self, loc_or_str, index=0, timeout=None): + def ele(self, loc_or_str, index=1, timeout=None): """返回当前元素下级符合条件的一个元素、属性或节点文本 :param loc_or_str: 元素的定位信息,可以是loc元组,或查询字符串 - :param index: 获取第几个元素,0开始 + :param index: 获取第几个元素,从1开始,可传入负数获取倒数第几个 :param timeout: 查找元素超时时间(秒),默认与元素所在页面等待时间一致 :return: ChromiumElement对象或属性、文本 """ @@ -417,10 +417,10 @@ class ChromiumElement(DrissionElement): """ return self._ele(loc_or_str, timeout=timeout, index=None) - def s_ele(self, loc_or_str=None, index=0): + def s_ele(self, loc_or_str=None, index=1): """查找一个符合条件的元素,以SessionElement形式返回 :param loc_or_str: 元素的定位信息,可以是loc元组,或查询字符串 - :param index: 获取第几个,0开始 + :param index: 获取第几个,从1开始,可传入负数获取倒数第几个 :return: SessionElement对象或属性、文本 """ if self.tag in __FRAME_ELEMENT__: @@ -444,11 +444,11 @@ class ChromiumElement(DrissionElement): return make_session_ele(self.inner_html, loc_or_str, index=None) return make_session_ele(self, loc_or_str, index=None) - def _find_elements(self, loc_or_str, timeout=None, index=0, relative=False, raise_err=None): + def _find_elements(self, loc_or_str, timeout=None, index=1, relative=False, raise_err=None): """返回当前元素下级符合条件的子元素、属性或节点文本,默认返回第一个 :param loc_or_str: 元素的定位信息,可以是loc元组,或查询字符串 :param timeout: 查找元素超时时间(秒) - :param index: 第几个结果,0开始,为None返回所有 + :param index: 第几个结果,从1开始,可传入负数获取倒数第几个,为None返回所有 :param relative: WebPage用的表示是否相对定位的参数 :param raise_err: 找不到元素是是否抛出异常,为None时根据全局设置 :return: ChromiumElement对象或文本、属性或其组成的列表 @@ -808,11 +808,11 @@ class ShadowRoot(BaseElement): def __repr__(self): return f'' - def __call__(self, loc_or_str, index=0, timeout=None): + def __call__(self, loc_or_str, index=1, timeout=None): """在内部查找元素 例:ele2 = ele1('@id=ele_id') :param loc_or_str: 元素的定位信息,可以是loc元组,或查询字符串 - :param index: 获取第几个,0开始 + :param index: 获取第几个,从1开始,可传入负数获取倒数第几个 :param timeout: 超时时间(秒) :return: 元素对象或属性、文本 """ @@ -893,20 +893,23 @@ class ShadowRoot(BaseElement): :param index: 第几个查询结果,1开始 :return: 直接子元素或节点文本组成的列表 """ - nodes = self.children(filter_loc=filter_loc) - if not nodes: - if Settings.raise_when_ele_not_found: - raise ElementNotFoundError(None, 'child()', {'filter_loc': filter_loc, 'index': index}) - else: - return NoneElement(self.page, 'child()', {'filter_loc': filter_loc, 'index': index}) + if not filter_loc: + loc = '*' + else: + loc = get_loc(filter_loc, True) # 把定位符转换为xpath + if loc[0] == 'css selector': + raise ValueError('此css selector语法不受支持,请换成xpath。') + loc = loc[1].lstrip('./') - try: - return nodes[index - 1] - except IndexError: - if Settings.raise_when_ele_not_found: - raise ElementNotFoundError(None, 'child()', {'filter_loc': filter_loc, 'index': index}) - else: - return NoneElement(self.page, 'child()', {'filter_loc': filter_loc, 'index': index}) + loc = f'xpath:./{loc}' + ele = self._ele(loc, index=index, relative=True) + if ele: + return ele + + if Settings.raise_when_ele_not_found: + raise ElementNotFoundError(None, 'child()', {'filter_loc': filter_loc, 'index': index}) + else: + return NoneElement(self.page, 'child()', {'filter_loc': filter_loc, 'index': index}) def next(self, filter_loc='', index=1): """返回当前元素后面一个符合条件的同级元素,可用查询语法筛选,可指定返回筛选结果的第几个 @@ -914,9 +917,16 @@ class ShadowRoot(BaseElement): :param index: 第几个查询结果,1开始 :return: ChromiumElement对象 """ - nodes = self.nexts(filter_loc=filter_loc) - if nodes: - return nodes[index - 1] + loc = get_loc(filter_loc, True) + if loc[0] == 'css selector': + raise ValueError('此css selector语法不受支持,请换成xpath。') + + loc = loc[1].lstrip('./') + xpath = f'xpath:./{loc}' + ele = self.parent_ele._ele(xpath, index=index, relative=True) + if ele: + return ele + if Settings.raise_when_ele_not_found: raise ElementNotFoundError(None, 'next()', {'filter_loc': filter_loc, 'index': index}) else: @@ -929,9 +939,16 @@ class ShadowRoot(BaseElement): :param index: 前面第几个查询结果,1开始 :return: 本元素前面的某个元素或节点 """ - nodes = self.befores(filter_loc=filter_loc) - if nodes: - return nodes[index - 1] + loc = get_loc(filter_loc, True) + if loc[0] == 'css selector': + raise ValueError('此css selector语法不受支持,请换成xpath。') + + loc = loc[1].lstrip('./') + xpath = f'xpath:./preceding::{loc}' + ele = self.parent_ele._ele(xpath, index=index, relative=True) + if ele: + return ele + if Settings.raise_when_ele_not_found: raise ElementNotFoundError(None, 'before()', {'filter_loc': filter_loc, 'index': index}) else: @@ -1006,10 +1023,10 @@ class ShadowRoot(BaseElement): xpath = f'xpath:./following::{loc}' return eles1 + self.parent_ele._ele(xpath, index=None, relative=True) - def ele(self, loc_or_str, index=0, timeout=None): + def ele(self, loc_or_str, index=1, timeout=None): """返回当前元素下级符合条件的一个元素 :param loc_or_str: 元素的定位信息,可以是loc元组,或查询字符串 - :param index: 获取第几个元素,0开始 + :param index: 获取第几个元素,从1开始,可传入负数获取倒数第几个 :param timeout: 查找元素超时时间(秒),默认与元素所在页面等待时间一致 :return: ChromiumElement对象 """ @@ -1023,10 +1040,10 @@ class ShadowRoot(BaseElement): """ return self._ele(loc_or_str, timeout=timeout, index=None) - def s_ele(self, loc_or_str=None, index=0): + def s_ele(self, loc_or_str=None, index=1): """查找一个符合条件的元素以SessionElement形式返回,处理复杂页面时效率很高 :param loc_or_str: 元素的定位信息,可以是loc元组,或查询字符串 - :param index: 获取第几个,0开始 + :param index: 获取第几个,从1开始,可传入负数获取倒数第几个 :return: SessionElement对象或属性、文本 """ r = make_session_ele(self, loc_or_str, index=index) @@ -1042,11 +1059,11 @@ class ShadowRoot(BaseElement): """ return make_session_ele(self, loc_or_str, index=None) - def _find_elements(self, loc_or_str, timeout=None, index=0, relative=False, raise_err=None): + def _find_elements(self, loc_or_str, timeout=None, index=1, relative=False, raise_err=None): """返回当前元素下级符合条件的子元素、属性或节点文本,默认返回第一个 :param loc_or_str: 元素的定位信息,可以是loc元组,或查询字符串 :param timeout: 查找元素超时时间(秒) - :param index: 第几个结果,0开始,为None返回所有 + :param index: 第几个结果,从1开始,可传入负数获取倒数第几个,为None返回所有 :param relative: WebPage用的表示是否相对定位的参数 :param raise_err: 找不到元素是是否抛出异常,为None时根据全局设置 :return: ChromiumElement对象或其组成的列表 @@ -1057,7 +1074,7 @@ class ShadowRoot(BaseElement): def do_find(): if loc[0] == 'css selector': - if index == 0: + if index == 1: nod_id = self.page.run_cdp('DOM.querySelector', nodeId=self._node_id, selector=loc[1])['nodeId'] if nod_id: r = make_chromium_eles(self.page, _ids=nod_id, is_obj_id=False) @@ -1077,7 +1094,7 @@ class ShadowRoot(BaseElement): if index is not None: try: node_id = self.page.run_cdp('DOM.querySelector', nodeId=self._node_id, - selector=css[index])['nodeId'] + selector=css[index - 1])['nodeId'] except IndexError: return None r = make_chromium_eles(self.page, _ids=node_id, is_obj_id=False) @@ -1116,11 +1133,11 @@ class ShadowRoot(BaseElement): return r['backendNodeId'] -def find_in_chromium_ele(ele, loc, index=0, timeout=None, relative=True): +def find_in_chromium_ele(ele, loc, index=1, timeout=None, relative=True): """在chromium元素中查找 :param ele: ChromiumElement对象 :param loc: 元素定位元组 - :param index: 第几个结果,为None返回所有 + :param index: 第几个结果,从1开始,可传入负数获取倒数第几个,为None返回所有 :param timeout: 查找元素超时时间(秒) :param relative: WebPage用于标记是否相对定位使用 :return: 返回ChromiumElement元素或它们组成的列表 @@ -1152,12 +1169,12 @@ def find_by_xpath(ele, xpath, index, timeout, relative=True): """执行用xpath在元素中查找元素 :param ele: 在此元素中查找 :param xpath: 查找语句 - :param index: 第几个结果,为None返回所有 + :param index: 第几个结果,从1开始,可传入负数获取倒数第几个,为None返回所有 :param timeout: 超时时间(秒) :param relative: 是否相对定位 :return: ChromiumElement或其组成的列表 """ - type_txt = '9' if index == 0 else '7' + type_txt = '9' if index == 1 else '7' node_txt = 'this.contentDocument' if ele.tag in __FRAME_ELEMENT__ and not relative else 'this' js = make_js_for_find_ele_by_xpath(xpath, type_txt, node_txt) ele.page.wait.load_complete() @@ -1179,7 +1196,7 @@ def find_by_xpath(ele, xpath, index, timeout, relative=True): if res['result']['subtype'] == 'null' or res['result']['description'] in ('NodeList(0)', 'Array(0)'): return None - if index == 0: + if index == 1: r = make_chromium_eles(ele.page, _ids=res['result']['objectId'], is_obj_id=True) return None if r is False else r @@ -1192,10 +1209,12 @@ def find_by_xpath(ele, xpath, index, timeout, relative=True): return None if False in r else r else: - try: - res = res[index] - except IndexError: + eles_count = len(res) + if eles_count == 0 or abs(index) > eles_count: return None + + index1 = eles_count + index + 1 if index < 0 else index + res = res[index1 - 1] if res['value']['type'] == 'object': r = make_chromium_eles(ele.page, _ids=res['value']['objectId'], is_obj_id=True) else: @@ -1217,12 +1236,12 @@ def find_by_css(ele, selector, index, timeout): """执行用css selector在元素中查找元素 :param ele: 在此元素中查找 :param selector: 查找语句 - :param index: 第几个结果,为None返回所有 + :param index: 第几个结果,从1开始,可传入负数获取倒数第几个,为None返回所有 :param timeout: 超时时间(秒) :return: ChromiumElement或其组成的列表 """ selector = selector.replace('"', r'\"') - find_all = '' if index == 0 else 'All' + find_all = '' if index == 1 else 'All' node_txt = 'this.contentDocument' if ele.tag in ('iframe', 'frame', 'shadow-root') else 'this' js = f'function(){{return {node_txt}.querySelector{find_all}("{selector}");}}' @@ -1237,7 +1256,7 @@ def find_by_css(ele, selector, index, timeout): if res['result']['subtype'] == 'null' or res['result']['description'] in ('NodeList(0)', 'Array(0)'): return None - if index == 0: + if index == 1: r = make_chromium_eles(ele.page, _ids=res['result']['objectId'], is_obj_id=True) return None if r is False else r @@ -1259,7 +1278,7 @@ def find_by_css(ele, selector, index, timeout): return NoneElement(ele.page) if index is not None else [] -def make_chromium_eles(page, _ids, index=0, is_obj_id=True): +def make_chromium_eles(page, _ids, index=1, is_obj_id=True): """根据node id或object id生成相应元素对象 :param page: ChromiumPage对象 :param _ids: 元素的id列表 @@ -1269,16 +1288,13 @@ def make_chromium_eles(page, _ids, index=0, is_obj_id=True): """ if is_obj_id: get_node_func = _get_node_by_obj_id - # id_txt = 'objectId' else: get_node_func = _get_node_by_node_id - # id_txt = 'nodeId' if not isinstance(_ids, (list, tuple)): _ids = (_ids,) - # if not ele_only: if index is not None: # 获取一个 - obj_id = _ids[index] + obj_id = _ids[index - 1] return get_node_func(page, obj_id) else: # 获取全部 @@ -1290,39 +1306,6 @@ def make_chromium_eles(page, _ids, index=0, is_obj_id=True): nodes.append(tmp) return nodes - # if index is None: - # nodes = [] - # for obj_id in _ids: - # tmp = get_node_func(page, obj_id) - # if tmp is False: - # return False - # if not isinstance(tmp, str): - # nodes.append(tmp) - # return nodes - # - # ids_count = len(_ids) - # if index < 0: - # index = ids_count + index - # if index > ids_count - 1: - # return False - # - # tmp = get_node_func(page, _ids[index]) - # if not isinstance(tmp, str): - # return tmp - # - # num = -1 - # for obj_id in _ids: - # node = _get_node_info(page, id_txt, obj_id) - # if node is False: - # return False - # if node['node']['nodeName'] in ('#text', '#comment'): - # continue - # num += 1 - # if num == index: - # return _make_ele(page, obj_id, node) - - # return NoneElement(page) - def _get_node_info(page, id_type, _id): if not _id: diff --git a/DrissionPage/_elements/chromium_element.pyi b/DrissionPage/_elements/chromium_element.pyi index 32e4c65..2549f32 100644 --- a/DrissionPage/_elements/chromium_element.pyi +++ b/DrissionPage/_elements/chromium_element.pyi @@ -49,7 +49,7 @@ class ChromiumElement(DrissionElement): def __call__(self, loc_or_str: Union[Tuple[str, str], str], - index: int = 0, + index: int = 1, timeout: float = None) -> Union[ChromiumElement, NoneElement]: ... def __eq__(self, other: ChromiumElement) -> bool: ... @@ -177,7 +177,7 @@ class ChromiumElement(DrissionElement): def ele(self, loc_or_str: Union[Tuple[str, str], str], - index: int = 0, + index: int = 1, timeout: float = None) -> Union[ChromiumElement, NoneElement]: ... def eles(self, @@ -186,14 +186,14 @@ class ChromiumElement(DrissionElement): def s_ele(self, loc_or_str: Union[Tuple[str, str], str] = None, - index: int = 0) -> Union[SessionElement, NoneElement]: ... + index: int = 1) -> Union[SessionElement, NoneElement]: ... def s_eles(self, loc_or_str: Union[Tuple[str, str], str] = None) -> List[SessionElement]: ... def _find_elements(self, loc_or_str: Union[Tuple[str, str], str], timeout: float = None, - index: Optional[int] = True, + index: Optional[int] = 1, relative: bool = False, raise_err: bool = False) -> Union[ChromiumElement, ChromiumFrame, NoneElement, List[Union[ChromiumElement, ChromiumFrame]]]: ... @@ -293,7 +293,7 @@ class ShadowRoot(BaseElement): def ele(self, loc_or_str: Union[Tuple[str, str], str], - index: int = 0, + index: int = 1, timeout: float = None) -> Union[ChromiumElement, NoneElement]: ... def eles(self, @@ -302,14 +302,14 @@ class ShadowRoot(BaseElement): def s_ele(self, loc_or_str: Union[Tuple[str, str], str] = None, - index: int = 0) -> Union[SessionElement, NoneElement]: ... + index: int = 1) -> Union[SessionElement, NoneElement]: ... def s_eles(self, loc_or_str: Union[Tuple[str, str], str]) -> List[SessionElement]: ... def _find_elements(self, loc_or_str: Union[Tuple[str, str], str], timeout: float = None, - index: Optional[int] = 0, + index: Optional[int] = 1, relative: bool = False, raise_err: bool = None) -> Union[ChromiumElement, ChromiumFrame, NoneElement, str, List[Union[ChromiumElement, ChromiumFrame, str]]]: ... @@ -323,7 +323,7 @@ class ShadowRoot(BaseElement): def find_in_chromium_ele(ele: ChromiumElement, loc: Union[str, Tuple[str, str]], - index: Optional[int] = 0, + index: Optional[int] = 1, timeout: float = None, relative: bool = True) -> Union[ChromiumElement, NoneElement, List[ChromiumElement]]: ... @@ -343,7 +343,7 @@ def find_by_css(ele: ChromiumElement, def make_chromium_eles(page: Union[ChromiumBase, ChromiumPage, WebPage, ChromiumTab, ChromiumFrame], _ids: Union[tuple, list, str, int], - index: Optional[int] = 0, + index: Optional[int] = 1, is_obj_id: bool = True ) -> Union[ChromiumElement, ChromiumFrame, NoneElement, List[Union[ChromiumElement, ChromiumFrame]]]: ... diff --git a/DrissionPage/_elements/session_element.py b/DrissionPage/_elements/session_element.py index 881a0d9..b8b9f9d 100644 --- a/DrissionPage/_elements/session_element.py +++ b/DrissionPage/_elements/session_element.py @@ -220,10 +220,10 @@ class SessionElement(DrissionElement): else: return self.inner_ele.get(attr) - def ele(self, loc_or_str, index=0, timeout=None): + def ele(self, loc_or_str, index=1, timeout=None): """返回当前元素下级符合条件的一个元素、属性或节点文本 :param loc_or_str: 元素的定位信息,可以是loc元组,或查询字符串 - :param index: 第几个元素,0开始 + :param index: 第几个元素,从1开始,可传入负数获取倒数第几个 :param timeout: 不起实际作用 :return: SessionElement对象或属性、文本 """ @@ -237,10 +237,10 @@ class SessionElement(DrissionElement): """ return self._ele(loc_or_str, index=None) - def s_ele(self, loc_or_str=None, index=0): + def s_ele(self, loc_or_str=None, index=1): """返回当前元素下级符合条件的一个元素、属性或节点文本 :param loc_or_str: 元素的定位信息,可以是loc元组,或查询字符串 - :param index: 获取第几个,0开始 + :param index: 获取第几个,从1开始,可传入负数获取倒数第几个 :return: SessionElement对象或属性、文本 """ return self._ele(loc_or_str, index=index, method='s_ele()') @@ -252,11 +252,11 @@ class SessionElement(DrissionElement): """ return self._ele(loc_or_str, index=None) - def _find_elements(self, loc_or_str, timeout=None, index=0, relative=False, raise_err=None): + def _find_elements(self, loc_or_str, timeout=None, index=1, relative=False, raise_err=None): """返回当前元素下级符合条件的子元素、属性或节点文本 :param loc_or_str: 元素的定位信息,可以是loc元组,或查询字符串 :param timeout: 不起实际作用,用于和父类对应 - :param index: 第几个结果,0开始,为None返回所有 + :param index: 第几个结果,从1开始,可传入负数获取倒数第几个,为None返回所有 :param relative: WebPage用的表示是否相对定位的参数 :param raise_err: 找不到元素是是否抛出异常,为None时根据全局设置 :return: SessionElement对象 @@ -284,12 +284,12 @@ class SessionElement(DrissionElement): return f'{path_str[1:]}' if mode == 'css' else path_str -def make_session_ele(html_or_ele, loc=None, index=0): +def make_session_ele(html_or_ele, loc=None, index=1): """从接收到的对象或html文本中查找元素,返回SessionElement对象 如要直接从html生成SessionElement而不在下级查找,loc输入None即可 :param html_or_ele: html文本、BaseParser对象 :param loc: 定位元组或字符串,为None时不在下级查找,返回根元素 - :param index: 获取第几个元素,None获取所有 + :param index: 获取第几个元素,从1开始,可传入负数获取倒数第几个,None获取所有 :return: 返回SessionElement元素或列表,或属性文本 """ # ---------------处理定位符--------------- @@ -382,12 +382,12 @@ def make_session_ele(html_or_ele, loc=None, index=0): else: eles_count = len(eles) - if index < 0: - index = eles_count + index - if index > eles_count - 1: + if eles_count == 0 or abs(index) > eles_count: return NoneElement(page) + if index < 0: + index = eles_count + index + 1 - ele = eles[index] + ele = eles[index - 1] if isinstance(ele, HtmlElement): return SessionElement(ele, page) elif isinstance(ele, str): diff --git a/DrissionPage/_elements/session_element.pyi b/DrissionPage/_elements/session_element.pyi index d9e7438..4e6fb8f 100644 --- a/DrissionPage/_elements/session_element.pyi +++ b/DrissionPage/_elements/session_element.pyi @@ -30,7 +30,7 @@ class SessionElement(DrissionElement): def __call__(self, loc_or_str: Union[Tuple[str, str], str], - index: int = 0, + index: int = 1, timeout: float = None) -> Union[SessionElement, NoneElement]: ... def __eq__(self, other: SessionElement) -> bool: ... @@ -116,7 +116,7 @@ class SessionElement(DrissionElement): def ele(self, loc_or_str: Union[Tuple[str, str], str], - index: int = 0, + index: int = 1, timeout: float = None) -> Union[SessionElement, NoneElement]: ... def eles(self, @@ -125,14 +125,14 @@ class SessionElement(DrissionElement): def s_ele(self, loc_or_str: Union[Tuple[str, str], str] = None, - index: int = 0) -> Union[SessionElement, NoneElement]: ... + index: int = 1) -> Union[SessionElement, NoneElement]: ... def s_eles(self, loc_or_str: Union[Tuple[str, str], str]) -> List[SessionElement]: ... def _find_elements(self, loc_or_str: Union[Tuple[str, str], str], timeout: float = None, - index: Optional[int] = 0, + index: Optional[int] = 1, relative: bool = False, raise_err: bool = None) -> Union[SessionElement, NoneElement, List[SessionElement]]: ... @@ -142,4 +142,4 @@ class SessionElement(DrissionElement): def make_session_ele(html_or_ele: Union[str, SessionElement, SessionPage, ChromiumElement, BaseElement, ChromiumFrame, ChromiumBase], loc: Union[str, Tuple[str, str]] = None, - index: Optional[int] = 0) -> Union[SessionElement, NoneElement, List[SessionElement]]: ... + index: Optional[int] = 1) -> Union[SessionElement, NoneElement, List[SessionElement]]: ... diff --git a/DrissionPage/_pages/chromium_base.py b/DrissionPage/_pages/chromium_base.py index f4c9197..e04740c 100644 --- a/DrissionPage/_pages/chromium_base.py +++ b/DrissionPage/_pages/chromium_base.py @@ -244,11 +244,11 @@ class ChromiumBase(BasePage): self.run_cdp('Page.setInterceptFileChooserDialog', enabled=False) self._upload_list = None - def __call__(self, loc_or_str, index=0, timeout=None): + def __call__(self, loc_or_str, index=1, timeout=None): """在内部查找元素 例:ele = page('@id=ele_id') :param loc_or_str: 元素的定位信息,可以是loc元组,或查询字符串 - :param index: 获取第几个元素,0开始 + :param index: 获取第几个元素,从1开始,可传入负数获取倒数第几个 :param timeout: 超时时间(秒) :return: ChromiumElement对象 """ @@ -491,10 +491,10 @@ class ChromiumBase(BasePage): return [{'name': cookie['name'], 'value': cookie['value'], 'domain': cookie['domain']} for cookie in cookies] - def ele(self, loc_or_ele, index=0, timeout=None): + def ele(self, loc_or_ele, index=1, timeout=None): """获取一个符合条件的元素对象 :param loc_or_ele: 定位符或元素对象 - :param index: 获取第几个元素,0开始 + :param index: 获取第几个元素,从1开始,可传入负数获取倒数第几个 :param timeout: 查找超时时间(秒) :return: ChromiumElement对象 """ @@ -508,10 +508,10 @@ class ChromiumBase(BasePage): """ return self._ele(loc_or_str, timeout=timeout, index=None) - def s_ele(self, loc_or_ele=None, index=0): + def s_ele(self, loc_or_ele=None, index=1): """查找一个符合条件的元素以SessionElement形式返回,处理复杂页面时效率很高 :param loc_or_ele: 元素的定位信息,可以是loc元组,或查询字符串 - :param index: 获取第几个,0开始 + :param index: 获取第几个,从1开始,可传入负数获取倒数第几个 :return: SessionElement对象或属性、文本 """ r = make_session_ele(self, loc_or_ele, index=index) @@ -530,11 +530,11 @@ class ChromiumBase(BasePage): """ return make_session_ele(self, loc_or_str, index=None) - def _find_elements(self, loc_or_ele, timeout=None, index=0, relative=False, raise_err=None): + def _find_elements(self, loc_or_ele, timeout=None, index=1, relative=False, raise_err=None): """执行元素查找 :param loc_or_ele: 定位符或元素对象 :param timeout: 查找超时时间(秒) - :param index: 第几个结果,0开始,为None返回所有 + :param index: 第几个结果,从1开始,可传入负数获取倒数第几个,为None返回所有 :param relative: WebPage用的表示是否相对定位的参数 :param raise_err: 找不到元素是是否抛出异常,为None时根据全局设置 :return: ChromiumElement对象或元素对象组成的列表 @@ -569,7 +569,7 @@ class ChromiumBase(BasePage): from_index = index + num end_index = from_index + 1 else: - from_index = index + from_index = index - 1 end_index = from_index + 1 if from_index <= num - 1: @@ -668,8 +668,8 @@ class ChromiumBase(BasePage): self.run_cdp('DOM.removeNode', nodeId=ele._node_id) def get_frame(self, loc_ind_ele, timeout=None): - """获取页面中一个frame对象,可传入定位符、iframe序号、ChromiumFrame对象,序号从0开始 - :param loc_ind_ele: 定位符、iframe序号、ChromiumFrame对象 + """获取页面中一个frame对象 + :param loc_ind_ele: 定位符、iframe序号、ChromiumFrame对象,序号从1开始,可传入负数获取倒数第几个 :param timeout: 查找元素超时时间(秒) :return: ChromiumFrame对象 """ @@ -691,9 +691,11 @@ class ChromiumBase(BasePage): r = ele elif isinstance(loc_ind_ele, int): - if loc_ind_ele < 0: - raise ValueError('序号必须大于等于0。') - xpath = f'xpath:(//*[name()="frame" or name()="iframe"])[{loc_ind_ele + 1}]' + if loc_ind_ele == 0: + loc_ind_ele = 1 + elif loc_ind_ele < 0: + loc_ind_ele = f'last()-{-loc_ind_ele}' + xpath = f'xpath:(//*[name()="frame" or name()="iframe"])[{loc_ind_ele}]' r = self._ele(xpath, timeout=timeout) elif str(type(loc_ind_ele)).endswith(".ChromiumFrame'>"): diff --git a/DrissionPage/_pages/chromium_base.pyi b/DrissionPage/_pages/chromium_base.pyi index 83e3573..ae21e4f 100644 --- a/DrissionPage/_pages/chromium_base.pyi +++ b/DrissionPage/_pages/chromium_base.pyi @@ -95,7 +95,7 @@ class ChromiumBase(BasePage): def __call__(self, loc_or_str: Union[Tuple[str, str], str, ChromiumElement], - index: int = 0, + index: int = 1, timeout: float = None) -> Union[ChromiumElement, NoneElement]: ... @property @@ -181,7 +181,7 @@ class ChromiumBase(BasePage): def ele(self, loc_or_ele: Union[Tuple[str, str], str, ChromiumElement, ChromiumFrame], - index: int = 0, + index: int = 1, timeout: float = None) -> Union[ChromiumElement, NoneElement]: ... def eles(self, @@ -190,14 +190,14 @@ class ChromiumBase(BasePage): def s_ele(self, loc_or_ele: Union[Tuple[str, str], str] = None, - index:int = 0) -> Union[SessionElement, NoneElement]: ... + index:int = 1) -> Union[SessionElement, NoneElement]: ... def s_eles(self, loc_or_str: Union[Tuple[str, str], str]) -> List[SessionElement]: ... def _find_elements(self, loc_or_ele: Union[Tuple[str, str], str, ChromiumElement, ChromiumFrame], timeout: float = None, - index: Optional[int] = 0, + index: Optional[int] = 1, relative: bool = False, raise_err: bool = None) \ -> Union[ChromiumElement, ChromiumFrame, NoneElement, List[Union[ChromiumElement, ChromiumFrame]]]: ... diff --git a/DrissionPage/_pages/chromium_frame.py b/DrissionPage/_pages/chromium_frame.py index 2f7b3f0..a165a01 100644 --- a/DrissionPage/_pages/chromium_frame.py +++ b/DrissionPage/_pages/chromium_frame.py @@ -64,11 +64,11 @@ class ChromiumFrame(ChromiumBase): break sleep(.1) - def __call__(self, loc_or_str, index=0, timeout=None): + def __call__(self, loc_or_str, index=1, timeout=None): """在内部查找元素 例:ele2 = ele1('@id=ele_id') :param loc_or_str: 元素的定位信息,可以是loc元组,或查询字符串 - :param index: 获取第几个,0开始 + :param index: 获取第几个,从1开始,可传入负数获取倒数第几个 :param timeout: 超时时间(秒) :return: ChromiumElement对象或属性、文本 """ @@ -562,11 +562,11 @@ class ChromiumFrame(ChromiumBase): self.tab.remove_ele(new_ele) return r - def _find_elements(self, loc_or_ele, timeout=None, index=0, relative=False, raise_err=None): + def _find_elements(self, loc_or_ele, timeout=None, index=1, relative=False, raise_err=None): """在frame内查找单个元素 :param loc_or_ele: 定位符或元素对象 :param timeout: 查找超时时间 - :param index: 第几个结果,0开始,为None返回所有 + :param index: 第几个结果,从1开始,可传入负数获取倒数第几个,为None返回所有 :param relative: WebPage用的表示是否相对定位的参数 :param raise_err: 找不到元素是是否抛出异常,为None时根据全局设置 :return: ChromiumElement对象 @@ -574,7 +574,7 @@ class ChromiumFrame(ChromiumBase): if isinstance(loc_or_ele, ChromiumElement): return loc_or_ele self.wait.load_complete() - return self.doc_ele._ele(loc_or_ele, timeout, + return self.doc_ele._ele(loc_or_ele, index=index, timeout=timeout, raise_err=raise_err) if index is not None else self.doc_ele.eles(loc_or_ele, timeout) def _is_inner_frame(self): diff --git a/DrissionPage/_pages/chromium_frame.pyi b/DrissionPage/_pages/chromium_frame.pyi index a7d606f..f18f4ac 100644 --- a/DrissionPage/_pages/chromium_frame.pyi +++ b/DrissionPage/_pages/chromium_frame.pyi @@ -44,7 +44,7 @@ class ChromiumFrame(ChromiumBase): def __call__(self, loc_or_str: Union[Tuple[str, str], str], - index: int = 0, + index: int = 1, timeout: float = None) -> Union[ChromiumElement, NoneElement]: ... def __eq__(self, other: ChromiumFrame) -> bool: ... @@ -210,7 +210,7 @@ class ChromiumFrame(ChromiumBase): def _find_elements(self, loc_or_ele: Union[Tuple[str, str], str, ChromiumElement, ChromiumFrame], timeout: float = None, - index: Optional[int] = 0, + index: Optional[int] = 1, relative: bool = False, raise_err: bool = None) \ -> Union[ChromiumElement, ChromiumFrame, None, List[Union[ChromiumElement, ChromiumFrame]]]: ... diff --git a/DrissionPage/_pages/chromium_page.py b/DrissionPage/_pages/chromium_page.py index 820d085..2101c8c 100644 --- a/DrissionPage/_pages/chromium_page.py +++ b/DrissionPage/_pages/chromium_page.py @@ -156,17 +156,17 @@ class ChromiumPage(ChromiumBase): :param kwargs: pdf生成参数 :return: as_pdf为True时返回bytes,否则返回文件文本 """ - return get_pdf(self, path, name, kwargs)if as_pdf else get_mhtml(self, path, name) + return get_pdf(self, path, name, kwargs) if as_pdf else get_mhtml(self, path, name) def get_tab(self, id_or_num=None): """获取一个标签页对象 - :param id_or_num: 要获取的标签页id或序号,为None时获取当前tab,序号不是视觉排列顺序,而是激活顺序 + :param id_or_num: 要获取的标签页id或序号,为None时获取当前tab,序号从1开始,可传入负数获取倒数第几个,不是视觉排列顺序,而是激活顺序 :return: 标签页对象 """ if isinstance(id_or_num, str): return ChromiumTab(self, id_or_num) elif isinstance(id_or_num, int): - return ChromiumTab(self, self.tabs[id_or_num]) + return ChromiumTab(self, self.tabs[id_or_num - 1 if id_or_num < 0 else id_or_num]) elif id_or_num is None: return ChromiumTab(self, self.tab_id) elif isinstance(id_or_num, ChromiumTab): diff --git a/DrissionPage/_pages/chromium_tab.py b/DrissionPage/_pages/chromium_tab.py index 3799f73..2bd7c78 100644 --- a/DrissionPage/_pages/chromium_tab.py +++ b/DrissionPage/_pages/chromium_tab.py @@ -87,17 +87,18 @@ class WebPageTab(SessionPage, ChromiumTab, BasePage): page._headers)) super(SessionPage, self).__init__(page=page, tab_id=tab_id) - def __call__(self, loc_or_str, timeout=None): + def __call__(self, loc_or_str, index=1, timeout=None): """在内部查找元素 例:ele = page('@id=ele_id') :param loc_or_str: 元素的定位信息,可以是loc元组,或查询字符串 + :param index: 获取第几个,从1开始,可传入负数获取倒数第几个 :param timeout: 超时时间(秒) :return: 子元素对象 """ if self._mode == 'd': - return super(SessionPage, self).__call__(loc_or_str, timeout) + return super(SessionPage, self).__call__(loc_or_str, index=index, timeout=timeout) elif self._mode == 's': - return super().__call__(loc_or_str) + return super().__call__(loc_or_str, index=index) @property def set(self): @@ -231,16 +232,17 @@ class WebPageTab(SessionPage, ChromiumTab, BasePage): return self.response return super().post(url, show_errmsg, retry, interval, **kwargs) - def ele(self, loc_or_ele, timeout=None): + def ele(self, loc_or_ele, index=1, timeout=None): """返回第一个符合条件的元素、属性或节点文本 :param loc_or_ele: 元素的定位信息,可以是元素对象,loc元组,或查询字符串 + :param index: 获取第几个,从1开始,可传入负数获取倒数第几个 :param timeout: 查找元素超时时间(秒),默认与页面等待时间一致 :return: 元素对象或属性、文本节点文本 """ if self._mode == 's': - return super().ele(loc_or_ele) + return super().ele(loc_or_ele, index=index) elif self._mode == 'd': - return super(SessionPage, self).ele(loc_or_ele, timeout=timeout) + return super(SessionPage, self).ele(loc_or_ele, index=index, timeout=timeout) def eles(self, loc_or_str, timeout=None): """返回页面中所有符合条件的元素、属性或节点文本 @@ -253,15 +255,16 @@ class WebPageTab(SessionPage, ChromiumTab, BasePage): elif self._mode == 'd': return super(SessionPage, self).eles(loc_or_str, timeout=timeout) - def s_ele(self, loc_or_ele=None): + def s_ele(self, loc_or_ele=None, index=1): """查找第一个符合条件的元素以SessionElement形式返回,d模式处理复杂页面时效率很高 :param loc_or_ele: 元素的定位信息,可以是loc元组,或查询字符串 + :param index: 获取第几个,从1开始,可传入负数获取倒数第几个 :return: SessionElement对象或属性、文本 """ if self._mode == 's': - return super().s_ele(loc_or_ele) + return super().s_ele(loc_or_ele, index=index) elif self._mode == 'd': - return super(SessionPage, self).s_ele(loc_or_ele) + return super(SessionPage, self).s_ele(loc_or_ele, index=index) def s_eles(self, loc_or_str): """查找所有符合条件的元素以SessionElement形式返回,d模式处理复杂页面时效率很高 @@ -355,11 +358,11 @@ class WebPageTab(SessionPage, ChromiumTab, BasePage): if self._response is not None: self._response.close() - def _find_elements(self, loc_or_ele, timeout=None, index=0, relative=False, raise_err=None): + def _find_elements(self, loc_or_ele, timeout=None, index=1, relative=False, raise_err=None): """返回页面中符合条件的元素、属性或节点文本,默认返回第一个 :param loc_or_ele: 元素的定位信息,可以是元素对象,loc元组,或查询字符串 :param timeout: 查找元素超时时间(秒),d模式专用 - :param index: 第几个结果,0开始,为None返回所有 + :param index: 第几个结果,从1开始,可传入负数获取倒数第几个,为None返回所有 :param relative: WebPage用的表示是否相对定位的参数 :param raise_err: 找不到元素是是否抛出异常,为None时根据全局设置 :return: 元素对象或属性、文本节点文本 diff --git a/DrissionPage/_pages/chromium_tab.pyi b/DrissionPage/_pages/chromium_tab.pyi index 3ca580c..1d6785c 100644 --- a/DrissionPage/_pages/chromium_tab.pyi +++ b/DrissionPage/_pages/chromium_tab.pyi @@ -76,6 +76,7 @@ class WebPageTab(SessionPage, ChromiumTab): def __call__(self, loc_or_str: Union[Tuple[str, str], str, ChromiumElement, SessionElement], + index: int = 1, timeout: float = None) -> Union[ChromiumElement, SessionElement, NoneElement]: ... @property @@ -145,14 +146,16 @@ class WebPageTab(SessionPage, ChromiumTab): def ele(self, loc_or_ele: Union[Tuple[str, str], str, ChromiumElement, SessionElement], + index: int = 1, timeout: float = None) -> Union[ChromiumElement, SessionElement, NoneElement]: ... def eles(self, loc_or_str: Union[Tuple[str, str], str], timeout: float = None) -> List[Union[ChromiumElement, SessionElement]]: ... - def s_ele(self, loc_or_ele: Union[Tuple[str, str], str] = None) \ - -> Union[SessionElement, NoneElement]: ... + def s_ele(self, + loc_or_ele: Union[Tuple[str, str], str] = None, + index: int = 1) -> Union[SessionElement, NoneElement]: ... def s_eles(self, loc_or_str: Union[Tuple[str, str], str]) -> List[SessionElement]: ... @@ -194,7 +197,7 @@ class WebPageTab(SessionPage, ChromiumTab): def _find_elements(self, loc_or_ele: Union[Tuple[str, str], str, ChromiumElement, SessionElement, ChromiumFrame], timeout: float = None, - index: Optional[int] = 0, + index: Optional[int] = 1, relative: bool = False, raise_err: bool = None) \ -> Union[ChromiumElement, SessionElement, ChromiumFrame, NoneElement, List[SessionElement], List[ diff --git a/DrissionPage/_pages/session_page.py b/DrissionPage/_pages/session_page.py index 88ca76f..bbc8e16 100644 --- a/DrissionPage/_pages/session_page.py +++ b/DrissionPage/_pages/session_page.py @@ -68,14 +68,15 @@ class SessionPage(BasePage): if not self._session: self._session, self._headers = self._session_options.make_session() - def __call__(self, loc_or_str, timeout=None): + def __call__(self, loc_or_str, index=1, timeout=None): """在内部查找元素 例:ele2 = ele1('@id=ele_id') :param loc_or_str: 元素的定位信息,可以是loc元组,或查询字符串 + :param index: 获取第几个,从1开始,可传入负数获取倒数第几个 :param timeout: 不起实际作用,用于和ChromiumElement对应,便于无差别调用 :return: SessionElement对象或属性文本 """ - return self.ele(loc_or_str) + return self.ele(loc_or_str, index=index) # -----------------共有属性和方法------------------- @property @@ -174,10 +175,10 @@ class SessionPage(BasePage): """ return self._s_connect(url, 'post', show_errmsg, retry, interval, **kwargs) - def ele(self, loc_or_ele, index=0, timeout=None): + def ele(self, loc_or_ele, index=1, timeout=None): """返回页面中符合条件的一个元素、属性或节点文本 :param loc_or_ele: 元素的定位信息,可以是元素对象,loc元组,或查询字符串 - :param index: 获取第几个,0开始 + :param index: 获取第几个,从1开始,可传入负数获取倒数第几个 :param timeout: 不起实际作用,用于和ChromiumElement对应,便于无差别调用 :return: SessionElement对象或属性、文本 """ @@ -191,10 +192,10 @@ class SessionPage(BasePage): """ return self._ele(loc_or_str, index=None) - def s_ele(self, loc_or_ele=None, index=0): + def s_ele(self, loc_or_ele=None, index=1): """返回页面中符合条件的一个元素、属性或节点文本 :param loc_or_ele: 元素的定位信息,可以是元素对象,loc元组,或查询字符串 - :param index: 获取第几个,0开始 + :param index: 获取第几个,从1开始,可传入负数获取倒数第几个 :return: SessionElement对象或属性、文本 """ return make_session_ele(self.html) if loc_or_ele is None else self._ele(loc_or_ele, @@ -207,11 +208,11 @@ class SessionPage(BasePage): """ return self._ele(loc_or_str, index=None) - def _find_elements(self, loc_or_ele, timeout=None, index=0, raise_err=None): + def _find_elements(self, loc_or_ele, timeout=None, index=1, raise_err=None): """返回页面中符合条件的元素、属性或节点文本,默认返回第一个 :param loc_or_ele: 元素的定位信息,可以是元素对象,loc元组,或查询字符串 :param timeout: 不起实际作用,用于和父类对应 - :param index: 第几个结果,0开始,为None返回所有 + :param index: 第几个结果,从1开始,可传入负数获取倒数第几个,为None返回所有 :param raise_err: 找不到元素是是否抛出异常,为None时根据全局设置 :return: SessionElement对象 """ diff --git a/DrissionPage/_pages/session_page.pyi b/DrissionPage/_pages/session_page.pyi index 1e3b8a8..c134a85 100644 --- a/DrissionPage/_pages/session_page.pyi +++ b/DrissionPage/_pages/session_page.pyi @@ -42,6 +42,7 @@ class SessionPage(BasePage): def __call__(self, loc_or_str: Union[Tuple[str, str], str, SessionElement], + index: int = 1, timeout: float = None) -> Union[SessionElement, NoneElement]: ... # -----------------共有属性和方法------------------- @@ -91,6 +92,7 @@ class SessionPage(BasePage): def ele(self, loc_or_ele: Union[Tuple[str, str], str, SessionElement], + index: int = 1, timeout: float = None) -> Union[SessionElement, NoneElement]: ... def eles(self, @@ -98,15 +100,15 @@ class SessionPage(BasePage): timeout: float = None) -> List[SessionElement]: ... def s_ele(self, - loc_or_ele: Union[Tuple[str, str], str, SessionElement] = None) \ - -> Union[SessionElement, NoneElement]: ... + loc_or_ele: Union[Tuple[str, str], str, SessionElement] = None, + index: int = 1) -> Union[SessionElement, NoneElement]: ... def s_eles(self, loc_or_str: Union[Tuple[str, str], str]) -> List[SessionElement]: ... def _find_elements(self, loc_or_ele: Union[Tuple[str, str], str, SessionElement], timeout: float = None, - index: Optional[int] = 0, + index: Optional[int] = 1, raise_err: bool = None) \ -> Union[SessionElement, NoneElement, List[SessionElement]]: ... diff --git a/DrissionPage/_pages/web_page.py b/DrissionPage/_pages/web_page.py index 96e7191..5f14da3 100644 --- a/DrissionPage/_pages/web_page.py +++ b/DrissionPage/_pages/web_page.py @@ -38,11 +38,11 @@ class WebPage(SessionPage, ChromiumPage, BasePage): super(SessionPage, self).__init__(addr_or_opts=chromium_options, timeout=timeout) self.change_mode(self._mode, go=False, copy_cookies=False) - def __call__(self, loc_or_str, index=0, timeout=None): + def __call__(self, loc_or_str, index=1, timeout=None): """在内部查找元素 例:ele = page('@id=ele_id') :param loc_or_str: 元素的定位信息,可以是loc元组,或查询字符串 - :param index: 获取第几个,0开始 + :param index: 获取第几个,从1开始,可传入负数获取倒数第几个 :param timeout: 超时时间(秒) :return: 子元素对象 """ @@ -183,16 +183,17 @@ class WebPage(SessionPage, ChromiumPage, BasePage): return self.response return super().post(url, show_errmsg, retry, interval, **kwargs) - def ele(self, loc_or_ele, timeout=None): + def ele(self, loc_or_ele, index=1, timeout=None): """返回第一个符合条件的元素、属性或节点文本 :param loc_or_ele: 元素的定位信息,可以是元素对象,loc元组,或查询字符串 + :param index: 获取第几个,从1开始,可传入负数获取倒数第几个 :param timeout: 查找元素超时时间(秒),默认与页面等待时间一致 :return: 元素对象或属性、文本节点文本 """ if self._mode == 's': - return super().ele(loc_or_ele) + return super().ele(loc_or_ele, index=index) elif self._mode == 'd': - return super(SessionPage, self).ele(loc_or_ele, timeout=timeout) + return super(SessionPage, self).ele(loc_or_ele, index=index, timeout=timeout) def eles(self, loc_or_str, timeout=None): """返回页面中所有符合条件的元素、属性或节点文本 @@ -205,15 +206,16 @@ class WebPage(SessionPage, ChromiumPage, BasePage): elif self._mode == 'd': return super(SessionPage, self).eles(loc_or_str, timeout=timeout) - def s_ele(self, loc_or_ele=None): + def s_ele(self, loc_or_ele=None, index=1): """查找第一个符合条件的元素以SessionElement形式返回,d模式处理复杂页面时效率很高 :param loc_or_ele: 元素的定位信息,可以是loc元组,或查询字符串 + :param index: 获取第几个,从1开始,可传入负数获取倒数第几个 :return: SessionElement对象或属性、文本 """ if self._mode == 's': - return super().s_ele(loc_or_ele) + return super().s_ele(loc_or_ele, index=index) elif self._mode == 'd': - return super(SessionPage, self).s_ele(loc_or_ele) + return super(SessionPage, self).s_ele(loc_or_ele, index=index) def s_eles(self, loc_or_str): """查找所有符合条件的元素以SessionElement形式返回,d模式处理复杂页面时效率很高 @@ -361,11 +363,11 @@ class WebPage(SessionPage, ChromiumPage, BasePage): if self._response is not None: self._response.close() - def _find_elements(self, loc_or_ele, timeout=None, index=0, relative=False, raise_err=None): + def _find_elements(self, loc_or_ele, timeout=None, index=1, relative=False, raise_err=None): """返回页面中符合条件的元素、属性或节点文本,默认返回第一个 :param loc_or_ele: 元素的定位信息,可以是元素对象,loc元组,或查询字符串 :param timeout: 查找元素超时时间,d模式专用 - :param index: 第几个结果,0开始,为None返回所有 + :param index: 第几个结果,从1开始,可传入负数获取倒数第几个,为None返回所有 :param relative: WebPage用的表示是否相对定位的参数 :param raise_err: 找不到元素是是否抛出异常,为None时根据全局设置 :return: 元素对象或属性、文本节点文本 diff --git a/DrissionPage/_pages/web_page.pyi b/DrissionPage/_pages/web_page.pyi index 474e12a..607d130 100644 --- a/DrissionPage/_pages/web_page.pyi +++ b/DrissionPage/_pages/web_page.pyi @@ -38,7 +38,7 @@ class WebPage(SessionPage, ChromiumPage, BasePage): def __call__(self, loc_or_str: Union[Tuple[str, str], str, ChromiumElement, SessionElement], - index: int = 0, + index: int = 1, timeout: float = None) -> Union[ChromiumElement, SessionElement, NoneElement]: ... # -----------------共有属性和方法------------------- @@ -106,13 +106,16 @@ class WebPage(SessionPage, ChromiumPage, BasePage): def ele(self, loc_or_ele: Union[Tuple[str, str], str, ChromiumElement, SessionElement], + index: int = 1, timeout: float = None) -> Union[ChromiumElement, SessionElement, NoneElement]: ... def eles(self, loc_or_str: Union[Tuple[str, str], str], timeout: float = None) -> List[Union[ChromiumElement, SessionElement]]: ... - def s_ele(self, loc_or_ele: Union[Tuple[str, str], str] = None) -> Union[SessionElement, NoneElement]: ... + def s_ele(self, + loc_or_ele: Union[Tuple[str, str], str] = None, + index: int = 1) -> Union[SessionElement, NoneElement]: ... def s_eles(self, loc_or_str: Union[Tuple[str, str], str]) -> List[SessionElement]: ... @@ -168,7 +171,7 @@ class WebPage(SessionPage, ChromiumPage, BasePage): def _find_elements(self, loc_or_ele: Union[Tuple[str, str], str, ChromiumElement, SessionElement, ChromiumFrame], timeout: float = None, - index: Optional[int] = 0, + index: Optional[int] = 1, relative: bool = False, raise_err: bool = None) \ -> Union[ChromiumElement, SessionElement, ChromiumFrame, NoneElement, List[SessionElement], diff --git a/DrissionPage/_units/selector.py b/DrissionPage/_units/selector.py index 1b94ed7..9e7f721 100644 --- a/DrissionPage/_units/selector.py +++ b/DrissionPage/_units/selector.py @@ -97,7 +97,7 @@ class SelectElement(object): def by_index(self, index, timeout=None): """此方法用于根据index值选择项。当元素是多选列表时,可以接收list或tuple - :param index: 序号,0开始,传入list或tuple可选择多项 + :param index: 序号,从1开始,可传入负数获取倒数第几个,传入list或tuple可选择多项 :param timeout: 超时时间,为None默认使用页面超时时间 :return: 是否选择成功 """ @@ -136,7 +136,7 @@ class SelectElement(object): def cancel_by_index(self, index, timeout=None): """此方法用于根据index值取消选择项。当元素是多选列表时,可以接收list或tuple - :param index: 序号,0开始,传入list或tuple可取消多项 + :param index: 序号,从1开始,可传入负数获取倒数第几个,传入list或tuple可取消多项 :param timeout: 超时时间,不输入默认实用页面超时时间 :return: 是否取消成功 """ @@ -231,7 +231,7 @@ class SelectElement(object): """ ok = False condition = [int(i) for i in condition] - text_len = max(condition) + text_len = abs(max(condition, key=abs)) end_time = perf_counter() + timeout while perf_counter() < end_time: if len(self.options) >= text_len: @@ -240,7 +240,7 @@ class SelectElement(object): if ok: eles = self.options - eles = [eles[i - 1] for i in condition] + eles = [eles[i - 1] if i > 0 else eles[i] for i in condition] self._select_options(eles, mode) return True