ShadowRootElement补足DOM相对定位方法;修复相对定位时用文本查找导致的错误;完善类型注解

This commit is contained in:
g1879 2022-01-21 14:39:58 +08:00
parent 2be7ed6154
commit c077aa0c2e
6 changed files with 321 additions and 37 deletions

View File

@ -69,10 +69,10 @@ class BaseElement(BaseParser):
def parent(self, level_or_loc: Union[tuple, str, int] = 1):
pass
def prev(self, index: int = 1):
def prev(self, index: int = 1) -> None:
return None # ShadowRootElement直接继承
def prevs(self):
def prevs(self) -> None:
return None # ShadowRootElement直接继承
def next(self, index: int = 1):
@ -117,10 +117,10 @@ class DrissionElement(BaseElement):
return [format_html(x.strip(' ').rstrip('\n')) for x in texts if x and sub('[\r\n\t ]', '', x) != '']
def parent(self, level_or_loc: Union[tuple, str, int] = 1) -> 'DrissionElement':
def parent(self, level_or_loc: Union[tuple, str, int] = 1) -> Union['DrissionElement', None]:
"""返回上面某一级父元素,可指定层数或用查询语法定位 \n
:param level_or_loc: 第几级父元素或定位符
:return: DriverElement对象
:return: 上级元素对象
"""
if isinstance(level_or_loc, int):
loc = f'xpath:./ancestor::*[{level_or_loc}]'
@ -138,43 +138,36 @@ class DrissionElement(BaseElement):
return self.ele(loc, timeout=0)
def prev(self, index: int = 1, filter_loc: Union[tuple, str] = '', timeout: float = 0):
def prev(self,
index: int = 1,
filter_loc: Union[tuple, str] = '',
timeout: float = 0) -> Union['DrissionElement', str, None]:
"""返回前面的一个兄弟元素,可用查询语法筛选,可指定返回筛选结果的第几个 \n
:param index: 前面第几个查询结果元素
:param filter_loc: 用于筛选元素的查询语法
:param timeout: 查找元素的超时时间
:return: 兄弟元素或节点文本组成的列表
:return: 兄弟元素
"""
nodes = self._get_brothers(index, filter_loc, 'preceding', timeout=timeout)
return nodes[-1] if nodes else None
def next(self, index: int = 1, filter_loc: Union[tuple, str] = '', timeout: float = 0):
def next(self,
index: int = 1,
filter_loc: Union[tuple, str] = '',
timeout: float = 0) -> Union['DrissionElement', str, None]:
"""返回后面的一个兄弟元素,可用查询语法筛选,可指定返回筛选结果的第几个 \n
:param index: 后面第几个查询结果元素
:param filter_loc: 用于筛选元素的查询语法
:param timeout: 查找元素的超时时间
:return: 兄弟元素或节点文本组成的列表
:return: 兄弟元素
"""
nodes = self._get_brothers(index, filter_loc, 'following', timeout=timeout)
return nodes[0] if nodes else None
def nexts(self, filter_loc: Union[tuple, str] = '', timeout: float = 0):
"""返回后面全部兄弟元素或节点组成的列表,可用查询语法筛选 \n
:param filter_loc: 用于筛选元素的查询语法
:param timeout: 查找元素的超时时间
:return: 兄弟元素或节点文本组成的列表
"""
return self._get_brothers(filter_loc=filter_loc, direction='following', timeout=timeout)
def prevs(self, filter_loc: Union[tuple, str] = '', timeout: float = 0):
"""返回前面全部兄弟元素或节点组成的列表,可用查询语法筛选 \n
:param filter_loc: 用于筛选元素的查询语法
:param timeout: 查找元素的超时时间
:return: 兄弟元素或节点文本组成的列表
"""
return self._get_brothers(filter_loc=filter_loc, direction='preceding', timeout=timeout)
def before(self, index: int = 1, filter_loc: Union[tuple, str] = '', timeout: float = None):
def before(self,
index: int = 1,
filter_loc: Union[tuple, str] = '',
timeout: float = None) -> Union['DrissionElement', str, None]:
"""返回前面的一个兄弟元素,可用查询语法筛选,可指定返回筛选结果的第几个 \n
:param index: 前面第几个查询结果元素
:param filter_loc: 用于筛选元素的查询语法
@ -184,7 +177,10 @@ class DrissionElement(BaseElement):
nodes = self._get_brothers(index, filter_loc, 'preceding', False, timeout=timeout)
return nodes[-1] if nodes else None
def after(self, index: int = 1, filter_loc: Union[tuple, str] = '', timeout: float = None):
def after(self,
index: int = 1,
filter_loc: Union[tuple, str] = '',
timeout: float = None) -> Union['DrissionElement', str, None]:
"""返回后面的一个兄弟元素,可用查询语法筛选,可指定返回筛选结果的第几个 \n
:param index: 后面第几个查询结果元素
:param filter_loc: 用于筛选元素的查询语法
@ -194,7 +190,29 @@ class DrissionElement(BaseElement):
nodes = self._get_brothers(index, filter_loc, 'following', False, timeout)
return nodes[0] if nodes else None
def befores(self, filter_loc: Union[tuple, str] = '', timeout: float = None):
def prevs(self,
filter_loc: Union[tuple, str] = '',
timeout: float = 0) -> List[Union['DrissionElement', str]]:
"""返回前面全部兄弟元素或节点组成的列表,可用查询语法筛选 \n
:param filter_loc: 用于筛选元素的查询语法
:param timeout: 查找元素的超时时间
:return: 兄弟元素或节点文本组成的列表
"""
return self._get_brothers(filter_loc=filter_loc, direction='preceding', timeout=timeout)
def nexts(self,
filter_loc: Union[tuple, str] = '',
timeout: float = 0) -> List[Union['DrissionElement', str]]:
"""返回后面全部兄弟元素或节点组成的列表,可用查询语法筛选 \n
:param filter_loc: 用于筛选元素的查询语法
:param timeout: 查找元素的超时时间
:return: 兄弟元素或节点文本组成的列表
"""
return self._get_brothers(filter_loc=filter_loc, direction='following', timeout=timeout)
def befores(self,
filter_loc: Union[tuple, str] = '',
timeout: float = None) -> List[Union['DrissionElement', str]]:
"""返回后面全部兄弟元素或节点组成的列表,可用查询语法筛选 \n
:param filter_loc: 用于筛选元素的查询语法
:param timeout: 查找元素的超时时间
@ -202,7 +220,9 @@ class DrissionElement(BaseElement):
"""
return self._get_brothers(filter_loc=filter_loc, direction='preceding', brother=False, timeout=timeout)
def afters(self, filter_loc: Union[tuple, str] = '', timeout: float = None):
def afters(self,
filter_loc: Union[tuple, str] = '',
timeout: float = None) -> List[Union['DrissionElement', str]]:
"""返回前面全部兄弟元素或节点组成的列表,可用查询语法筛选 \n
:param filter_loc: 用于筛选元素的查询语法
:param timeout: 查找元素的超时时间
@ -215,7 +235,7 @@ class DrissionElement(BaseElement):
filter_loc: Union[tuple, str] = '',
direction: str = 'following',
brother: bool = True,
timeout: float = .5) -> List['DrissionElement']:
timeout: float = .5) -> List[Union['DrissionElement', str]]:
"""按要求返回兄弟元素或节点组成的列表 \n
:param index: 获取第几个该参数不为None时只获取该编号的元素
:param filter_loc: 用于筛选元素的查询语法
@ -238,15 +258,18 @@ class DrissionElement(BaseElement):
raise ValueError('此css selector语法不受支持请换成xpath。')
loc = loc[1].lstrip('./')
if index:
loc = f'xpath:./{direction}{brother}::{loc}[{index}]'
else:
loc = f'xpath:./{direction}{brother}::{loc}'
loc = f'xpath:./{direction}{brother}::{loc}'
nodes = self._ele(loc, timeout=timeout, single=False)
nodes = [e for e in nodes if not (isinstance(e, str) and sub('[ \n\t\r]', '', e) == '')]
return nodes
if nodes and index is not None:
try:
return [nodes[index - 1]]
except IndexError:
return []
else:
return nodes
# ----------------以下属性或方法由后代实现----------------
@property

