Xpath解析及其语法Zf

news/2025/3/11 10:33:58/文章来源:https://www.cnblogs.com/westworldss/p/18586166

XPath解析

XPath(XML Path Language)是一种用于在XML和HTML文档中查找信息的语言,其通过路径表达式来定位节点,属性和文本内容,并支持复杂查询条件,XPath 是许多 Web 抓取工具如 Scrapy,Selenium 等的核心技术之一

XPath 解析的基本步骤

  1. 导入lxml.etree
from lxml import etree
  1. 使用etree.parse(filename, parser=None)函数返回一个树形结构
  • etree.parse()用于解析本地XML或HTML文件,并将其转换为一个树形结构即ElementTree对象,可以通过该对象访问文档的各个节点
  • filename:要解析的文件路径
  • parser(可选):默认情况下,parser()会根据文件扩展名自动选择合适的解析器,如.xml文件使用XML解析器,.html使用HTML解析器
  1. 使用etree.HTML(html_string, parser=None)解析网络html字符串
  • html_string :要解析的HTML字符串
  • parser:(可选):默认情况下etree.HTML()使用etree.HTMLparser()进行解析
  • 返回值:etree.HTML()返回一个ELement对象,表示HTML文档的根元素,可以通过该对象访问文档各个节点
  1. 使用.xpath(xpath_expression)在已经解析好的HTML文档中执行XPath查询
result = html_tree.xpath(xpath_expression)
  • xpath_expression:XPath表达式,用于在文档中查找节点,XPath表达式可以是绝对路径或相对路径,也可以包含谓词,函数和轴操作,主要的XPath语法下面会展开讲解
  • html_tree:可以是 ElementTree 对象(由 etree.parse() 返回)或 Element 对象(由 etree.HTML() 返回)
from lxml import etree# 使用etree.parser()解析文件路径
parser = etree.HTMLParser(encoding='utf-8')  # 以utf8进行编码
tree = etree.parse('../Learning02/三国演义.html', parser=parser)
print(tree)
#output-> # 使用etree.HTML()解析本地文件或网络动态HTML
# 读取文件 解析为字符串
file = open('../Learning02/三国演义.html', 'r', encoding='utf-8')
data = file.read()
root = etree.HTML(data)
print(root)#整合
root = etree.HTML(open('../Learning02/三国演义.html', 'r', encoding='utf-8').read())
print(root)
#output-> 

XPath语法

XPath语法可以用于在XML与HTML文档中查找信息的语言

路径表达式

XPath使用路径表达式来定位文档中的节点,路径也可以分为绝对路径与相对路径

绝对路径

  • /:表示从根节点开始选择,其用于定义一个绝对路径

从根节点html开始查找到head,再从head下找出title标签

root = etree.HTML(open('../Learning02/三国演义.html', 'r', encoding='utf-8').read())
all_titles = root.xpath('/html/head/title')
for title in all_titles:print(etree.tostring(title, encoding='utf-8').decode('utf-8'))
#output-> 《三国演义》全集在线阅读_史书典籍_诗词名句网

相对路径

相比与绝对路径,相对路径使用率更好,更好用

  • //:表示从当前节点开始,选择文档中所有符合条件的节点,并且不考虑他们的位置
root = etree.HTML(open('../Learning02/三国演义.html', 'r', encoding='utf-8').read())
all_a = root.xpath('//a')
for a in all_a:print(a.text)
#None
#首页
#分类
#作者
#...

当前节点

  • ./:表示当前节点,通常用于指明当前节点本身,避免混淆
all_a = root.xpath('//a')
print(all_a[1].xpath('./text()')) #./表示当前的a标签
#output-> ['首页']

选择属性

  • @:用于选择元素的属性,而不是元素本身
# 使用 @ 选择 标签的 href 属性
all_hrefs = root.xpath('//a[@href]')
for hrefs in all_hrefs:print(etree.tostring(hrefs, encoding='unicode'))

