继续研究text属性的格式,未完成

This commit is contained in:
g1879 2021-01-04 00:35:55 +08:00
parent c0bfdfa1e9
commit 89769f3caa
3 changed files with 78 additions and 21 deletions

View File

@ -5,7 +5,7 @@
@File : common.py
"""
from abc import abstractmethod
from html import unescape
# from html import unescape
from pathlib import Path
from re import split as re_SPLIT
from shutil import rmtree
@ -96,7 +96,12 @@ def str_to_loc(loc: str) -> tuple:
text:search_text - 文本含有search_text的元素 \n
text=search_text - 文本等于search_text的元素 \n
xpath://div[@class="ele_class"] - 用xpath查找 \n
css:div.ele_class - 用css selector查找
css:div.ele_class - 用css selector查找 \n
xpath://div[@class="ele_class"] - 等同于 x://div[@class="ele_class"] \n
css:div.ele_class - 等同于 c:div.ele_class \n
tag:div - 等同于 t:div \n
text:search_text - 等同于 tx:search_text \n
text=search_text - 等同于 tx=search_text \n
"""
loc_by = 'xpath'
@ -195,7 +200,7 @@ def _make_xpath_str(tag: str, arg: str, val: str, mode: str = 'fuzzy') -> str:
def _make_search_str(search_str: str) -> str:
""""转义,不知何故不能直接用\来转义 \n
""""转义,不知何故不能直接用 \ 来转义 \n
:param search_str: 查询字符串
:return: "转义后的字符串
"""
@ -212,9 +217,20 @@ def _make_search_str(search_str: str) -> str:
return search_str
def format_html(text: str) -> str:
def format_html(text: str, replace_space: bool = True) -> str:
"""处理html编码字符"""
return unescape(text) if text else text
if not text:
return text
# text = unescape(text)
# if '&' in text:
# html = unescape(text)
if replace_space:
text = text.replace('\xa0', ' ')
return text
def translate_loc(loc: tuple) -> tuple:

View File

@ -4,6 +4,7 @@
@Contact : g1879@qq.com
@File : driver_element.py
"""
import re
from pathlib import Path
from time import sleep
from typing import Union, List, Any, Tuple
@ -78,7 +79,13 @@ class DriverElement(DrissionElement):
@property
def text(self) -> str:
"""返回元素内所有文本"""
return self.attr('innerText')
# return self.inner_ele.get_attribute('innerText')
re_str = self.inner_ele.get_attribute('innerText')
re_str = re.sub(r'\n{2,}', '\n', re_str)
re_str = re.sub(r' {2,}', ' ', re_str)
return format_html(re_str.strip('\n '))
# return re_str.strip('\n ')
@property
def link(self) -> str:
@ -178,7 +185,10 @@ class DriverElement(DrissionElement):
:param attr: 属性名
:return: 属性值文本
"""
attr = 'innerText' if attr == 'text' else attr
# attr = 'innerText' if attr == 'text' else attr
if attr in ('text', 'innerText'):
return self.text
return format_html(self.inner_ele.get_attribute(attr))
def ele(self,
@ -188,7 +198,7 @@ class DriverElement(DrissionElement):
"""返回当前元素下级符合条件的子元素、属性或节点文本,默认返回第一个 \n
示例 \n
- 用loc元组查找 \n
ele.ele((By.CLASS_NAME, 'ele_class')) - 返回第一个class为ele_class的子元素 \n
ele.ele((By.CLASS_NAME, 'ele_class')) - 返回第一个class为ele_class的子元素 \n
- 用查询字符串查找 \n
查找方式属性tag name和属性文本xpathcss selectoridclass \n
@表示属性.表示class#表示id=表示精确匹配,:表示模糊匹配,无控制字符串时默认搜索该字符串 \n
@ -209,6 +219,12 @@ class DriverElement(DrissionElement):
ele.ele('text=some_text') - 返回第一个文本等于some_text的子元素 \n
ele.ele('xpath://div[@class="ele_class"]') - 返回第一个符合xpath的子元素 \n
ele.ele('css:div.ele_class') - 返回第一个符合css selector的子元素 \n
- 查询字符串还有最精简模式用x代替xpathc代替csst代替tagtx代替text \n
ele.ele('xpath://div[@class="ele_class"]') - 等同于 ele.ele('x://div[@class="ele_class"]') \n
ele.ele('css:div.ele_class') - 等同于 ele.ele('c:div.ele_class') \n
ele.ele('tag:div') - 等同于 ele.ele('t:div') \n
ele.ele('text:some_text') - 等同于 ele.ele('tx:some_text') \n
ele.ele('text=some_text') - 等同于 ele.ele('tx=some_text')
:param loc_or_str: 元素的定位信息可以是loc元组或查询字符串
:param mode: 'single' 'all'对应查找一个或全部
:param timeout: 查找元素超时时间
@ -244,7 +260,7 @@ class DriverElement(DrissionElement):
"""返回当前元素下级所有符合条件的子元素、属性或节点文本 \n
示例 \n
- 用loc元组查找 \n
ele.eles((By.CLASS_NAME, 'ele_class')) - 返回所有class为ele_class的子元素 \n
ele.eles((By.CLASS_NAME, 'ele_class')) - 返回所有class为ele_class的子元素 \n
- 用查询字符串查找 \n
查找方式属性tag name和属性文本xpathcss selectoridclass \n
@表示属性.表示class#表示id=表示精确匹配,:表示模糊匹配,无控制字符串时默认搜索该字符串 \n
@ -265,6 +281,12 @@ class DriverElement(DrissionElement):
ele.eles('text=some_text') - 返回所有文本等于some_text的子元素 \n
ele.eles('xpath://div[@class="ele_class"]') - 返回所有符合xpath的子元素 \n
ele.eles('css:div.ele_class') - 返回所有符合css selector的子元素 \n
- 查询字符串还有最精简模式用x代替xpathc代替csst代替tagtx代替text \n
ele.eles('xpath://div[@class="ele_class"]') - 等同于 ele.eles('x://div[@class="ele_class"]') \n
ele.eles('css:div.ele_class') - 等同于 ele.eles('c:div.ele_class') \n
ele.eles('tag:div') - 等同于 ele.eles('t:div') \n
ele.eles('text:some_text') - 等同于 ele.eles('tx:some_text') \n
ele.eles('text=some_text') - 等同于 ele.eles('tx=some_text')
:param loc_or_str: 元素的定位信息可以是loc元组或查询字符串
:param timeout: 查找元素超时时间
:return: DriverElement对象组成的列表
@ -574,7 +596,7 @@ def execute_driver_find(page_or_ele,
:return: 返回DriverElement元素或它们组成的列表
"""
mode = mode or 'single'
if mode not in ['single', 'all']:
if mode not in ('single', 'all'):
raise ValueError(f"Argument mode can only be 'single' or 'all', not '{mode}'.")
if isinstance(page_or_ele, DrissionElement):
@ -674,7 +696,7 @@ class ElementsByXpath(object):
else:
driver, the_node = ele_or_driver.parent, ele_or_driver
# 把lxml元素对象包装成DriverElement对象并按需要返回第一个或全部
# 把lxml元素对象包装成DriverElement对象并按需要返回第一个或全部
if self.mode == 'single':
try:
e = get_nodes(the_node, xpath_txt=self.xpath, type_txt='9')

