mirror of
https://gitee.com/g1879/DrissionPage.git
synced 2024-12-10 04:00:23 +08:00
完成视觉相对定位;定位语法增加tag()
This commit is contained in:
parent
de75793b94
commit
b8aa656f45
@ -351,6 +351,21 @@ class ChromiumElement(DrissionElement):
|
||||
else:
|
||||
return NoneElement(page=self.owner, method='on()', args={'timeout': timeout})
|
||||
|
||||
def offset(self, offset_x, offset_y):
|
||||
"""获取相对本元素左上角左边指定偏移量位置的元素
|
||||
:param offset_x: 横坐标偏移量,向右为正
|
||||
:param offset_y: 纵坐标偏移量,向下为正
|
||||
:return: 元素对象
|
||||
"""
|
||||
x, y = self.rect.location
|
||||
try:
|
||||
return ChromiumElement(owner=self.owner,
|
||||
backend_id=self.owner.run_cdp('DOM.getNodeForLocation', x=x + offset_x,
|
||||
y=y + offset_y, includeUserAgentShadowDOM=True,
|
||||
ignorePointerEventsNone=False)['backendNodeId'])
|
||||
except CDPError:
|
||||
return NoneElement(page=self.owner, method='offset()', args={'offset_x': offset_x, 'offset_y': offset_y})
|
||||
|
||||
def east(self, locator=None, index=1):
|
||||
"""获取元素右边某个指定元素
|
||||
:param locator: 定位符,只支持str,且不支持xpath和css方式,传入int按像素距离获取
|
||||
@ -433,7 +448,6 @@ class ChromiumElement(DrissionElement):
|
||||
value = -3 if minus else 3
|
||||
size = self.owner.rect.size
|
||||
max_len = size[0] if mode == 'east' else size[1]
|
||||
# loc_data = {'tag': None, 'and': True, 'args': [('属性名称', '匹配内容', '匹配方式', '是否否定')]}
|
||||
loc_data = locator_to_tuple(locator) if locator else None
|
||||
curr_ele = None
|
||||
while 0 < cdp_data[variable] < max_len:
|
||||
@ -444,13 +458,12 @@ class ChromiumElement(DrissionElement):
|
||||
continue
|
||||
else:
|
||||
curr_ele = bid
|
||||
ele = self.owner.run_cdp('DOM.describeNode', backendNodeId=bid)['node']
|
||||
ele = ChromiumElement(self.owner, backend_id=bid)
|
||||
|
||||
# print(ele)
|
||||
if loc_data is None: # todo
|
||||
if loc_data is None or _check_ele(ele, loc_data):
|
||||
num += 1
|
||||
if num == index:
|
||||
return ChromiumElement(owner=self.owner, backend_id=bid)
|
||||
return ele
|
||||
except:
|
||||
pass
|
||||
|
||||
@ -1634,3 +1647,59 @@ class Pseudo(object):
|
||||
def after(self):
|
||||
"""返回当前元素的::after伪元素内容"""
|
||||
return self._ele.style('content', 'after')
|
||||
|
||||
|
||||
def _check_ele(ele, loc_data):
|
||||
"""检查元素是否符合loc_data指定的要求
|
||||
:param ele: 元素对象
|
||||
:param loc_data: 格式: {'and': bool, 'args': ['属性名称', '匹配方式', '属性值', 是否否定]}
|
||||
:return: bool
|
||||
"""
|
||||
attrs = ele.attrs
|
||||
if loc_data['and']:
|
||||
ok = True
|
||||
for i in loc_data['args']:
|
||||
name, symbol, value, deny = i
|
||||
if name == 'tag()':
|
||||
arg = ele.tag
|
||||
symbol = '='
|
||||
elif name == 'text()':
|
||||
arg = ele.raw_text
|
||||
elif name is None:
|
||||
arg = None
|
||||
else:
|
||||
arg = attrs.get(name, '')
|
||||
|
||||
if ((symbol == '=' and ((deny and arg == value) or (not deny and arg != value)))
|
||||
or (symbol == ':' and ((deny and value in arg) or (not deny and value not in arg)))
|
||||
or (symbol == '^' and ((deny and arg.startswith(value))
|
||||
or (not deny and not arg.startswith(value))))
|
||||
or (symbol == '$' and ((deny and arg.endswith(value)) or (not deny and not arg.endswith(value))))
|
||||
or (arg is None and attrs)):
|
||||
ok = False
|
||||
break
|
||||
|
||||
else:
|
||||
ok = False
|
||||
for i in loc_data['args']:
|
||||
name, value, symbol, deny = i
|
||||
if name == 'tag()':
|
||||
arg = ele.tag
|
||||
symbol = '='
|
||||
elif name == 'text()':
|
||||
arg = ele.text
|
||||
elif name is None:
|
||||
arg = None
|
||||
else:
|
||||
arg = attrs.get(name, '')
|
||||
|
||||
if ((symbol == '=' and ((not deny and arg == value) or (deny and arg != value)))
|
||||
or (symbol == ':' and ((not deny and value in arg) or (deny and value not in arg)))
|
||||
or (symbol == '^' and ((not deny and arg.startswith(value))
|
||||
or (deny and not arg.startswith(value))))
|
||||
or (symbol == '$' and ((not deny and arg.endswith(value)) or (deny and not arg.endswith(value))))
|
||||
or (arg is None and not attrs)):
|
||||
ok = True
|
||||
break
|
||||
|
||||
return ok
|
||||
|
@ -8,128 +8,79 @@
|
||||
from re import split
|
||||
from .by import By
|
||||
|
||||
格式 = {
|
||||
'and': True,
|
||||
'args': ('属性名称', '属性值', '匹配方式', '是否否定')
|
||||
}
|
||||
|
||||
|
||||
def locator_to_tuple(loc):
|
||||
"""解析定位字符串生成dict格式数据
|
||||
:param loc: 待处理的字符串
|
||||
:return: 格式: {'and': bool, 'args': ['属性名称', '匹配方式', '属性值', 是否否定]}
|
||||
"""
|
||||
loc = _preprocess(loc)
|
||||
# todo
|
||||
|
||||
# 多属性查找
|
||||
if loc.startswith(('@@', '@|', '@!')) and loc not in ('@@', '@|', '@!'):
|
||||
loc_str = _make_multi_xpath_str('*', loc)[1]
|
||||
args = _get_args(loc)
|
||||
|
||||
# 单属性查找
|
||||
elif loc.startswith('@') and loc != '@':
|
||||
loc_str = _make_single_xpath_str('*', loc)[1]
|
||||
arg = _get_arg(loc[1:])
|
||||
arg.append(False)
|
||||
args = {'and': True, 'args': [arg]}
|
||||
|
||||
# 根据tag name查找
|
||||
elif loc.startswith(('tag:', 'tag=')) and loc not in ('tag:', 'tag='):
|
||||
elif loc.startswith(('tag:', 'tag=', 'tag^', 'tag$')) and loc not in ('tag:', 'tag=', 'tag^', 'tag$'):
|
||||
at_ind = loc.find('@')
|
||||
if at_ind == -1:
|
||||
loc_str = f'//*[name()="{loc[4:]}"]'
|
||||
elif loc[at_ind:].startswith(('@@', '@|', '@!')):
|
||||
loc_str = _make_multi_xpath_str(loc[4:at_ind], loc[at_ind:])[1]
|
||||
args = {'and': True, 'args': [['tag()', '=', loc[4:].lower(), False]]}
|
||||
else:
|
||||
loc_str = _make_single_xpath_str(loc[4:at_ind], loc[at_ind:])[1]
|
||||
args_str = loc[at_ind:]
|
||||
if args_str.startswith(('@@', '@|', '@!')):
|
||||
args = _get_args(args_str)
|
||||
args['args'].append([f'tag()', '=', loc[4:at_ind].lower(), False])
|
||||
else: # t:div@aa=bb的格式
|
||||
arg = _get_arg(loc[at_ind + 1:])
|
||||
arg.append(False)
|
||||
args = {'and': True, 'args': [['tag()', '=', loc[4:at_ind].lower(), False], arg]}
|
||||
|
||||
# 根据文本查找
|
||||
elif loc.startswith('text='):
|
||||
loc_str = f'//*[text()={_make_search_str(loc[5:])}]'
|
||||
elif loc.startswith('text:') and loc != 'text:':
|
||||
loc_str = f'//*/text()[contains(., {_make_search_str(loc[5:])})]/..'
|
||||
elif loc.startswith('text^') and loc != 'text^':
|
||||
loc_str = f'//*/text()[starts-with(., {_make_search_str(loc[5:])})]/..'
|
||||
elif loc.startswith('text$') and loc != 'text$':
|
||||
loc_str = f'//*/text()[substring(., string-length(.) - string-length({_make_search_str(loc[5:])}) +1) = ' \
|
||||
f'{_make_search_str(loc[5:])}]/..'
|
||||
|
||||
# 用xpath查找
|
||||
elif loc.startswith(('xpath:', 'xpath=')) and loc not in ('xpath:', 'xpath='):
|
||||
loc_str = loc[6:]
|
||||
elif loc.startswith(('x:', 'x=')) and loc not in ('x:', 'x='):
|
||||
loc_str = loc[2:]
|
||||
|
||||
# 用css selector查找
|
||||
elif loc.startswith(('css:', 'css=')) and loc not in ('css:', 'css='):
|
||||
loc_by = 'css selector'
|
||||
loc_str = loc[4:]
|
||||
elif loc.startswith(('c:', 'c=')) and loc not in ('c:', 'c='):
|
||||
loc_by = 'css selector'
|
||||
loc_str = loc[2:]
|
||||
elif loc.startswith(('text=', 'text:', 'text^', 'text$')):
|
||||
args = {'and': True, 'args': [['text()', loc[4], loc[5:], False]]}
|
||||
|
||||
# 根据文本模糊查找
|
||||
elif loc:
|
||||
loc_str = f'//*/text()[contains(., {_make_search_str(loc)})]/..'
|
||||
else:
|
||||
loc_str = '//*'
|
||||
args = {'and': True, 'args': [['text()', '=', loc, False]]}
|
||||
|
||||
return {}
|
||||
return args
|
||||
|
||||
|
||||
def _get_args(tag: str = None, text: str = '') -> tuple:
|
||||
"""生成多属性查找的xpath语句
|
||||
:param tag: 标签名
|
||||
def _get_args(text: str = '') -> dict:
|
||||
"""解析定位参数字符串生成dict格式数据
|
||||
:param text: 待处理的字符串
|
||||
:return: xpath字符串
|
||||
:return: 格式: {'and': bool, 'args': ['属性名称', '匹配方式', '属性值', 是否否定]}
|
||||
"""
|
||||
# todo
|
||||
arg_list = []
|
||||
args = split(r'(@!|@@|@\|)', text)[1:]
|
||||
if '@@' in args and '@|' in args:
|
||||
raise ValueError('@@和@|不能同时出现在一个定位语句中。')
|
||||
elif '@@' in args:
|
||||
_and = True
|
||||
else: # @|
|
||||
_and = False
|
||||
_and = '@|' not in args
|
||||
|
||||
for k in range(0, len(args) - 1, 2):
|
||||
r = split(r'([:=$^])', args[k + 1], maxsplit=1)
|
||||
arg_str = ''
|
||||
len_r = len(r)
|
||||
arg = _get_arg(args[k + 1])
|
||||
if arg:
|
||||
arg.append(True if args[k] == '@!' else False) # 是否去除某个属性
|
||||
arg_list.append(arg)
|
||||
|
||||
if not r[0]: # 不查询任何属性
|
||||
arg_str = 'not(@*)'
|
||||
return {'and': _and, 'args': arg_list}
|
||||
|
||||
else:
|
||||
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]}'
|
||||
|
||||
elif len_r == 3: # 属性名和内容都有
|
||||
arg = '.' if r[0] in ('text()', 'tx()') else f'@{r[0]}'
|
||||
symbol = r[1]
|
||||
if symbol == '=':
|
||||
arg_str = f'{arg}={_make_search_str(r[2])}'
|
||||
|
||||
elif symbol == ':':
|
||||
arg_str = f'contains({arg},{_make_search_str(r[2])})'
|
||||
|
||||
elif symbol == '^':
|
||||
arg_str = f'starts-with({arg},{_make_search_str(r[2])})'
|
||||
|
||||
elif symbol == '$':
|
||||
arg_str = f'substring({arg}, string-length({arg}) - string-length({_make_search_str(r[2])}) +1) ' \
|
||||
f'= {_make_search_str(r[2])}'
|
||||
|
||||
else:
|
||||
raise ValueError(f'符号不正确:{symbol}')
|
||||
|
||||
if arg_str and ignore:
|
||||
arg_str = f'not({arg_str})'
|
||||
|
||||
if arg_str:
|
||||
arg_list.append(arg_str)
|
||||
|
||||
arg_str = ' and '.join(arg_list) if _and else ' or '.join(arg_list)
|
||||
if tag != '*':
|
||||
condition = f' and ({arg_str})' if arg_str else ''
|
||||
arg_str = f'name()="{tag}"{condition}'
|
||||
|
||||
return 'xpath', f'//*[{arg_str}]' if arg_str else f'//*'
|
||||
def _get_arg(text) -> list:
|
||||
"""解析arg=abc格式字符串,生成格式:['属性名称', '匹配方式', '属性值', 是否否定],不是式子的返回None"""
|
||||
r = split(r'([:=$^])', text, maxsplit=1)
|
||||
if not r[0]:
|
||||
return [None, None, None, None]
|
||||
# !=时只有属性名没有属性内容,查询是否存在该属性
|
||||
name = r[0] if r[0] != 'tx()' else 'text()'
|
||||
name = name if name != 't()' else 'teg()'
|
||||
return [name, None, None] if len(r) != 3 else [name, r[1], r[2]]
|
||||
|
||||
|
||||
def is_loc(text):
|
||||
@ -183,7 +134,7 @@ def str_to_xpath_loc(loc):
|
||||
loc_str = _make_single_xpath_str('*', loc)[1]
|
||||
|
||||
# 根据tag name查找
|
||||
elif loc.startswith(('tag:', 'tag=')) and loc not in ('tag:', 'tag='):
|
||||
elif loc.startswith(('tag:', 'tag=', 'tag^', 'tag$')) and loc not in ('tag:', 'tag=', 'tag^', 'tag$'):
|
||||
at_ind = loc.find('@')
|
||||
if at_ind == -1:
|
||||
loc_str = f'//*[name()="{loc[4:]}"]'
|
||||
@ -206,16 +157,11 @@ def str_to_xpath_loc(loc):
|
||||
# 用xpath查找
|
||||
elif loc.startswith(('xpath:', 'xpath=')) and loc not in ('xpath:', 'xpath='):
|
||||
loc_str = loc[6:]
|
||||
elif loc.startswith(('x:', 'x=')) and loc not in ('x:', 'x='):
|
||||
loc_str = loc[2:]
|
||||
|
||||
# 用css selector查找
|
||||
elif loc.startswith(('css:', 'css=')) and loc not in ('css:', 'css='):
|
||||
loc_by = 'css selector'
|
||||
loc_str = loc[4:]
|
||||
elif loc.startswith(('c:', 'c=')) and loc not in ('c:', 'c='):
|
||||
loc_by = 'css selector'
|
||||
loc_str = loc[2:]
|
||||
|
||||
# 根据文本模糊查找
|
||||
elif loc:
|
||||
@ -243,7 +189,7 @@ def str_to_css_loc(loc):
|
||||
loc_by, loc_str = _make_single_css_str('*', loc)
|
||||
|
||||
# 根据tag name查找
|
||||
elif loc.startswith(('tag:', 'tag=')) and loc not in ('tag:', 'tag='):
|
||||
elif loc.startswith(('tag:', 'tag=', 'tag^', 'tag$')) and loc not in ('tag:', 'tag=', 'tag^', 'tag$'):
|
||||
at_ind = loc.find('@')
|
||||
if at_ind == -1:
|
||||
loc_str = loc[4:]
|
||||
@ -253,14 +199,12 @@ def str_to_css_loc(loc):
|
||||
loc_by, loc_str = _make_single_css_str(loc[4:at_ind], loc[at_ind:])
|
||||
|
||||
# 根据文本查找
|
||||
elif loc.startswith(('text=', 'text:', 'text^', 'text$', 'xpath=', 'xpath:', 'x:', 'x=')):
|
||||
elif loc.startswith(('text=', 'text:', 'text^', 'text$', 'xpath=', 'xpath:')):
|
||||
loc_by, loc_str = str_to_xpath_loc(loc)
|
||||
|
||||
# 用css selector查找
|
||||
elif loc.startswith(('css:', 'css=')) and loc not in ('css:', 'css='):
|
||||
loc_str = loc[4:]
|
||||
elif loc.startswith(('c:', 'c=')) and loc not in ('c:', 'c='):
|
||||
loc_str = loc[2:]
|
||||
|
||||
# 根据文本模糊查找
|
||||
elif loc:
|
||||
@ -289,39 +233,45 @@ def _make_single_xpath_str(tag: str, text: str) -> tuple:
|
||||
len_r = len(r)
|
||||
len_r0 = len(r[0])
|
||||
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 == '^': # 匹配开头
|
||||
if r[0] in ('@text()', '@tx()'):
|
||||
txt_str = f'/text()[starts-with(., {_make_search_str(r[2])})]/..'
|
||||
arg_str = ''
|
||||
else:
|
||||
arg_str = f"starts-with({r[0]},{_make_search_str(r[2])})"
|
||||
|
||||
elif symbol == '$': # 匹配结尾
|
||||
if r[0] in ('@text()', '@tx()'):
|
||||
txt_str = f'/text()[substring(., string-length(.) - string-length({_make_search_str(r[2])}) +1) ' \
|
||||
f'= {_make_search_str(r[2])}]/..'
|
||||
arg_str = ''
|
||||
else:
|
||||
arg_str = f'substring({r[0]}, string-length({r[0]}) - string-length({_make_search_str(r[2])}) +1)' \
|
||||
f' = {_make_search_str(r[2])}'
|
||||
|
||||
elif symbol == ':': # 模糊查找
|
||||
if r[0] in ('@text()', '@tx()'):
|
||||
txt_str = f'/text()[contains(., {_make_search_str(r[2])})]/..'
|
||||
arg_str = ''
|
||||
else:
|
||||
arg_str = f"contains({r[0]},{_make_search_str(r[2])})"
|
||||
|
||||
if r[0] in ('@tag()', '@t()'):
|
||||
arg_str = f'name()="{r[2].lower()}"'
|
||||
else:
|
||||
raise ValueError(f'符号不正确:{symbol}')
|
||||
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 == '^': # 匹配开头
|
||||
if r[0] in ('@text()', '@tx()'):
|
||||
txt_str = f'/text()[starts-with(., {_make_search_str(r[2])})]/..'
|
||||
arg_str = ''
|
||||
else:
|
||||
arg_str = f"starts-with({r[0]},{_make_search_str(r[2])})"
|
||||
|
||||
elif symbol == '$': # 匹配结尾
|
||||
if r[0] in ('@text()', '@tx()'):
|
||||
txt_str = (f'/text()[substring(., string-length(.) - string-length({_make_search_str(r[2])}) '
|
||||
f'+1) = {_make_search_str(r[2])}]/..')
|
||||
arg_str = ''
|
||||
else:
|
||||
arg_str = (f'substring({r[0]}, string-length({r[0]}) - string-length({_make_search_str(r[2])}) '
|
||||
f'+1) = {_make_search_str(r[2])}')
|
||||
|
||||
elif symbol == ':': # 模糊查找
|
||||
if r[0] in ('@text()', '@tx()'):
|
||||
txt_str = f'/text()[contains(., {_make_search_str(r[2])})]/..'
|
||||
arg_str = ''
|
||||
else:
|
||||
arg_str = f"contains({r[0]},{_make_search_str(r[2])})"
|
||||
|
||||
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 r[0] in ('@tag()', '@t()'):
|
||||
arg_str = ''
|
||||
else:
|
||||
arg_str = 'normalize-space(text())' if r[0] in ('@text()', '@tx()') else f'{r[0]}'
|
||||
|
||||
if arg_str:
|
||||
arg_list.append(arg_str)
|
||||
@ -339,10 +289,9 @@ def _make_multi_xpath_str(tag: str, text: str) -> tuple:
|
||||
args = split(r'(@!|@@|@\|)', text)[1:]
|
||||
if '@@' in args and '@|' in args:
|
||||
raise ValueError('@@和@|不能同时出现在一个定位语句中。')
|
||||
elif '@@' in args:
|
||||
_and = True
|
||||
else: # @|
|
||||
_and = False
|
||||
_and = '@|' not in args
|
||||
tags = [] if tag == '*' else [f'name()="{tag}"']
|
||||
tags_connect = ' or '
|
||||
|
||||
for k in range(0, len(args) - 1, 2):
|
||||
r = split(r'([:=$^])', args[k + 1], maxsplit=1)
|
||||
@ -355,23 +304,39 @@ def _make_multi_xpath_str(tag: str, text: str) -> tuple:
|
||||
else:
|
||||
ignore = True if args[k] == '@!' else False # 是否去除某个属性
|
||||
if len_r != 3: # 只有属性名没有属性内容,查询是否存在该属性
|
||||
if r[0] in ('tag()', 't()'):
|
||||
continue
|
||||
arg_str = 'normalize-space(text())' if r[0] in ('text()', 'tx()') else f'@{r[0]}'
|
||||
|
||||
elif len_r == 3: # 属性名和内容都有
|
||||
arg = '.' if r[0] in ('text()', 'tx()') else f'@{r[0]}'
|
||||
if r[0] in ('tag()', 't()'):
|
||||
if ignore:
|
||||
tags.append(f'not(name()="{r[2]}")')
|
||||
tags_connect = ' and '
|
||||
else:
|
||||
tags.append(f'name()="{r[2]}"')
|
||||
continue
|
||||
|
||||
symbol = r[1]
|
||||
if r[0] in ('text()', 'tx()'):
|
||||
arg = '.'
|
||||
txt = r[2]
|
||||
else:
|
||||
arg = f'@{r[0]}'
|
||||
txt = r[2]
|
||||
|
||||
if symbol == '=':
|
||||
arg_str = f'{arg}={_make_search_str(r[2])}'
|
||||
arg_str = f'{arg}={_make_search_str(txt)}'
|
||||
|
||||
elif symbol == ':':
|
||||
arg_str = f'contains({arg},{_make_search_str(r[2])})'
|
||||
arg_str = f'contains({arg},{_make_search_str(txt)})'
|
||||
|
||||
elif symbol == '^':
|
||||
arg_str = f'starts-with({arg},{_make_search_str(r[2])})'
|
||||
arg_str = f'starts-with({arg},{_make_search_str(txt)})'
|
||||
|
||||
elif symbol == '$':
|
||||
arg_str = f'substring({arg}, string-length({arg}) - string-length({_make_search_str(r[2])}) +1) ' \
|
||||
f'= {_make_search_str(r[2])}'
|
||||
arg_str = f'substring({arg}, string-length({arg}) - string-length({_make_search_str(txt)}) +1) ' \
|
||||
f'= {_make_search_str(txt)}'
|
||||
|
||||
else:
|
||||
raise ValueError(f'符号不正确:{symbol}')
|
||||
@ -383,9 +348,9 @@ def _make_multi_xpath_str(tag: str, text: str) -> tuple:
|
||||
arg_list.append(arg_str)
|
||||
|
||||
arg_str = ' and '.join(arg_list) if _and else ' or '.join(arg_list)
|
||||
if tag != '*':
|
||||
if tags:
|
||||
condition = f' and ({arg_str})' if arg_str else ''
|
||||
arg_str = f'name()="{tag}"{condition}'
|
||||
arg_str = f'({tags_connect.join(tags)}){condition}'
|
||||
|
||||
return 'xpath', f'//*[{arg_str}]' if arg_str else f'//*'
|
||||
|
||||
@ -417,10 +382,7 @@ def _make_multi_css_str(tag: str, text: str) -> tuple:
|
||||
args = split(r'(@!|@@|@\|)', text)[1:]
|
||||
if '@@' in args and '@|' in args:
|
||||
raise ValueError('@@和@|不能同时出现在一个定位语句中。')
|
||||
elif '@@' in args:
|
||||
_and = True
|
||||
else: # @|
|
||||
_and = False
|
||||
_and = '@|' not in args
|
||||
|
||||
for k in range(0, len(args) - 1, 2):
|
||||
r = split(r'([:=$^])', args[k + 1], maxsplit=1)
|
||||
@ -431,9 +393,18 @@ def _make_multi_css_str(tag: str, text: str) -> tuple:
|
||||
len_r = len(r)
|
||||
ignore = True if args[k] == '@!' else False # 是否去除某个属性
|
||||
if len_r != 3: # 只有属性名没有属性内容,查询是否存在该属性
|
||||
if r[0] in ('tag()', 't()'):
|
||||
continue
|
||||
arg_str = f'[{r[0]}]'
|
||||
|
||||
elif len_r == 3: # 属性名和内容都有
|
||||
if r[0] in ('tag()', 't()'):
|
||||
if tag == '*':
|
||||
tag = f':not({r[2].lower()})' if ignore else f'{r[2]}'
|
||||
else:
|
||||
tag += f',:not({r[2].lower()})' if ignore else f',{r[2]}'
|
||||
continue
|
||||
|
||||
d = {'=': '', '^': '^', '$': '$', ':': '*'}
|
||||
arg_str = f'[{r[0]}{d[r[1]]}={css_trans(r[2])}]'
|
||||
|
||||
@ -459,6 +430,9 @@ def _make_single_css_str(tag: str, text: str) -> tuple:
|
||||
return _make_single_xpath_str(tag, text)
|
||||
|
||||
r = split(r'([:=$^])', text, maxsplit=1)
|
||||
if r[0] in ('@tag()', '@t()'):
|
||||
return 'css selector', r[2]
|
||||
|
||||
if len(r) == 3:
|
||||
d = {'=': '', '^': '^', '$': '$', ':': '*'}
|
||||
arg_str = f'[{r[0][1:]}{d[r[1]]}={css_trans(r[2])}]'
|
||||
@ -581,4 +555,10 @@ def _preprocess(loc):
|
||||
elif loc.startswith(('tx:', 'tx=', 'tx^', 'tx$')):
|
||||
loc = f'text{loc[2:]}'
|
||||
|
||||
elif loc.startswith(('c:', 'c=')):
|
||||
loc = f'css:{loc[2:]}'
|
||||
|
||||
elif loc.startswith(('x:', 'x=')):
|
||||
loc = f'xpath:{loc[2:]}'
|
||||
|
||||
return loc
|
||||
|
@ -20,6 +20,9 @@ def get_loc(loc: Union[tuple, str], translate_css: bool = False, css_mode: bool
|
||||
def str_to_xpath_loc(loc: str) -> tuple: ...
|
||||
|
||||
|
||||
def str_to_css_loc(loc: str) -> tuple: ...
|
||||
|
||||
|
||||
def translate_loc(loc: tuple) -> tuple: ...
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user