XPath谓语

谓语是xpath中用于进一步筛选节点的表达式,通常放在方括号[] 内,其可以基于节点的位置,属性值,文本内容或其他条件来选择特定的节点,谓语可以嵌套使用,也可以与其他谓语组合使用

  • 基本语法
//element[condition]
  • element:要选择的元素
  • condition:谓语中的条件,用于进一步筛选符合条件的元素

位置谓语

位置谓语用于根据节点在兄弟节点中的位置进行选择,可以使用position()或直接指定位置编号

  • 获取第一个ul标签中的第一个li标签
#//ul获取的是所有ul,[0]选择第一个
lis = root.xpath('//ul')[0].xpath('./li[1]')
for li in lis:print(etree.tostring(li, encoding='unicode'))
#output-> * [首页](https://github.com)
  • 使用last()获取最后第一个节点,和导数第二个节点
# 倒一个
last_li = root.xpath('//ul')[0].xpath('./li[last()]')
print(etree.tostring(last_li[0], encoding='unicode'))
# 倒二个
last_second_li = root.xpath('//ul')[0].xpath('./li[last()-1]')
print(etree.tostring(last_second_li[0], encoding='unicode'))
#output-> * [安卓下载](https://github.com)#* [古籍](https://github.com)
  • 使用position()获取位置进行筛选
# 获取前两个li标签
last_li = root.xpath('//ul')[0].xpath('./li[position()<3]')
for li in last_li:print(etree.tostring(li, encoding='unicode'))
# 获取偶数位标签
lis = root.xpath('//ul')[0].xpath('./li[position() mod 2=0]')
for li in lis:print(etree.tostring(li, encoding='unicode'))
  • 属性谓语

属性谓语用于选择具体特定属性的节点

  • 使用@attribute来获取属性名称,结合条件进行筛选
# 选取所有具有 href 属性的 a 元素
hrefs = root.xpath("//a[@href]")
for href in hrefs:print(etree.tostring(href, encoding='unicode'))
  • 查找class属性值
all_class = root.xpath('//@class')
print(all_class)
  • 组合谓语

将多个条件组合在一起,使用逻辑运算符 and,or等来创建更复杂的谓语

#选取href属性值为https://example.com且class属性值为link的a元素
//a[@href='https://example.com' and @class='link']
#选取href属性值为https://example.com或https://another.com的a 元素
//a[@href='https://example.com' or @href='https://another.com']
  • 函数谓语

