XPath解析

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

XPath 解析的基本步骤

  1. 导入lxml.etree

    from lxml import etree
  2. 使用etree.parse(filename, parser=None)函数返回一个树形结构

    • etree.parse()用于解析本地XML或HTML文件,并将其转换为一个树形结构即ElementTree对象,可以通过该对象访问文档的各个节点
    • filename:要解析的文件路径
    • parser(可选):默认情况下,parser()会根据文件扩展名自动选择合适的解析器,如.xml文件使用XML解析器,.html使用HTML解析器
  3. 使用etree.HTML(html_string, parser=None)解析网络html字符串

    • html_string :要解析的HTML字符串
    • parser:(可选):默认情况下etree.HTML()使用etree.HTMLparser()进行解析
    • 返回值:etree.HTML()返回一个ELement对象,表示HTML文档的根元素,可以通过该对象访问文档各个节点
  4. 使用.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-> <lxml.etree._ElementTree object at 0x000001A240107000> # 使用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-> <Element html at 0x1a23e462880>

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-> <title>《三国演义》全集在线阅读_史书典籍_诗词名句网</title>

相对路径

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

  • //:表示从当前节点开始,选择文档中所有符合条件的节点,并且不考虑他们的位置
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-> ['首页']

选择属性

  • @:用于选择元素的属性,而不是元素本身
# 使用 @ 选择 <a> 标签的 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-> <li><a href="/">首页</a></li>
  • 使用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-> <li><a href="/app/">安卓下载</a></li>
    #<li><a href="/book/">古籍</a></li>
  • 使用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 ', <Element li at 0x2009621d800>, '\n,...]

XPath,re正则,BeautifulSoup对比

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

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

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

Xpath解析及其语法的更多相关文章

  1. JAVA通过XPath解析XML性能比较(原创)

    (转载请标明原文地址) 最近在做一个小项目,使用到XML文件解析技术,通过对该技术的了解和使用,总结了以下内容. 1 XML文件解析的4种方法 通常解析XML文件有四种经典的方法.基本的解析方式有两种 ...

  2. @1-4使用Xpath解析豆瓣短评

    使用Xpath解析豆瓣短评 Python爬虫(入门+进阶)     DC学院 本节课程主要介绍解析神器Xpath是什么.Xpath如何安装及使用,以及使用实际的例子讲解Xpath如何解析豆瓣短评的网页 ...

  3. JAVA通过XPath解析XML性能比较

    转自[http://www.cnblogs.com/mouse-coder/p/3451243.html] 最近在做一个小项目,使用到XML文件解析技术,通过对该技术的了解和使用,总结了以下内容. 1 ...

  4. 利用XPath解析带有xmlns的XML文件

    在.net中,编写读取xml 的程序中提示"未将对象引用设置到对象的实例",当时一看觉得有点奇怪.为什么在读取xml数据的时候也要实例化一个对象.google了才知道,xml文件中 ...

  5. 爬虫系列二(数据清洗--->xpath解析数据)

    一 xpath介绍 XPath 是一门在 XML 文档中查找信息的语言.XPath 用于在 XML 文档中通过元素和属性进行导航. XPath 使用路径表达式在 XML 文档中进行导航 XPath 包 ...

  6. python开发遇到的坑(1)xpath解析ValueError: Unicode strings with encoding declaration are not supported

    Traceback (most recent call last): File "/Users/*******.py", line 37, in <module> Bt ...

  7. xpath解析数据

    xpath解析数据 """ xpath 也是一种用于解析xml文档数据的方式 xml path w3c xpath搜索用法 在 XPath 中,有七种类型的节点:元素.属 ...

  8. xpath 解析 及案例

    xpath解析 编码流程: 1.实例化一个etree对象,且将页面源码加载到该对象中 2.使用xpath函数,且在函数中必须作用一个xpath表达式进行标签的定位 3.使用xpath进行属性和文本的提 ...

  9. Scrapy基础(六)————Scrapy爬取伯乐在线一通过css和xpath解析文章字段

    上次我们介绍了scrapy的安装和加入debug的main文件,这次重要介绍创建的爬虫的基本爬取有用信息 通过命令(这篇博文)创建了jobbole这个爬虫,并且生成了jobbole.py这个文件,又写 ...

  10. BeautifulSoup与Xpath解析库总结

    一.BeautifulSoup解析库 1.快速开始 html_doc = """ <html><head><title>The Dor ...

随机推荐

  1. CSS – Box Shadow & Text Shadow

    前言 之前在 CSS – W3Schools 学习笔记 (3) 介绍过这个功能, 但一直不熟练. 每次用都卡卡的, 估计是没有写一篇独立的笔记的缘故. 特此写一篇. Text Shadow 下面这个是 ...

  2. EF Core – Many to Many

    前言 Many to many 是 EF Core 5.0 才开始有的, 以前都用 2 个 1-n 来实现的. 由于它比 1-n 复杂, 所以有必要写一遍来记入一下. 参考: Relationship ...

  3. DLA:动态层级注意力架构,实现特征图的持续动态刷新与交互 | IJCAI'24

    论文深入探讨了层级注意力与一般注意力机制之间的区别,并指出现有的层级注意力方法是在静态特征图上实现层间交互的.这些静态层级注意力方法限制了层间上下文特征提取的能力.为了恢复注意力机制的动态上下文表示能 ...

  4. 25. Socket与粘包问题

    1. Socket概念 Socket允许应用程序通过它发送或接收数据,对其进行像对文件一样的打开.读写和关闭等操作,从而允许应用程序将I/O插入到网络中,并与网络中的其他应用程序进行通信.Socket ...

  5. kdump

    Kdump简单介绍 什么是Kdump? Kdump是在系统崩溃.死锁或死机时用来转储内存运行参数的一个工具和服务,是一种新的crash dump捕获机制,用来捕获kernel crash(内核崩溃)的 ...

  6. 1.1 HELLO 窗口

    跟着教程,开始第一步创建窗口吧!这一节不涉及太多知识. 本节会出现一些名词,我们现在只需要知道它们大概是干什么的就行. ● GLFW:一个专门针对OpenGL的C语言库,通过它提供的接口,我们就可以渲 ...

  7. 开源之夏 2022 重磅来袭!欢迎报名 KubeSphere 社区项目!

    活动简介 "开源之夏(英文简称 OSPP)"是中科院软件所"开源软件供应链点亮计划"指导下的系列暑期活动,由软件所与 openEuler 社区共同主办. 开源之 ...

  8. 基于 KubeSphere 的开源微服务开发平台 Pig 最佳实践

    作者:何昌涛,北京北大英华科技有限公司高级 Java 工程师,云原生爱好者. 前言 近年来,为了满足越来越复杂的业务需求,我们从传统单体架构系统升级为微服务架构,就是把一个大型应用程序分割成可以独立部 ...

  9. Oracle 数据泵 定时全库备份&&删除备份文件【注意点】

    一.概述 在给客户部署的数据泵备份&&删除过期备份脚本时,脚本删除部分未生效,导致存储空间占用非常大. 手动执行该删除命令时,执行成功: 最后发现需要增加 find.rm 等命令的PA ...

  10. C#实现信创国产Linux麦克风摄像头推流(源码,银河麒麟、统信UOS)

    随着国际政治经济形势的变化,尤其是中美科技竞争日益激烈,软件信创国产化已经迫在眉睫.在这种大环境下,我们将现有的Windows版软件逐步迁移到信创国产化基础设施上,适配国产操作系统(如银河麒麟.统信U ...