继续研究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 @File : common.py
""" """
from abc import abstractmethod from abc import abstractmethod
from html import unescape # from html import unescape
from pathlib import Path from pathlib import Path
from re import split as re_SPLIT from re import split as re_SPLIT
from shutil import rmtree 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
text=search_text - 文本等于search_text的元素 \n text=search_text - 文本等于search_text的元素 \n
xpath://div[@class="ele_class"] - 用xpath查找 \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' loc_by = 'xpath'
@ -212,9 +217,20 @@ def _make_search_str(search_str: str) -> str:
return search_str return search_str
def format_html(text: str) -> str: def format_html(text: str, replace_space: bool = True) -> str:
"""处理html编码字符""" """处理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: def translate_loc(loc: tuple) -> tuple:

View File

@ -4,6 +4,7 @@
@Contact : g1879@qq.com @Contact : g1879@qq.com
@File : driver_element.py @File : driver_element.py
""" """
import re
from pathlib import Path from pathlib import Path
from time import sleep from time import sleep
from typing import Union, List, Any, Tuple from typing import Union, List, Any, Tuple
@ -78,7 +79,13 @@ class DriverElement(DrissionElement):
@property @property
def text(self) -> str: 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 @property
def link(self) -> str: def link(self) -> str:
@ -178,7 +185,10 @@ class DriverElement(DrissionElement):
:param attr: 属性名 :param attr: 属性名
:return: 属性值文本 :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)) return format_html(self.inner_ele.get_attribute(attr))
def ele(self, def ele(self,
@ -209,6 +219,12 @@ class DriverElement(DrissionElement):
ele.ele('text=some_text') - 返回第一个文本等于some_text的子元素 \n ele.ele('text=some_text') - 返回第一个文本等于some_text的子元素 \n
ele.ele('xpath://div[@class="ele_class"]') - 返回第一个符合xpath的子元素 \n ele.ele('xpath://div[@class="ele_class"]') - 返回第一个符合xpath的子元素 \n
ele.ele('css:div.ele_class') - 返回第一个符合css selector的子元素 \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 loc_or_str: 元素的定位信息可以是loc元组或查询字符串
:param mode: 'single' 'all'对应查找一个或全部 :param mode: 'single' 'all'对应查找一个或全部
:param timeout: 查找元素超时时间 :param timeout: 查找元素超时时间
@ -265,6 +281,12 @@ class DriverElement(DrissionElement):
ele.eles('text=some_text') - 返回所有文本等于some_text的子元素 \n ele.eles('text=some_text') - 返回所有文本等于some_text的子元素 \n
ele.eles('xpath://div[@class="ele_class"]') - 返回所有符合xpath的子元素 \n ele.eles('xpath://div[@class="ele_class"]') - 返回所有符合xpath的子元素 \n
ele.eles('css:div.ele_class') - 返回所有符合css selector的子元素 \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 loc_or_str: 元素的定位信息可以是loc元组或查询字符串
:param timeout: 查找元素超时时间 :param timeout: 查找元素超时时间
:return: DriverElement对象组成的列表 :return: DriverElement对象组成的列表
@ -574,7 +596,7 @@ def execute_driver_find(page_or_ele,
:return: 返回DriverElement元素或它们组成的列表 :return: 返回DriverElement元素或它们组成的列表
""" """
mode = mode or 'single' 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}'.") raise ValueError(f"Argument mode can only be 'single' or 'all', not '{mode}'.")
if isinstance(page_or_ele, DrissionElement): if isinstance(page_or_ele, DrissionElement):

View File

@ -36,9 +36,8 @@ class SessionElement(DrissionElement):
@property @property
def html(self) -> str: def html(self) -> str:
"""返回元素outerHTML文本""" """返回元素outerHTML文本"""
# tostring()会把跟紧元素的文本节点也带上,因此要去掉
html = format_html(tostring(self._inner_ele, method="html").decode()) html = format_html(tostring(self._inner_ele, method="html").decode())
return format_html(html[:html.rfind('>') + 1]) return html[:html.rfind('>') + 1] # tostring()会把跟紧元素的文本节点也带上,因此要去掉
@property @property
def inner_html(self) -> str: def inner_html(self) -> str:
@ -50,26 +49,35 @@ class SessionElement(DrissionElement):
def text(self) -> str: 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): def get_node(ele):
str_list = [] str_list = []
for el in ele.eles('xpath:./node()'): for el in ele.eles('xpath:./node()'):
if isinstance(el, str): if isinstance(el, str):
if el.replace(' ', '').replace('\n', '') != '': 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: elif '\n' in el:
str_list.append('\n') str_list.append('\n')
else: else:
str_list.append(' ') str_list.append(' ')
else: else:
str_list.extend(get_node(el)) str_list.extend(get_node(el))
if el.tag in ('br', 'p',):
str_list.append('\n')
return str_list return str_list
re_str = ''.join(get_node(self)) re_str = ''.join(get_node(self))
re_str = re.sub(r'\n{2,}', '\n', re_str) re_str = re.sub(r'\n{2,}', '\n', re_str)
re_str = re.sub(r' {2,}', ' ', re_str) re_str = re.sub(r' {2,}', ' ', re_str)
return format_html(re_str.strip('\n ')) return format_html(re_str.strip('\n '))
@property @property
@ -176,7 +184,7 @@ class SessionElement(DrissionElement):
elif attr == 'src': elif attr == 'src':
return self._make_absolute(self.inner_ele.get('src')) return self._make_absolute(self.inner_ele.get('src'))
elif attr in ['text', 'innerText']: elif attr in ('text', 'innerText'):
return self.text return self.text
elif attr == 'outerHTML': elif attr == 'outerHTML':
@ -213,6 +221,12 @@ class SessionElement(DrissionElement):
ele.ele('text=some_text') - 返回第一个文本等于some_text的子元素 \n ele.ele('text=some_text') - 返回第一个文本等于some_text的子元素 \n
ele.ele('xpath://div[@class="ele_class"]') - 返回第一个符合xpath的子元素 \n ele.ele('xpath://div[@class="ele_class"]') - 返回第一个符合xpath的子元素 \n
ele.ele('css:div.ele_class') - 返回第一个符合css selector的子元素 \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 loc_or_str: 元素的定位信息可以是loc元组或查询字符串
:param mode: 'single' 'all对应查找一个或全部 :param mode: 'single' 'all对应查找一个或全部
:return: SessionElement对象 :return: SessionElement对象
@ -267,6 +281,12 @@ class SessionElement(DrissionElement):
ele.eles('text=some_text') - 返回所有文本等于some_text的子元素 \n ele.eles('text=some_text') - 返回所有文本等于some_text的子元素 \n
ele.eles('xpath://div[@class="ele_class"]') - 返回所有符合xpath的子元素 \n ele.eles('xpath://div[@class="ele_class"]') - 返回所有符合xpath的子元素 \n
ele.eles('css:div.ele_class') - 返回所有符合css selector的子元素 \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 loc_or_str: 元素的定位信息可以是loc元组或查询字符串
:return: SessionElement对象组成的列表 :return: SessionElement对象组成的列表
""" """
@ -363,7 +383,7 @@ def execute_session_find(page_or_ele,
:return: 返回SessionElement元素或列表 :return: 返回SessionElement元素或列表
""" """
mode = mode or 'single' 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}'.") raise ValueError(f"Argument mode can only be 'single' or 'all', not '{mode}'.")
# 根据传入对象类型获取页面对象和lxml元素对象 # 根据传入对象类型获取页面对象和lxml元素对象
@ -372,7 +392,6 @@ def execute_session_find(page_or_ele,
page_or_ele = page_or_ele.inner_ele page_or_ele = page_or_ele.inner_ele
else: # 传入的是SessionPage对象 else: # 传入的是SessionPage对象
page = page_or_ele 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) page_or_ele = fromstring(page_or_ele.response.text)
try: try: