Python利用lxml提取HTML页面所有叶子节点XPath路径的实现方法

Owen
Owen
发布时间:2026-10-13| 5人浏览过
原创

本文介绍如何使用Python的lxml模块提取HTML页面中所有叶子节点的XPath路径。针对原始解析结果包含非叶子节点的问题,提出基于路径包含关系的过滤算法:若当前路径被下一路径包含则跳过,否则视为叶子节点。通过实际代码演示了从原始XPath列表到纯净叶子节点XPath列表的转换过程,并提供了相关XML处理工具推荐。

本文详细介绍了一种基于Python lxml模块解析HTML并提取页面内所有叶子节点XPath路径的实现方法,供读者参考学习。

在实际应用中,有时需要利用叶子节点的XPath作为特征进行后续处理。然而,lxml模块默认解析得到的是页面中所有节点的XPath路径,这并非我们真正需要的结果。经过查阅大量网络博客和技术文档,并未发现直接输出HTML中全部叶子节点的现成API或函数。尽管未能找到合适资源,但这并不意味着无法实现。通过对页面所有节点XPath输出结果的观察,可以发现以下规律:

1. XPath路径之间存在明显的包含关系。

2. 叶子节点的XPath必然包含前一个叶子节点路径与后一个叶子节点路径之间的所有中间路径。

3. 所有的叶子节点之间互不包含。

基于上述观察,我们可以设计相应的处理逻辑。具体做法是设置一个标志位,遍历XPath列表:如果当前路径被下一条路径包含,则索引加1继续处理;直到遇到不包含的情况,此时当前路径即为一条叶子节点路径,将其加入结果列表。经检验,生成的结果路径列表中均不存在包含关系,因此可暂认为均为叶子节点路径。由于未进行大规模实验验证是否存在例外情况,该结论仅供参考,但方法本身是可行的。具体实现代码如下:

#!usr/bin/env python
#encoding:utf-8
'''''
__author__:沂水寒城
功能:得到页面的叶子节点的xpath
'''
def get_leaf_node_xpath(one_page_xpath):
  '''''
  输入:一个页面的原始xpath路径列表
  输出:只包含页面的叶子节点的xpath列表
  '''
  one_page_xpath.append('0')
  leaf_node_xpath_list=[]
  for i in range(len(one_page_xpath)-1):
    j=i+1
    one_xpath=one_page_xpath[i]
    two_xpath=one_page_xpath[j]
    if one_xpath in two_xpath:
      one_xpath=two_xpath
      two_xpath=one_page_xpath[j+1]
    else:
      leaf_node_xpath_list.append(one_xpath)
  return leaf_node_xpath_list
if __name__ == '__main__':
  with open('baidu.txt') as f:
    html=f.read()
  htree, one_page_xpath=get_clean_allnodes_xpath(html)
  leaf_node_xpath_list=get_leaf_node_xpath(one_page_xpath)
  print leaf_node_xpath_list
  with open('data/dom_leaf_xpath/original_xpath.txt', 'w') as f1:
    for one_line in one_page_xpath:
      f1.write(one_line.strip()+'\n')
  with open('data/dom_leaf_xpath/leaf_xpath.txt', 'w') as f2:
    for one_line in leaf_node_xpath_list:
      f2.write(one_line.strip()+'\n')

打开保存的文件内容为:

original_xpath.txt内容为:

