当前位置: 首页 > news >正文

python简单易懂的lxml读取HTML节点及常用操作方法

python简单易懂的lxml读取HTML节点及常用操作方法

1. 初始化和基本概念

  • lxml 是一个强大的pyth库,用于处理XML和HTML文档。
  • 它提供了类似BeautifulSoup的功能,但性能更高。
  • 在使用lxml时,通常会先解析HTML或XML文档,得到一个ElementTree对象。
pip install lxml

2. 解析HTML文档

  • 使用lxml.html.fromstring(html)来从字符串中创建一个ElementTree对象。

  • 示例:

    from lxml import html
    html_content = '<html><body><p>Hello world!</p></body></html>'
    tree = html.fromstring(html_content)
    

    或者使用etree.HTML(rhtml_content)来创建ElementTree对象:

from lxml import etree
html_content = '<html><body><p>Hello world!</p></body></html>'
tree = etree.HTML(html_content)

3. XPath选择器

  • XPath是一种用于在XML文档中查找信息的语言。

  • lxml支持XPath选择器,可以用来定位文档中的元素。

  • 示例:

    # 获取所有的段落标签
    paragraphs = tree.xpath('//p')
    

4. 遍历节点

  • iter_node() 函数可以用来遍历一个节点的所有子节点。

  • 示例:

    for node in iter_node(body):# 处理每个节点pass
    

5. 获取节点属性

  • 使用.attrib属性来获取节点的所有属性。

  • 示例:

    class_name = node.attrib.get('class', '')
    

在使用lxml处理HTML或XML文档时,获取节点的属性和属性值是非常常见的需求。下面详细解释如何获取标签的全部属性以及如何分别获取单个属性和属性值。

1. 获取标签的全部属性

lxml中,你可以通过访问节点的attrib属性来获取所有属性。attrib是一个字典,键是属性名,值是属性值。

示例代码:
from lxml import htmlhtml_content = '''
<div id="content" class="main-content"><p>Hello, world!</p>
</div>
'''tree = html.fromstring(html_content)
div_node = tree.xpath('//div')[0]# 获取所有属性
all_attributes = div_node.attrib
print("All attributes:", all_attributes)# 输出:
# All attributes: {'id': 'content', 'class': 'main-content'}
2. 分别获取单个属性和属性值

如果你只需要获取某个特定属性的值,可以直接通过键访问字典中的值。如果属性不存在,则可以使用get方法提供一个默认值。

示例代码:
# 获取单个属性
id_attribute = div_node.attrib.get('id', 'default-id')
print("ID attribute:", id_attribute)class_attribute = div_node.attrib.get('class', 'default-class')
print("Class attribute:", class_attribute)# 输出:
# ID attribute: content
# Class attribute: main-content
3. 获取属性值

如果属性名已知,可以直接通过键访问字典中的值。如果属性名未知或需要处理多个属性,可以遍历attrib字典来获取所有属性及其值。

示例代码:
# 遍历所有属性
for attr_name, attr_value in div_node.attrib.items():print(f"Attribute: {attr_name}, Value: {attr_value}")# 输出:
# Attribute: id, Value: content
# Attribute: class, Value: main-content
4. 处理特殊情况

在某些情况下,属性可能包含空格分隔的多个值(例如class属性),这时你可以使用split方法来分割字符串。

示例代码:
# 处理包含多个值的属性
class_values = div_node.attrib.get('class', '').split()
print("Class values:", class_values)# 输出:
# Class values: ['main-content']
5. 综合示例

下面是一个综合示例,展示了如何获取节点的所有属性、单个属性以及如何处理特殊情况下的属性值。

from lxml import htmlhtml_content = '''
<div id="content" class="main-content secondary"><p>Hello, world!</p>
</div>
'''tree = html.fromstring(html_content)
div_node = tree.xpath('//div')[0]# 获取所有属性
all_attributes = div_node.attrib
print("All attributes:", all_attributes)# 获取单个属性
id_attribute = div_node.attrib.get('id', 'default-id')
print("ID attribute:", id_attribute)class_attribute = div_node.attrib.get('class', 'default-class')
print("Class attribute:", class_attribute)# 遍历所有属性
for attr_name, attr_value in div_node.attrib.items():print(f"Attribute: {attr_name}, Value: {attr_value}")# 处理包含多个值的属性
class_values = div_node.attrib.get('class', '').split()
print("Class values:", class_values)# 输出:
# All attributes: {'id': 'content', 'class': 'main-content secondary'}
# ID attribute: content
# Class attribute: main-content secondary
# Attribute: id, Value: content
# Attribute: class, Value: main-content secondary
# Class values: ['main-content', 'secondary']

6. 获取节点文本

  • 使用.text属性来获取节点的文本内容。

  • 示例:

    node_text = node.text
    

或者如果下面还有子节点的话,最好是用:

# 将所有的文本拼接起来
link_name = ''.join(child.itertext()).strip().replace('\n', '').strip()
# 去掉过多的空格
link_name = re.sub(r'\s+', ' ', link_name ).strip()

7. 获取节点路径

  • 使用.getroottree().getpath(node)来获取节点的完整XPath路径。

  • 示例:

    path = node.getroottree().getpath(node)
    
1.获取最末尾节点路径
               # 提取最后一个 '/' 后面的元素last_element = path.split('/')[-1] if '/' in path else path

8. 检查节点类型(标签名)

  • 通过.tag属性来检查节点的标签名。

  • 示例:

    if node.tag == 'p':# 处理段落节点pass
    

9. 子节点操作

  • 使用.getchildren()来获取节点的所有子节点,node.getparent()获取节点的所有父节点。

  • 示例:

    children = node.getchildren()
    

10. 提取属性值

  • 使用@属性名来提取属性值。

  • 示例:

    image_srcs = node.xpath('.//img/@src')
    

11. 节点转换为字符串HTML

  • 使用etree.tostring(node)来将节点转换为字符串形式。

  • 示例:

    node_html = etree.tostring(node, pretty_print=True, encoding='unicode')
    

12. 计算文本密度

  • 文本密度是指文本相对于其他非文本内容(如图片、链接)的比例。

  • 通过计算节点中的文本长度与节点总长度的比例来估算文本密度。

  • 示例:

    text_density = len(node.text_content()) / len(etree.tostring(node))
    

13. 处理列表页面

  • 在处理列表页面时,有时候需要检查是否有特定的类名来进行对应操作,如'list'

  • 示例:

    if 'list' in a_element[0].get('class', '').lower():# 处理列表节点pass
    

扩展

构建包含属性的XPath路径

流程:

1. 获取子节点的XPath路径

首先,我们遍历一个节点的所有子节点,并获取每个子节点的XPath路径。

for child in node.getchildren():xpath_path = '/' + node.getroottree().getpath(child)
2. 获取子节点的所有属性

对于每个子节点,我们获取其所有属性:

attributes = child.attrib
3. 构建包含属性的XPath路径

接下来,我们根据子节点的属性构建一个完整的XPath路径。如果子节点有属性,我们会在XPath路径后面加上属性条件。

3.1 属性存在时

如果子节点有属性,我们构建一个包含所有属性的XPath路径:

if attributes:xpath_with_attributes = xpath_path + "["for i, (key, value) in enumerate(attributes.items()):xpath_with_attributes += f"@{key}='{value}'"if i < len(attributes) - 1:xpath_with_attributes += " and "xpath_with_attributes += "]"
  • attributes.items() 返回一个迭代器,其中包含了属性的键值对。
  • enumerate(attributes.items()) 为每个属性分配一个索引。
  • f"@{key}='{value}'" 构建一个XPath条件,表示属性 key 的值为 value
  • 如果不是最后一个属性,则添加 " and " 以连接多个条件。
  • 最后添加 "]" 来结束XPath条件。
3.2 属性不存在时