View File

@ -248,6 +248,101 @@ class DriverElement(DrissionElement):
self._scroll = Scroll(self)
return self._scroll
def parent(self, level_or_loc: Union[tuple, str, int] = 1) -> Union['DriverElement', None]:
"""返回上面某一级父元素,可指定层数或用查询语法定位 \n
:param level_or_loc: 第几级父元素或定位符
:return: 上级元素对象
"""
return super().parent(level_or_loc)
def prev(self,
index: int = 1,
filter_loc: Union[tuple, str] = '',
timeout: float = 0) -> Union['DriverElement', str, None]:
"""返回前面的一个兄弟元素,可用查询语法筛选,可指定返回筛选结果的第几个 \n
:param index: 前面第几个查询结果元素
:param filter_loc: 用于筛选元素的查询语法
:param timeout: 查找元素的超时时间
:return: 兄弟元素
"""
return super().prev(index, filter_loc, timeout)
def next(self,
index: int = 1,
filter_loc: Union[tuple, str] = '',
timeout: float = 0) -> Union['DriverElement', str, None]:
"""返回后面的一个兄弟元素,可用查询语法筛选,可指定返回筛选结果的第几个 \n
:param index: 后面第几个查询结果元素
:param filter_loc: 用于筛选元素的查询语法
:param timeout: 查找元素的超时时间
:return: 兄弟元素
"""
return super().next(index, filter_loc, timeout)
def before(self,
index: int = 1,
filter_loc: Union[tuple, str] = '',
timeout: float = None) -> Union['DriverElement', str, None]:
"""返回前面的一个兄弟元素,可用查询语法筛选,可指定返回筛选结果的第几个 \n
:param index: 前面第几个查询结果元素
:param filter_loc: 用于筛选元素的查询语法
:param timeout: 查找元素的超时时间
:return: 本元素前面的某个元素或节点
"""
return super().before(index, filter_loc, timeout)
def after(self,
index: int = 1,
filter_loc: Union[tuple, str] = '',
timeout: float = None) -> Union['DriverElement', str, None]:
"""返回后面的一个兄弟元素,可用查询语法筛选,可指定返回筛选结果的第几个 \n
:param index: 后面第几个查询结果元素
:param filter_loc: 用于筛选元素的查询语法
:param timeout: 查找元素的超时时间
:return: 本元素后面的某个元素或节点
"""
return super().after(index, filter_loc, timeout)
def prevs(self,
filter_loc: Union[tuple, str] = '',
timeout: float = 0) -> List[Union['DriverElement', str]]:
"""返回前面全部兄弟元素或节点组成的列表,可用查询语法筛选 \n
:param filter_loc: 用于筛选元素的查询语法
:param timeout: 查找元素的超时时间
:return: 兄弟元素或节点文本组成的列表
"""
return super().prevs(filter_loc, timeout)
def nexts(self,
filter_loc: Union[tuple, str] = '',
timeout: float = 0) -> List[Union['DriverElement', str]]:
"""返回后面全部兄弟元素或节点组成的列表,可用查询语法筛选 \n
:param filter_loc: 用于筛选元素的查询语法
:param timeout: 查找元素的超时时间
:return: 兄弟元素或节点文本组成的列表
"""
return super().nexts(filter_loc, timeout)
def befores(self,
filter_loc: Union[tuple, str] = '',
timeout: float = None) -> List[Union['DriverElement', str]]:
"""返回后面全部兄弟元素或节点组成的列表,可用查询语法筛选 \n
:param filter_loc: 用于筛选元素的查询语法
:param timeout: 查找元素的超时时间
:return: 本元素前面的元素或节点组成的列表
"""
return super().befores(filter_loc, timeout)
def afters(self,
filter_loc: Union[tuple, str] = '',
timeout: float = None) -> List[Union['DriverElement', str]]:
"""返回前面全部兄弟元素或节点组成的列表,可用查询语法筛选 \n
:param filter_loc: 用于筛选元素的查询语法
:param timeout: 查找元素的超时时间
:return: 本元素后面的元素或节点组成的列表
"""
return super().afters(filter_loc, timeout)
def left(self, index: int = 1, filter_loc: Union[tuple, str] = '') -> 'DriverElement':
"""获取网页上显示在当前元素左边的某个元素,可设置选取条件,可指定结果中第几个 \n
:param index: 获取第几个

View File

@ -72,6 +72,101 @@ class SessionElement(DrissionElement):
"""返回未格式化处理的元素内文本"""
return str(self._inner_ele.text_content())
def parent(self, level_or_loc: Union[tuple, str, int] = 1) -> Union['SessionElement', None]:
"""返回上面某一级父元素,可指定层数或用查询语法定位 \n
:param level_or_loc: 第几级父元素或定位符
:return: 上级元素对象
"""
return super().parent(level_or_loc)
def prev(self,
index: int = 1,
filter_loc: Union[tuple, str] = '',
timeout: float = 0) -> Union['SessionElement', str, None]:
"""返回前面的一个兄弟元素,可用查询语法筛选,可指定返回筛选结果的第几个 \n
:param index: 前面第几个查询结果元素
:param filter_loc: 用于筛选元素的查询语法
:param timeout: 查找元素的超时时间
:return: 兄弟元素
"""
return super().prev(index, filter_loc, timeout)
def next(self,
index: int = 1,
filter_loc: Union[tuple, str] = '',
timeout: float = 0) -> Union['SessionElement', str, None]:
"""返回后面的一个兄弟元素,可用查询语法筛选,可指定返回筛选结果的第几个 \n
:param index: 后面第几个查询结果元素
:param filter_loc: 用于筛选元素的查询语法
:param timeout: 查找元素的超时时间
:return: 兄弟元素
"""
return super().next(index, filter_loc, timeout)
def before(self,
index: int = 1,
filter_loc: Union[tuple, str] = '',
timeout: float = None) -> Union['SessionElement', str, None]:
"""返回前面的一个兄弟元素,可用查询语法筛选,可指定返回筛选结果的第几个 \n
:param index: 前面第几个查询结果元素
:param filter_loc: 用于筛选元素的查询语法
:param timeout: 查找元素的超时时间
:return: 本元素前面的某个元素或节点
"""
return super().before(index, filter_loc, timeout)
def after(self,
index: int = 1,
filter_loc: Union[tuple, str] = '',
timeout: float = None) -> Union['SessionElement', str, None]:
"""返回后面的一个兄弟元素,可用查询语法筛选,可指定返回筛选结果的第几个 \n
:param index: 后面第几个查询结果元素
:param filter_loc: 用于筛选元素的查询语法
:param timeout: 查找元素的超时时间
:return: 本元素后面的某个元素或节点
"""
return super().after(index, filter_loc, timeout)
def prevs(self,
filter_loc: Union[tuple, str] = '',
timeout: float = 0) -> List[Union['SessionElement', str]]:
"""返回前面全部兄弟元素或节点组成的列表,可用查询语法筛选 \n
:param filter_loc: 用于筛选元素的查询语法
:param timeout: 查找元素的超时时间
:return: 兄弟元素或节点文本组成的列表
"""
return super().prevs(filter_loc, timeout)
def nexts(self,
filter_loc: Union[tuple, str] = '',
timeout: float = 0) -> List[Union['SessionElement', str]]:
"""返回后面全部兄弟元素或节点组成的列表,可用查询语法筛选 \n
:param filter_loc: 用于筛选元素的查询语法
:param timeout: 查找元素的超时时间
:return: 兄弟元素或节点文本组成的列表
"""
return super().nexts(filter_loc, timeout)
def befores(self,
filter_loc: Union[tuple, str] = '',
timeout: float = None) -> List[Union['SessionElement', str]]:
"""返回后面全部兄弟元素或节点组成的列表,可用查询语法筛选 \n
:param filter_loc: 用于筛选元素的查询语法
:param timeout: 查找元素的超时时间
:return: 本元素前面的元素或节点组成的列表
"""
return super().befores(filter_loc, timeout)
def afters(self,
filter_loc: Union[tuple, str] = '',
timeout: float = None) -> List[Union['SessionElement', str]]:
"""返回前面全部兄弟元素或节点组成的列表,可用查询语法筛选 \n
:param filter_loc: 用于筛选元素的查询语法
:param timeout: 查找元素的超时时间
:return: 本元素后面的元素或节点组成的列表
"""
return super().afters(filter_loc, timeout)
def attr(self, attr: str) -> Union[str, None]:
"""返回attribute属性值 \n
:param attr: 属性名

View File

@ -72,7 +72,9 @@ class ShadowRootElement(BaseElement):
return self.parent_ele.ele(loc, timeout=0)
def next(self, index: int = 1, filter_loc: Union[tuple, str] = '') -> Union[DriverElement, None]:
def next(self,
index: int = 1,
filter_loc: Union[tuple, str] = '') -> Union[DriverElement, str, None]:
"""返回后面的一个兄弟元素,可用查询语法筛选,可指定返回筛选结果的第几个 \n
:param index: 第几个查询结果元素
:param filter_loc: 用于筛选元素的查询语法
@ -81,7 +83,28 @@ class ShadowRootElement(BaseElement):
nodes = self.nexts(filter_loc=filter_loc)
return nodes[index - 1] if nodes else None
def nexts(self, filter_loc: Union[tuple, str] = '') -> List[DriverElement]:
def before(self,
index: int = 1,
filter_loc: Union[tuple, str] = '') -> Union[DriverElement, str, None]:
"""返回前面的一个兄弟元素,可用查询语法筛选,可指定返回筛选结果的第几个 \n
:param index: 前面第几个查询结果元素
:param filter_loc: 用于筛选元素的查询语法
:return: 本元素前面的某个元素或节点
"""
nodes = self.befores(filter_loc=filter_loc)
return nodes[index - 1] if nodes else None
def after(self, index: int = 1,
filter_loc: Union[tuple, str] = '') -> Union[DriverElement, str, None]:
"""返回后面的一个兄弟元素,可用查询语法筛选,可指定返回筛选结果的第几个 \n
:param index: 后面第几个查询结果元素
:param filter_loc: 用于筛选元素的查询语法
:return: 本元素后面的某个元素或节点
"""
nodes = self.afters(filter_loc=filter_loc)
return nodes[index - 1] if nodes else None
def nexts(self, filter_loc: Union[tuple, str] = '') -> List[Union[DriverElement, str]]:
"""返回后面所有兄弟元素或节点组成的列表 \n
:param filter_loc: 用于筛选元素的查询语法
:return: DriverElement对象组成的列表
@ -94,6 +117,29 @@ class ShadowRootElement(BaseElement):
xpath = f'xpath:./{loc}'
return self.parent_ele.eles(xpath, timeout=0.1)
def befores(self, filter_loc: Union[tuple, str] = '') -> List[Union[DriverElement, str]]:
"""返回后面全部兄弟元素或节点组成的列表,可用查询语法筛选 \n
:param filter_loc: 用于筛选元素的查询语法
:return: 本元素前面的元素或节点组成的列表
"""
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}'
return self.parent_ele.eles(xpath, timeout=0.1)
def afters(self, filter_loc: Union[tuple, str] = '') -> List[Union[DriverElement, str]]:
"""返回前面全部兄弟元素或节点组成的列表,可用查询语法筛选 \n
:param filter_loc: 用于筛选元素的查询语法
:return: 本元素后面的元素或节点组成的列表
"""
eles1 = self.nexts(filter_loc)
loc = get_loc(filter_loc, True)[1].lstrip('./')
xpath = f'xpath:./following::{loc}'
return eles1 + self.parent_ele.eles(xpath, timeout=0.1)
def ele(self,
loc_or_str: Union[Tuple[str, str], str],
timeout: float = None) -> Union[DriverElement, str, None]:

