适配新版浏览器的的ShadowRoot;在shadow root下查找元素现在可用完全版的定位语句

This commit is contained in:
g1879 2021-12-21 17:28:46 +08:00
parent 9e6e2cb264
commit 38ed85edb8

View File

@ -4,7 +4,6 @@
@Contact : g1879@qq.com
@File : shadow_root_element.py
"""
from re import split as re_SPLIT
from typing import Union, Any, Tuple, List
from selenium.webdriver.remote.webelement import WebElement
@ -43,8 +42,13 @@ class ShadowRootElement(BaseElement):
@property
def html(self) -> str:
return f'<shadow_root>{self.inner_html}</shadow_root>'
@property
def inner_html(self) -> str:
"""返回内部的html文本"""
return self.inner_ele.get_attribute('innerHTML')
shadow_root = WebElement(self.page.driver, self.inner_ele._id)
return shadow_root.get_attribute('innerHTML')
def parent(self, level_or_loc: Union[str, int] = 1) -> DriverElement:
"""返回上面某一级父元素,可指定层数或用查询语法定位 \n
@ -133,21 +137,18 @@ class ShadowRootElement(BaseElement):
:param single: True则返回第一个False则返回全部
:return: DriverElement对象
"""
if isinstance(loc_or_str, str):
loc_or_str = str_to_css_loc(loc_or_str)
# 先转换为sessionElement再获取所有元素获取它们的css selector路径再用路径在页面上执行查找
eles = make_session_ele(self.html).eles(loc_or_str)
elif isinstance(loc_or_str, tuple) and len(loc_or_str) == 2:
if loc_or_str[0] == 'xpath':
raise ValueError('不支持xpath。')
if not eles:
return None if single else []
css_paths = [i.css_path[47:] for i in eles]
if single:
return make_driver_ele(self, f'css:{css_paths[0]}', single, timeout)
else:
raise ValueError('loc_or_str参数只能是tuple或str类型。')
if loc_or_str[0] == 'css selector':
return make_driver_ele(self, loc_or_str, single, timeout)
elif loc_or_str[0] == 'text':
return self._find_eles_by_text(loc_or_str[1], loc_or_str[2], loc_or_str[3], single)
return [make_driver_ele(self, f'css:{css}', True, timeout) for css in css_paths]
def run_script(self, script: str, *args) -> Any:
"""执行js代码传入自己为第一个参数 \n
@ -155,7 +156,8 @@ class ShadowRootElement(BaseElement):
:param args: 传入的参数
:return: js执行结果
"""
return self.inner_ele.parent.execute_script(script, self.inner_ele, *args)
shadow_root = WebElement(self.page.driver, self.inner_ele._id)
return shadow_root.parent.execute_script(script, shadow_root, *args)
def is_enabled(self) -> bool:
"""是否可用"""
@ -166,6 +168,7 @@ class ShadowRootElement(BaseElement):
try:
self.is_enabled()
return True
except Exception:
return False
@ -214,76 +217,3 @@ class ShadowRootElement(BaseElement):
results.append(DriverElement(ele, self.page))
return None if single else results
def str_to_css_loc(loc: str) -> tuple:
"""处理元素查找语句 \n
查找方式属性tag name及属性文本css selector \n
@表示属性.表示class#表示id=表示精确匹配,:表示模糊匹配,无控制字符串时默认搜索该字符串 \n
"""
loc_by = 'css selector'
# .和#替换为class和id查找
if loc.startswith('.'):
if loc.startswith(('.=', '.:',)):
loc = loc.replace('.', '@class', 1)
else:
loc = loc.replace('.', '@class=', 1)
elif loc.startswith('#'):
if loc.startswith(('#=', '#:',)):
loc = loc.replace('#', '@id', 1)
else:
loc = loc.replace('#', '@id=', 1)
elif loc.startswith(('t:', 't=')):
loc = f'tag:{loc[2:]}'
elif loc.startswith(('tx:', 'tx=')):
loc = f'text{loc[2:]}'
elif loc.startswith(('x:', 'x=', 'xpath:', 'xpath=')):
raise ValueError('不支持xpath。')
# 根据属性查找
if loc.startswith('@'):
r = re_SPLIT(r'([:=])', loc[1:], maxsplit=1)
if len(r) == 3:
mode = '=' if r[1] == '=' else '*='
loc_str = f'*[{r[0]}{mode}{r[2]}]'
else:
loc_str = f'*[{loc[1:]}]'
# 根据tag name查找
elif loc.startswith(('tag=', 'tag:')):
if '@' not in loc[4:]:
loc_str = f'{loc[4:]}'
else:
at_lst = loc[4:].split('@', maxsplit=1)
r = re_SPLIT(r'([:=])', at_lst[1], maxsplit=1)
if len(r) == 3:
if r[0] in ('text()', 'tx()'):
match = 'exact' if r[1] == '=' else 'fuzzy'
return 'text', r[2], at_lst[0], match
mode = '=' if r[1] == '=' else '*='
loc_str = f'{at_lst[0]}[{r[0]}{mode}"{r[2]}"]'
else:
loc_str = f'{at_lst[0]}[{r[0]}]'
# 用css selector查找
elif loc.startswith(('css=', 'css:')):
loc_str = loc[4:]
# 根据文本查找
elif loc.startswith(('text=', 'text:')):
match = 'exact' if loc[4] == '=' else 'fuzzy'
return 'text', loc[5:], '', match
# 根据文本模糊查找
else:
return 'text', loc, '', 'fuzzy'
return loc_by, loc_str