如果子节点没有属性,我们直接使用原始的XPath路径:

else:xpath_with_attributes = xpath_path
综合示例

下面是一个完整的示例代码,展示了如何遍历节点的子节点并构建包含属性的XPath路径:

from lxml import htmlhtml_content = '''
<html><body><div id="container" class="main"><p>Hello, world!</p><a href="/link" id="example">Example Link</a></div></body>
</html>
'''tree = html.fromstring(html_content)
root_node = tree.xpath('//div[@id="container"]')[0]# 遍历根节点的所有子节点
for child in root_node.getchildren():xpath_path = '/' + root_node.getroottree().getpath(child)# 获取子节点的所有属性attributes = child.attrib# 构建包含所有属性的XPath路径if attributes:xpath_with_attributes = xpath_path + "["for i, (key, value) in enumerate(attributes.items()):xpath_with_attributes += f"@{key}='{value}'"if i < len(attributes) - 1:xpath_with_attributes += " and "xpath_with_attributes += "]"else:xpath_with_attributes = xpath_pathprint(f"XPath Path: {xpath_path}")print(f"XPath with Attributes: {xpath_with_attributes}")print("Attributes:", attributes)print("")# 输出:
# XPath Path: /html/body/div/p
# XPath with Attributes: /html/body/div/p
# Attributes: {}
#
# XPath Path: /html/body/div/a
# XPath with Attributes: /html/body/div/a[@href='/link' and @id='example']
# Attributes: {'href': '/link', 'id': 'example'}
详细解释
  1. 获取子节点的XPath路径

    • node.getchildren() 返回节点的所有子节点。
    • node.getroottree().getpath(child) 获取子节点的XPath路径。
    • 我们在路径前加上 / 来确保路径格式正确。
  2. 获取子节点的所有属性

    • child.attrib 返回子节点的所有属性及其值。
  3. 构建包含属性的XPath路径

    • 如果子节点有属性,我们构建一个包含所有属性的XPath路径。
    • 使用 enumerate 来为每个属性分配一个索引,以便在多个属性之间添加 and
    • 如果子节点没有属性,我们直接使用原始的XPath路径。
http://www.lryc.cn/news/438556.html

相关文章:

  • Java | Leetcode Java题解之第406题根据身高重建队列
  • 安卓获取apk的公钥,用于申请app备案等
  • 【leetcode_python】杨辉三角
  • Parallels Desktop 20 for Mac中文版发布了?会哪些新功能
  • SpringBoot整合SSE-灵活管控连接
  • 挖矿木马-Linux
  • 【leetcode——415场周赛】——python前两题
  • 【CSS in Depth 2 精译_029】5.2 Grid 网格布局中的网格结构剖析(上)
  • ZYNQ LWIP(RAW API) TCP函数学习
  • Spring Boot,在应用程序启动后执行某些 SQL 语句
  • 【SQL】百题计划:SQL最基本的判断和查询。
  • 04_Python数据类型_列表
  • F5设备绑定EIP
  • 使用 PyCharm 新建 Python 项目详解
  • 从0开始学习 RocketMQ:分布式事务消息的实现
  • MySQL 查询数据库的数据总量
  • [C++]——vector
  • 自动驾驶:LQR、ILQR和DDP原理、公式推导以及代码演示(七、CILQR约束条件下的ILQR求解)
  • 随想录笔记-二叉树练习题
  • 华雁智科前端面试题
  • 【iOS】单例模式
  • Linux | 探索 Linux 信号机制:信号的产生和自定义捕捉
  • 递归的时间复杂度分析
  • C++: 二叉树进阶面试题
  • 【HarmonyOS NEXT】实现网络图片保存到手机相册
  • Pytorch详解-数据模块
  • 浅谈openresty
  • 【学习笔记】2024最新版SpringCloud教程
  • Proxyless Service Mesh:下一代微服务架构体系
  • 大数据Flink(一百一十八):SQL水印操作(Watermark)