View File

@ -882,6 +882,31 @@ eles = ele1.nears()
divs = ele1.nears('tag:div')
```
# `ShadowRootElement`相关查找
本库把 shadow-root 也作为元素对象看待,是为`ShadowRootElement`对象。对`ShadowRootElement`对象可与普通元素一样查找下级元素和 DOM 内相对定位,但不能用页面布局相对定位。
`ShadowRootElement`对象进行相对定位时,把它看作其父对象内部的第一个对象,其余定位逻辑与普通对象一致。
!> **注意:** <br>
如果`ShadowRootElement`元素的下级元素中有其它`ShadowRootElement`元素,那这些下级`ShadowRootElement`元素内部是无法直接通过定位语句查找到的,只能先定位到其父元素,再用`shadow-root`属性获取。
```python
# 获取一个 shadow-root 元素
sr_ele = page.ele('#app').shadow_root
# 在该元素下查找下级元素
ele1 = sr_ele.ele('tag:div')
# 用相对定位获取其它元素
ele1 = sr_ele.parent(2)
ele1 = sr_ele.next(1, 'tag:div')
ele1 = sr_ele.after(1, 'tag:div')
eles = sr_ele.nexts('tag:div')
# 定位下级元素中的 shadow+-root 元素
sr_ele2 = sr_ele.ele('tag:div').shadow_root
```
# 简化写法
为进一步精简代码,对语法进行了精简

View File

@ -6,7 +6,7 @@ with open("README.md", "r", encoding='utf-8') as fh:
setup(
name="DrissionPage",
version="2.4.1",
version="2.4.2",
author="g1879",
author_email="g1879@qq.com",
description="A module that integrates selenium and requests session, encapsulates common page operations.",