Xpath提供了许多内置函数,来应对更复杂的筛选条件

  • contains((string1, string2)函数:

    • string1:要搜索的字符串
    • string2:要查找的字符串
# 选取class包含"book"的img标签
images = root.xpath('//img[contains(@src,"book")]')
for image in images:print(etree.tostring(image, encoding='unicode'))
  • starts-with(string1, string2)函数:

检查一个字符串是否以指定字符的前缀开始,是返回true,否返回false

- `string1:`要检查的字符串
- `string2:`作为前缀的字符串
# 选取所有href以https://开头的a标签
all_a = root.xpath('//a[starts-with(@href,"https:")]')
for a in all_a:print(etree.tostring(a, encoding='unicode'))
  • 文本内容谓语

用于选择包含特定文本内容的节点,可以使用text()函数来提取节点的文本内容

# 选择使用包含"三国"文本的p标签
paragraphs = root.xpath('//p[contains(text(),"三国")]')
for p in paragraphs:print(etree.tostring(p, encoding='unicode'))

通配符

xpath提供了多种通配符,用于在路径表达式中匹配未知的元素,属性,或任何节点.这些通配符非常有用,尤其是当不确定具体节点名称和结构的情况下

通配符 描述
* 匹配任何元素节点。 一般用于浏览器copy xpath会出现
@* 匹配任何属性节点。
node() 匹配任何类型的节点。

使用*匹配任何元素节点

  • * 是最常用的通配符之一,其可以匹配任何元素,而不需要具体标签名.这在不确定元素名称或希望选择所有类型的元素时非常有用
# 选择所有 div 下的所有子元素
divs = root.xpath("//div/*")
for div in divs:print(etree.tostring(div, encoding='unicode'))

使用@* 匹配任何属性节点

  • @* 用于匹配任何属性节点,而不用指定具体属性名称,在你不确定属性名称或希望选择所有属性时非常有用
# 选择所有 a 元素的所有属性
all_a = root.xpath('//a/@*')
for a in all_a:print(a)

使用node()匹配任何类型的节点

  • node() 是一个更通用的通配符,其能匹配任何类型节点,包括元素节点,文本节点,属性节点,注释节点等等,其在需要选择不仅仅是元素节点是十分有用
# 选择所有 ul 下的所有子节点(包括文本节点)
nodes = root.xpath('//ul/node()')
print(nodes)
#output-> ['\n ', , '\n,...] 

XPath,re正则,BeautifulSoup对比

在之前的学习中我们首先学习了re正则表达式,其次学习了更加便捷的bs4,哪为何还要学习XPath解析呢,接下来我们将它们的优点和适用场景进行对比学习

工具 优点 缺点 适用场景
XPath 强大的路径表达能力,支持层级结构和条件查询 学习曲线较陡,对不规范 HTML 容错性较差 结构化良好的 XML/HTML,复杂查询
re 灵活性高,适合处理纯文本中的模式匹配 不适合解析 HTML/XML,可读性差 从纯文本中提取特定模式的数据
BeautifulSoup 易于使用,容错性强,适合初学者 性能稍低,功能有限 不规范的 HTML,简单数据提取,网页抓取
  • 总结

    • 若需要处理结构良好的XML或HTML文档,并需要进行复杂查询,那么XPath解析是最佳选择
    • 若需要从纯文本中提取特定模式的数据时,如从日志中提取日期,IP地址的,re正则表达式是最佳选择
    • 需要解析不规范的 HTML 或者只需要进行简单的数据提取,BeautifulSoup 是最友好的选择
    • XPath解析
  • XPath 解析的基本步骤

  • XPath语法

  • 路径表达式

  • 绝对路径

  • 相对路径

  • 当前节点

  • 选择属性

  • XPath谓语:悠兔机场官网订阅

  • 位置谓语

  • 通配符

  • 使用*匹配任何元素节点

  • 使用@* 匹配任何属性节点

  • 使用node()匹配任何类型的节点

  • XPath,re正则,BeautifulSoup对比

    __EOF__

    ihave2carryon - 本文链接: https://github.com/ihave2carryon/p/18585329

  • 关于博主: 评论和私信会在第一时间回复。或者直接私信我。
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
  • 声援博主: 如果您觉得文章对您有帮助,可以点击文章右下角【[推荐](javascript:void(0)😉】一下。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/846648.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

信息安全概论复习5

什么是防火墙?防火墙分类(四种分类:安全策略、网络体系结构、应用技术、拓扑结构)按安全策略分类(两种安全策略:不允许就禁止;没有禁止都是允许的)(两种网络服务访问权限策略:外部不能访问内部;外部只能访问内部的某些站点)按网络体系结构分类 (不同层对应不同的防…

20222314 2024-2025-1 《网络与系统攻防技术》实验五实验报告

20222314 2024-2025-1 《网络与系统攻防技术》实验5实验报告 1.实验内容 学习了信息搜集技术,包括但不限于ip反查,nmap以及其他软件的信息搜集功能 2.实验过程 (1)从www.besti.edu.cn、baidu.com、sina.com.cn中选择一个DNS域名进行查询,获取如下信息:DNS注册人及联系方式…

elastic8.4.0搜索+logstash-mysql实时同步+kibana可视化操作+netcore代码笔记

做全文搜索,es比较好用,安装可能有点费时费力。mysql安装就不说了。主要是elastic8.4.0+kibana8.4.0+logstash-8.16.1,可视化操作及少量netcore查询代码。 安装elastic8.4.0+kibana8.4.0使用docker-desktop,logstash-8.16.1是线程解压执行文件。1. docker-compose.yml 如下…

关于双JWT的流程记录

鉴权问题一直是个经典问题,从最初的cookie-session方案,到token方案,再到使用签名保证准确性的JWT方案一直到OAuth2.0,这里我在项目中对于原来的传统授权方式使用双JWT进行改造 为什么要使用双token 由于token的过期时间在token生成后就难以更改,所有token的过期时长不宜设置过…

一个有效的策略使您无法连接到此打印机列队里

你的计算机上有一个有效的策略使您无法连接到此打印机列队里,请联系管理员,无法连接打印机。 错误代码,000002 能共享打印机,能访问共享打印机。但在客户端访问出现该问题,无法连接。 发现是共享的打印机服务器未在域里,需要加域,加入域控后该问题解决。

基于 .NET 开发的多功能流媒体管理控制平台

前言 今天大姚给大家分享一个基于 .NET 开发且开源(MIT License)的多功能流媒体管理控制平台:AKStream。 项目介绍 AKStream是一个基于.NET开发且开源(MIT License)的、功能全面的流媒体管理控制平台,集成了GB28181、RTSP、RTMP、HTTP等设备的推拉流控制、PTZ控制、音视频…

sql注入-数据库表基本操作

一、数据库 linux下登录: mysql -u root -p查看数据库: show databases;可以在phpmyadmin面板点击SQL进行操作1. 增加/创建 创建xxx数据库,并使用utf-8编码 create database xxx charset utf8;2. 删除 删除xxx数据库 drop database xxx;3. 选择进入数据库 进入xxx数据库 use…

elastic8.4.0搜索+logstash=mysql实时同步+kibana可视化操作+netcore代码笔记

做全文搜索,es比较好用,安装可能有点费时费力。mysql安装就不说了。主要是elastic8.4.0+kibana8.4.0+logstash-8.16.1,可视化操作及少了netcore查询代码。 安装elastic8.4.0+kibana8.4.0使用docker-desktop,logstash-8.16.1是线程解压执行文件。1. docker-compose.yml 如下…

达梦网络通信异常-断开的管道(write failed)报错排查及解决过程

应用连接数据库偶发性报网络通信异常,报错截图如下:查看驱动版本,应用所用的驱动和数据库当前版本匹配 数据库版本 网络和数据库日志方面也没有问题,连接池超时设置调整之后还是报错 应用报错日志有断开的管道 根据网上参考类似错误。应该是长时间没有刷新页面导致数据库断…

【日记】论韭菜是怎么养成的,指我自己(656 字)

正文今天被一种盛大的焦虑裹挟。可能由于现在视野越来越广了,原来的盲区也有了或多或少的了解,总觉得自己现在非常菜。今天上班还听到同事们在炒股,身后的同事说她这两天赚了半个月的工资,大概快四千块钱。我没说话,侧着耳朵听。有同事问她怎么选的,她说听一个炒股高人选…

使用自定义 JsonConverter 解决 long 类型在前端的精度问题

问题 Javascript 的 number 类型存在精度限制,浏览器反序列化 JSON 时,无法完整保留 long 类型的精度。在 JSON 序列化时将 long 转换为 string 进行传递就可以保留精度。在 ASP.NET Core 中,可以创建一个 自定义 JsonConverter 来达到这一目的。 实现 long 和 string 转换的…

『玩转Streamlit』--表单Form

在Streamlit中,Form组件是一种特殊的UI元素,允许用户输入数据而不立即触发应用的重新运行。 这对于创建需要用户输入多个参数后再进行处理的交互式表单非常有用。 1. 概要 Form组件的主要作用是在一个表单内集中处理多个用户输入,使得数据收集和验证更加高效和直观。 通过Fo…