View File

@ -36,9 +36,8 @@ class SessionElement(DrissionElement):
@property
def html(self) -> str:
"""返回元素outerHTML文本"""
# tostring()会把跟紧元素的文本节点也带上,因此要去掉
html = format_html(tostring(self._inner_ele, method="html").decode())
return format_html(html[:html.rfind('>') + 1])
return html[:html.rfind('>') + 1] # tostring()会把跟紧元素的文本节点也带上,因此要去掉
@property
def inner_html(self) -> str:
@ -50,26 +49,35 @@ class SessionElement(DrissionElement):
def text(self) -> str:
"""返回元素内所有文本"""
# re_str = str(self._inner_ele.text_content())
# # re_str = re.sub(r'<br */?>', '\n', re_str)
# re_str = re.sub(r'\n{2,}', '\n', re_str)
# re_str = re.sub(r' {2,}', ' ', re_str)
# return format_html(re_str.strip('\n '))
# # return format_html(re_str)
# 为尽量保证与浏览器结果一致,弄得比较复杂
def get_node(ele):
str_list = []
for el in ele.eles('xpath:./node()'):
if isinstance(el, str):
if el.replace(' ', '').replace('\n', '') != '':
str_list.append(el.replace('\xa0', '&nbsp;').replace('\n', ' ').strip())
# str_list.append(el.replace('\xa0', '&nbsp;').replace('\n', ' ').strip())
str_list.append(el.replace('\n', ' ').strip(' '))
elif '\n' in el:
str_list.append('\n')
else:
str_list.append(' ')
else:
str_list.extend(get_node(el))
if el.tag in ('br', 'p',):
str_list.append('\n')
return str_list
re_str = ''.join(get_node(self))
re_str = re.sub(r'\n{2,}', '\n', re_str)
re_str = re.sub(r' {2,}', ' ', re_str)
return format_html(re_str.strip('\n '))
@property
@ -176,7 +184,7 @@ class SessionElement(DrissionElement):
elif attr == 'src':
return self._make_absolute(self.inner_ele.get('src'))
elif attr in ['text', 'innerText']:
elif attr in ('text', 'innerText'):
return self.text
elif attr == 'outerHTML':
@ -189,10 +197,10 @@ class SessionElement(DrissionElement):
return self.inner_ele.get(attr)
def ele(self, loc_or_str: Union[Tuple[str, str], str], mode: str = None):
"""返回当前元素下级符合条件的子元素、属性或节点文本,默认返回第一个 \n
"""返回当前元素下级符合条件的子元素、属性或节点文本,默认返回第一个 \n
示例 \n
- 用loc元组查找 \n
ele.ele((By.CLASS_NAME, 'ele_class')) - 返回第一个class为ele_class的子元素 \n
ele.ele((By.CLASS_NAME, 'ele_class')) - 返回第一个class为ele_class的子元素 \n
- 用查询字符串查找 \n
查找方式属性tag name和属性文本xpathcss selectoridclass \n
@表示属性.表示class#表示id=表示精确匹配,:表示模糊匹配,无控制字符串时默认搜索该字符串 \n
@ -213,6 +221,12 @@ class SessionElement(DrissionElement):
ele.ele('text=some_text') - 返回第一个文本等于some_text的子元素 \n
ele.ele('xpath://div[@class="ele_class"]') - 返回第一个符合xpath的子元素 \n
ele.ele('css:div.ele_class') - 返回第一个符合css selector的子元素 \n
- 查询字符串还有最精简模式用x代替xpathc代替csst代替tagtx代替text \n
ele.ele('xpath://div[@class="ele_class"]') - 等同于 ele.ele('x://div[@class="ele_class"]') \n
ele.ele('css:div.ele_class') - 等同于 ele.ele('c:div.ele_class') \n
ele.ele('tag:div') - 等同于 ele.ele('t:div') \n
ele.ele('text:some_text') - 等同于 ele.ele('tx:some_text') \n
ele.ele('text=some_text') - 等同于 ele.ele('tx=some_text')
:param loc_or_str: 元素的定位信息可以是loc元组或查询字符串
:param mode: 'single' 'all对应查找一个或全部
:return: SessionElement对象
@ -246,7 +260,7 @@ class SessionElement(DrissionElement):
"""返回当前元素下级所有符合条件的子元素、属性或节点文本 \n
示例 \n
- 用loc元组查找 \n
ele.eles((By.CLASS_NAME, 'ele_class')) - 返回所有class为ele_class的子元素 \n
ele.eles((By.CLASS_NAME, 'ele_class')) - 返回所有class为ele_class的子元素 \n
- 用查询字符串查找 \n
查找方式属性tag name和属性文本xpathcss selectoridclass \n
@表示属性.表示class#表示id=表示精确匹配,:表示模糊匹配,无控制字符串时默认搜索该字符串 \n
@ -267,6 +281,12 @@ class SessionElement(DrissionElement):
ele.eles('text=some_text') - 返回所有文本等于some_text的子元素 \n
ele.eles('xpath://div[@class="ele_class"]') - 返回所有符合xpath的子元素 \n
ele.eles('css:div.ele_class') - 返回所有符合css selector的子元素 \n
- 查询字符串还有最精简模式用x代替xpathc代替csst代替tagtx代替text \n
ele.eles('xpath://div[@class="ele_class"]') - 等同于 ele.eles('x://div[@class="ele_class"]') \n
ele.eles('css:div.ele_class') - 等同于 ele.eles('c:div.ele_class') \n
ele.eles('tag:div') - 等同于 ele.eles('t:div') \n
ele.eles('text:some_text') - 等同于 ele.eles('tx:some_text') \n
ele.eles('text=some_text') - 等同于 ele.eles('tx=some_text')
:param loc_or_str: 元素的定位信息可以是loc元组或查询字符串
:return: SessionElement对象组成的列表
"""
@ -363,7 +383,7 @@ def execute_session_find(page_or_ele,
:return: 返回SessionElement元素或列表
"""
mode = mode or 'single'
if mode not in ['single', 'all']:
if mode not in ('single', 'all'):
raise ValueError(f"Argument mode can only be 'single' or 'all', not '{mode}'.")
# 根据传入对象类型获取页面对象和lxml元素对象
@ -372,7 +392,6 @@ def execute_session_find(page_or_ele,
page_or_ele = page_or_ele.inner_ele
else: # 传入的是SessionPage对象
page = page_or_ele
# page_or_ele = fromstring(format_html(page_or_ele.response.text, False))
page_or_ele = fromstring(page_or_ele.response.text)
try: