@@改为@&,@@-改为@!;增加css方式的定位符解析

This commit is contained in:
g1879 2023-11-24 01:40:22 +08:00
parent 75f05062fb
commit e3f654ce12
4 changed files with 120 additions and 39 deletions

View File

@ -173,12 +173,12 @@ class Browser(object):
end_time = perf_counter() + timeout
while perf_counter() < end_time:
p = popen(txt)
sleep(.1)
try:
if f' {self.process_id} ' not in p.read():
return
except TypeError:
return
sleep(.2)
pass
if force:
ip, port = self.address.split(':')

View File

@ -16,7 +16,7 @@ def is_loc(text):
def get_loc(loc, translate_css=False, css_mode=False):
"""接收本库定位语法或selenium定位元组转换为标准定位元组可翻译css selector为xpath
:param loc: 本库定位语法或selenium定位元组
:param translate_css: 是否翻译css selector为xpath
:param translate_css: 是否翻译css selector为xpath用于相对定位
:param css_mode: 是否尽量用css selector方式
:return: DrissionPage定位元组
"""
@ -24,7 +24,7 @@ def get_loc(loc, translate_css=False, css_mode=False):
loc = translate_css_loc(loc) if css_mode else translate_loc(loc)
elif isinstance(loc, str):
loc = str_to_css_loc(loc) if css_mode else str_to_loc(loc)
loc = str_to_css_loc(loc) if css_mode else str_to_xpath_loc(loc)
else:
raise TypeError('loc参数只能是tuple或str。')
@ -41,7 +41,7 @@ def get_loc(loc, translate_css=False, css_mode=False):
return loc
def str_to_loc(loc):
def str_to_xpath_loc(loc):
"""处理元素查找语句
:param loc: 查找语法字符串
:return: 匹配符元组
@ -68,15 +68,24 @@ def str_to_loc(loc):
# ------------------------------------------------------------------
# 多属性查找
if loc.startswith('@@') and loc != '@@':
loc_str = _make_multi_xpath_str('*', loc)
if loc.startswith('@!') and loc != '@!':
r = split(r'(@!|@&|@\|)', loc)
if '@&' in r and '@|' in r:
raise ValueError('@&和@|不能同时出现在一个定位语句中。')
elif '@&' in r:
loc_str = _make_multi_xpath_str('*', loc)[1]
else: # @|
loc_str = _make_multi_xpath_str('*', loc, False)[1]
elif loc.startswith('@&') and loc != '@&':
loc_str = _make_multi_xpath_str('*', loc)[1]
elif loc.startswith('@|') and loc != '@|':
loc_str = _make_multi_xpath_str('*', loc, False)
loc_str = _make_multi_xpath_str('*', loc, False)[1]
# 单属性查找
elif loc.startswith('@') and loc != '@':
loc_str = _make_single_xpath_str('*', loc)
loc_str = _make_single_xpath_str('*', loc)[1]
# 根据tag name查找
elif loc.startswith(('tag:', 'tag=')) and loc not in ('tag:', 'tag='):
@ -84,12 +93,12 @@ def str_to_loc(loc):
if at_ind == -1:
loc_str = f'//*[name()="{loc[4:]}"]'
else:
if loc[at_ind:].startswith('@@'):
loc_str = _make_multi_xpath_str(loc[4:at_ind], loc[at_ind:])
if loc[at_ind:].startswith(('@&', '@!')):
loc_str = _make_multi_xpath_str(loc[4:at_ind], loc[at_ind:])[1]
elif loc[at_ind:].startswith('@|'):
loc_str = _make_multi_xpath_str(loc[4:at_ind], loc[at_ind:], False)
loc_str = _make_multi_xpath_str(loc[4:at_ind], loc[at_ind:], False)[1]
else:
loc_str = _make_single_xpath_str(loc[4:at_ind], loc[at_ind:])
loc_str = _make_single_xpath_str(loc[4:at_ind], loc[at_ind:])[1]
# 根据文本查找
elif loc.startswith('text='):
@ -133,7 +142,6 @@ def str_to_css_loc(loc):
:param loc: 查找语法字符串
:return: 匹配符元组
"""
return str_to_loc(loc)
loc_by = 'css selector'
if loc.startswith('.'):
@ -156,15 +164,24 @@ def str_to_css_loc(loc):
# ------------------------------------------------------------------
# 多属性查找
if loc.startswith('@@') and loc != '@@':
loc_str = _make_multi_xpath_str('*', loc)
if loc.startswith('@!') and loc != '@!':
r = split(r'(@!|@&|@\|)', loc)
if '@&' in r and '@|' in r:
raise ValueError('@&和@|不能同时出现在一个定位语句中。')
elif '@&' in r:
loc_by, loc_str = _make_multi_css_str('*', loc)
else: # @|
loc_by, loc_str = _make_multi_css_str('*', loc, False)
elif loc.startswith('@&') and loc != '@&':
loc_by, loc_str = _make_multi_css_str('*', loc)
elif loc.startswith('@|') and loc != '@|':
loc_str = _make_multi_xpath_str('*', loc, False)
loc_by, loc_str = _make_multi_css_str('*', loc, False)
# 单属性查找
elif loc.startswith('@') and loc != '@':
loc_str = _make_single_xpath_str('*', loc)
loc_by, loc_str = _make_single_css_str('*', loc)
# 根据tag name查找
elif loc.startswith(('tag:', 'tag=')) and loc not in ('tag:', 'tag='):
@ -172,12 +189,12 @@ def str_to_css_loc(loc):
if at_ind == -1:
loc_str = loc[4:]
else:
if loc[at_ind:].startswith('@@'):
loc_str = _make_multi_xpath_str(loc[4:at_ind], loc[at_ind:])
if loc[at_ind:].startswith(('@&', '@!')):
loc_by, loc_str = _make_multi_css_str(loc[4:at_ind], loc[at_ind:])
elif loc[at_ind:].startswith('@|'):
loc_str = _make_multi_xpath_str(loc[4:at_ind], loc[at_ind:], False)
loc_by, loc_str = _make_multi_css_str(loc[4:at_ind], loc[at_ind:], False)
else:
loc_str = _make_single_xpath_str(loc[4:at_ind], loc[at_ind:])
loc_by, loc_str = _make_single_css_str(loc[4:at_ind], loc[at_ind:])
# 根据文本查找
elif loc.startswith('text='):
@ -222,8 +239,8 @@ def str_to_css_loc(loc):
return loc_by, loc_str
def _make_single_xpath_str(tag: str, text: str) -> str:
"""生成xpath语句
def _make_single_xpath_str(tag: str, text: str) -> tuple:
"""生成单属性xpath语句
:param tag: 标签名
:param text: 待处理的字符串
:return: xpath字符串
@ -238,16 +255,13 @@ def _make_single_xpath_str(tag: str, text: str) -> str:
r = split(r'([:=$^])', text, maxsplit=1)
len_r = len(r)
len_r0 = len(r[0])
if len_r != 3 and len_r0 > 1:
arg_str = 'normalize-space(text())' if r[0] in ('@text()', '@tx()') else f'{r[0]}'
elif len_r == 3 and len_r0 > 1:
if len_r == 3 and len_r0 > 1:
symbol = r[1]
if symbol == '=': # 精确查找
arg = '.' if r[0] in ('@text()', '@tx()') else r[0]
arg_str = f'{arg}={_make_search_str(r[2])}'
elif symbol == '^': # 开头开头
elif symbol == '^': # 匹配开头
if r[0] in ('@text()', '@tx()'):
txt_str = f'/text()[starts-with(., {_make_search_str(r[2])})]/..'
arg_str = ''
@ -273,13 +287,16 @@ def _make_single_xpath_str(tag: str, text: str) -> str:
else:
raise ValueError(f'符号不正确:{symbol}')
elif len_r != 3 and len_r0 > 1:
arg_str = 'normalize-space(text())' if r[0] in ('@text()', '@tx()') else f'{r[0]}'
if arg_str:
arg_list.append(arg_str)
arg_str = ' and '.join(arg_list)
return f'//*[{arg_str}]{txt_str}' if arg_str else f'//*{txt_str}'
return 'xpath', f'//*[{arg_str}]{txt_str}' if arg_str else f'//*{txt_str}'
def _make_multi_xpath_str(tag: str, text: str, _and: bool = True) -> str:
def _make_multi_xpath_str(tag: str, text: str, _and: bool = True) -> tuple:
"""生成多属性查找的xpath语句
:param tag: 标签名
:param text: 待处理的字符串
@ -287,10 +304,12 @@ def _make_multi_xpath_str(tag: str, text: str, _and: bool = True) -> str:
:return: xpath字符串
"""
arg_list = []
args = text.split('@@') if _and else text.split('@|')
args = split(r'(@!|@&)', text)[1:] if _and else split(r'(@!|@\|)', text)[1:]
if (_and and '@|' in args) or (not _and and '@&' in args):
raise ValueError('@&和@|不能同时出现在一个定位语句中。')
for arg in args[1:]:
r = split(r'([:=$^])', arg, maxsplit=1)
for k in range(0, len(args) - 1, 2):
r = split(r'([:=$^])', args[k + 1], maxsplit=1)
arg_str = ''
len_r = len(r)
@ -298,8 +317,7 @@ def _make_multi_xpath_str(tag: str, text: str, _and: bool = True) -> str:
arg_str = 'not(@*)'
else:
r[0], ignore = (r[0][1:], True) if r[0][0] == '-' else (r[0], None) # 是否去除某个属性
ignore = True if args[k] == '@!' else False # 是否去除某个属性
if len_r != 3: # 只有属性名没有属性内容,查询是否存在该属性
arg_str = 'normalize-space(text())' if r[0] in ('text()', 'tx()') else f'@{r[0]}'
@ -333,7 +351,7 @@ def _make_multi_xpath_str(tag: str, text: str, _and: bool = True) -> str:
condition = f' and ({arg_str})' if arg_str else ''
arg_str = f'name()="{tag}"{condition}'
return f'//*[{arg_str}]' if arg_str else f'//*'
return 'xpath', f'//*[{arg_str}]' if arg_str else f'//*'
def _make_search_str(search_str: str) -> str:
@ -353,6 +371,65 @@ def _make_search_str(search_str: str) -> str:
return search_str
def _make_multi_css_str(tag: str, text: str, _and: bool = True) -> tuple:
"""生成多属性查找的css selector语句
:param tag: 标签名
:param text: 待处理的字符串
:param _and: 是否与方式
:return: css selector字符串
"""
arg_list = []
args = split(r'(@!|@&)', text)[1:] if _and else split(r'(@!|@\|)', text)[1:]
if (_and and '@|' in args) or (not _and and '@&' in args):
raise ValueError('@&和@|不能同时出现在一个定位语句中。')
for k in range(0, len(args)-1, 2):
r = split(r'([:=$^])', args[k+1], maxsplit=1)
if not r[0] or r[0].startswith(('text()', 'tx()')):
return _make_multi_xpath_str(tag, text, _and)
arg_str = ''
len_r = len(r)
ignore = True if args[k] == '@!' else False # 是否去除某个属性
if len_r != 3: # 只有属性名没有属性内容,查询是否存在该属性
arg_str = f'[{r[0]}]'
elif len_r == 3: # 属性名和内容都有
d = {'=': '', '^': '^', '$': '$', ':': '*'}
arg_str = f'[{r[0]}{d[r[1]]}={css_trans(r[2])}]'
if arg_str and ignore:
arg_str = f':not({arg_str})'
if arg_str:
arg_list.append(arg_str)
if _and:
return 'css selector', f'{tag}{"".join(arg_list)}'
return 'css selector', f'{tag}{("," + tag).join(arg_list)}'
def _make_single_css_str(tag: str, text: str) -> tuple:
"""生成单属性css selector语句
:param tag: 标签名
:param text: 待处理的字符串
:return: css selector字符串
"""
if text == '@' or text.startswith(('@text()', '@tx()')):
return _make_single_xpath_str(tag, text)
r = split(r'([:=$^])', text, maxsplit=1)
if len(r) == 3:
d = {'=': '', '^': '^', '$': '$', ':': '*'}
arg_str = f'[{r[0][1:]}{d[r[1]]}={css_trans(r[2])}]'
else:
arg_str = f'[{css_trans(r[0][1:])}]'
return 'css selector', f'{tag}{arg_str}'
def translate_loc(loc):
"""把By类型的loc元组转换为css selector或xpath类型的
:param loc: By类型的loc元组

View File

@ -12,7 +12,7 @@ def is_loc(text: str) -> bool: ...
def get_loc(loc: Union[tuple, str], translate_css: bool = False, css_mode: bool = False) -> tuple: ...
def str_to_loc(loc: str) -> tuple: ...
def str_to_xpath_loc(loc: str) -> tuple: ...
def translate_loc(loc: tuple) -> tuple: ...

View File

@ -1029,7 +1029,7 @@ class ChromiumShadowRoot(BaseElement):
result = None
timeout = timeout if timeout is not None else self.page.timeout
end_time = perf_counter() + timeout
while not result and perf_counter() <= end_time:
while perf_counter() <= end_time:
if loc[0] == 'css selector':
if single:
nod_id = self.page.run_cdp('DOM.querySelector', nodeId=self._node_id, selector=loc[1])['nodeId']
@ -1057,6 +1057,10 @@ class ChromiumShadowRoot(BaseElement):
if node_id:
result.append(make_chromium_ele(self.page, node_id=node_id))
if result:
break
sleep(.1)
return result
def _get_node_id(self, obj_id):