/html /html/head /html/head/meta[1] /html/head/meta[2] /html/head/meta[3] /html/head/meta[4] /html/head/title /html/body /html/body/p /html/body/p/comment()[1] /html/body/p/comment()[2] /html/body/p/comment()[3] /html/body/p/meta /html/body/div[1] /html/body/div[1]/div[1] /html/body/div[1]/div[1]/div /html/body/div[1]/div[1]/div/div[1] /html/body/div[1]/div[1]/div/div[1]/div /html/body/div[1]/div[1]/div/div[1]/div/div[1] /html/body/div[1]/div[1]/div/div[1]/div/a /html/body/div[1]/div[1]/div/div[1]/div/form /html/body/div[1]/div[1]/div/div[1]/div/form/span[1] /html/body/div[1]/div[1]/div/div[1]/div/form/span[2] /html/body/div[1]/div[1]/div/div[1]/div/form/span[3] /html/body/div[1]/div[1]/div/div[1]/div/form/span[3]/span /html/body/div[1]/div[1]/div/div[1]/div/form/span[3]/span/div /html/body/div[1]/div[1]/div/div[1]/div/form/span[3]/span/div/span /html/body/div[1]/div[1]/div/div[1]/div/form/span[3]/span/ul /html/body/div[1]/div[1]/div/div[1]/div/form/span[3]/span/ul/li[1] /html/body/div[1]/div[1]/div/div[1]/div/form/span[3]/span/ul/li[1]/a /html/body/div[1]/div[1]/div/div[1]/div/form/span[3]/span/ul/li[2] /html/body/div[1]/div[1]/div/div[1]/div/form/span[3]/span/ul/li[2]/a /html/body/div[1]/div[1]/div/div[1]/div/form/span[3]/span/ul/li[3] /html/body/div[1]/div[1]/div/div[1]/div/form/span[3]/span/ul/li[4] /html/body/div[1]/div[1]/div/div[1]/div/form/span[3]/span/ul/li[4]/a /html/body/div[1]/div[1]/div/div[1]/div/div[2] /html/body/div[1]/div[1]/div/div[2] /html/body/div[1]/div[1]/div/div[2]/a[1] /html/body/div[1]/div[1]/div/div[2]/a[2] /html/body/div[1]/div[1]/div/div[2]/a[3] /html/body/div[1]/div[1]/div/div[3] /html/body/div[1]/div[1]/div/div[3]/a[1] /html/body/div[1]/div[1]/div/div[3]/a[2] /html/body/div[1]/div[1]/div/div[3]/a[3] /html/body/div[1]/div[1]/div/div[3]/a[4] /html/body/div[1]/div[1]/div/div[3]/a[5] /html/body/div[1]/div[1]/div/div[3]/a[6] /html/body/div[1]/div[1]/div/div[3]/a[7] /html/body/div[1]/div[1]/div/div[3]/a[8] /html/body/div[1]/div[1]/div/div[3]/a[9] /html/body/div[1]/div[2] /html/body/div[1]/div[2]/a[1] /html/body/div[1]/div[2]/a[2] /html/body/div[1]/div[2]/a[3] /html/body/div[1]/div[2]/a[4] /html/body/div[1]/div[2]/a[5] /html/body/div[1]/div[2]/a[6] /html/body/div[1]/div[2]/a[7] /html/body/div[1]/div[2]/a[8] /html/body/div[1]/div[2]/a[9] /html/body/div[1]/div[3] /html/body/div[1]/div[3]/div /html/body/div[1]/div[3]/div/div /html/body/div[1]/div[3]/div/div/div[1] /html/body/div[1]/div[3]/div/div/div[2] /html/body/div[1]/div[3]/div/div/div[2]/p /html/body/div[1]/div[4] /html/body/div[1]/div[4]/div /html/body/div[1]/div[4]/div/div /html/body/div[1]/div[4]/div/div/p[1] /html/body/div[1]/div[4]/div/div/p[1]/a[1] /html/body/div[1]/div[4]/div/div/p[1]/a[2] /html/body/div[1]/div[4]/div/div/p[1]/a[3] /html/body/div[1]/div[4]/div/div/p[1]/a[4] /html/body/div[1]/div[4]/div/div/p[2] /html/body/div[1]/div[4]/div/div/p[2]/a[1] /html/body/div[1]/div[4]/div/div/p[2]/a[2] /html/body/div[1]/div[4]/div/div/p[2]/a[3] /html/body/div[1]/div[5] /html/body/div[2] /html/body/div[3] /html/body/div[4] 0

最后一行的0只是为了代码中列表能够遍历到最后一个路径而不出现索引错误的一个简单的处理,人为的添加了一个元素,没有实际意义,也不会参与处理

leaf_xpath.txt内容为:

/html/head/meta[1] /html/head/meta[2] /html/head/meta[3] /html/head/meta[4] /html/head/title /html/body/p/comment()[1] /html/body/p/comment()[2] /html/body/p/comment()[3] /html/body/p/meta /html/body/div[1]/div[1]/div/div[1]/div/div[1] /html/body/div[1]/div[1]/div/div[1]/div/a /html/body/div[1]/div[1]/div/div[1]/div/form/span[1] /html/body/div[1]/div[1]/div/div[1]/div/form/span[2] /html/body/div[1]/div[1]/div/div[1]/div/form/span[3]/span/div/span /html/body/div[1]/div[1]/div/div[1]/div/form/span[3]/span/ul/li[1]/a /html/body/div[1]/div[1]/div/div[1]/div/form/span[3]/span/ul/li[2]/a /html/body/div[1]/div[1]/div/div[1]/div/form/span[3]/span/ul/li[3] /html/body/div[1]/div[1]/div/div[1]/div/form/span[3]/span/ul/li[4]/a /html/body/div[1]/div[1]/div/div[1]/div/div[2] /html/body/div[1]/div[1]/div/div[2]/a[1] /html/body/div[1]/div[1]/div/div[2]/a[2] /html/body/div[1]/div[1]/div/div[2]/a[3] /html/body/div[1]/div[1]/div/div[3]/a[1] /html/body/div[1]/div[1]/div/div[3]/a[2] /html/body/div[1]/div[1]/div/div[3]/a[3] /html/body/div[1]/div[1]/div/div[3]/a[4] /html/body/div[1]/div[1]/div/div[3]/a[5] /html/body/div[1]/div[1]/div/div[3]/a[6] /html/body/div[1]/div[1]/div/div[3]/a[7] /html/body/div[1]/div[1]/div/div[3]/a[8] /html/body/div[1]/div[1]/div/div[3]/a[9] /html/body/div[1]/div[2]/a[1] /html/body/div[1]/div[2]/a[2] /html/body/div[1]/div[2]/a[3] /html/body/div[1]/div[2]/a[4] /html/body/div[1]/div[2]/a[5] /html/body/div[1]/div[2]/a[6] /html/body/div[1]/div[2]/a[7] /html/body/div[1]/div[2]/a[8] /html/body/div[1]/div[2]/a[9] /html/body/div[1]/div[3]/div/div/div[1] /html/body/div[1]/div[3]/div/div/div[2]/p /html/body/div[1]/div[4]/div/div/p[1]/a[1] /html/body/div[1]/div[4]/div/div/p[1]/a[2] /html/body/div[1]/div[4]/div/div/p[1]/a[3] /html/body/div[1]/div[4]/div/div/p[1]/a[4] /html/body/div[1]/div[4]/div/div/p[2]/a[1] /html/body/div[1]/div[4]/div/div/p[2]/a[2] /html/body/div[1]/div[4]/div/div/p[2]/a[3] /html/body/div[1]/div[5] /html/body/div[2] /html/body/div[3] /html/body/div[4]

针对这个问题暂时可以想到的方法就是这样的,利用包含性来解决,没有其他的新思路,如果还有新的思路欢迎交流学习!

PS:这里再为大家提供几款关于xml操作的在线工具供大家参考使用:

在线XML/JSON互相转换工具: http://tools.jb51.net/code/xmljson

在线格式化XML/在线压缩XML: http://tools.jb51.net/code/xmlformat

XML在线压缩/格式化工具: http://tools.jb51.net/code/xml_format_compress

XML代码在线格式化美化工具: http://tools.jb51.net/code/xmlcodeformat

更多关于Python相关内容感兴趣的读者可查看本站专题:《Python操作xml数据技巧总结》、《Python数据结构与算法教程》、《Python Socket编程技巧总结》、《Python函数使用技巧总结》、《Python字符串操作技巧汇总》、《Python入门与进阶经典教程》及《Python文件与目录操作技巧汇总》

希望本文所述对大家Python程序设计有所帮助。

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。