服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - 编程技术 - XPath是什么?XPath详解教程

XPath是什么?XPath详解教程

2023-09-01 19:00洋洋菜鸟 编程技术

XPath 全称 XML Path Language ,即 XML 路径语言,它是一门在 XML 文档中查找信息的语言 它最初是用来搜寻 XML 文档的,但是它同样适用于 HTML 文档的搜索

1. XPath 概览

        XPath 全称 XML Path Language ,即 XML 路径语言,它是一门在 XML 文档中查找信息的语言 它最初是用来搜寻 XML 文档的,但是它同样适用于 HTML 文档的搜索
        XPath 的选择功能十分强大,它提供了非常简洁明了的路径选择表达式 另外,它还提供了超过 100 个内建函数,用于字符串、数值、时间的匹配以及节点、序列的处理 几乎所有我们想要定
的节点,者阿以用 XPath 来选择
        XPath于1999年11月16日成为 W3C 标准,它被设计为供 XSLT、XPointer 以及其他 XML 解析 软件使用,更多的文档可以访问其官方网站 xpath cover page - W3C

2. XPath 常用规则

常用的集中规则有:

  • nodename   选择此节点的所有子节点
  • /  从当前节点选择直接子节点
  • // 从当前节点选择子孙节点
  • . 选取当前节点
  •  ..  选取当前节点的父节点
  •  @  选取属性

        举个例子 : //title [@lang = 'ergou']   这个就是选择所有标签名为title 并且 lang的属性值为二狗的元素

        //title [@lang = 'ergou'][1]  这个就是选择所有标签名为title 并且 lang的属性值为二狗的元素的第一个元素

        //title [@lang = 'ergou'][1]/@href   这个就是选择所有标签名为title 并且 lang的属性值为二狗的元素的第一个元素的href 属性

3. 准备工作

        使用之前,首先要确保安装好 lxml 库,若没有安装 ,可以参考安装过程

4.实例引入

        这里首先导人 lxml 库的 etree 模块,然后声明了一段HTML文本,调用 HTML 类进行初始化,这样就成功构造了一个XPath解析对 这里需要注意的是,HTML文本中的最后一个li节点是没有 闭合的,但是etree模块可以自动修正HTML文本
from lxml import etree 
text = ''' 
  • first item
  • second item
  • third item
  • fourth item
  • fifth item
''' html = etree.HTML(text) result= etree.tostring(html) print(result.decode('utf-8'))
        这里我们调用 tostring()方法即可输出修正后的HTML代码,但是结果是 bytes 类型 这里利用
decode()方法将其转成 str 类型,结果如下:

XPath是什么?XPath详解教程

        可以看到,经过处理之后, li 节点标签被补全,并且还向动添加了 body,html 节点

        另外,也可以直接读取文本文件进行解析,示例如下:

from lxml import etree
html = etree.parse('./test.html',etree.HTMLParser())
'''
其中test.html为上述的
  • first item
  • second item
  • third item
  • fourth item
  • fifth item
''' result= etree.tostring(html) print(result.decode('utf-8'))

返回:

XPath是什么?XPath详解教程

        至于有 ,应该是我手打,不知哪错了,排除这个,结果与上面略有不同,就是多了一个声明DOCTYPE ,不过对解析没有任何影响

5.所有节点

        我们一般会用刀 // 开头的 XPath 规则来选取所有符合要求的节点 这里以上面的 HTML 文本为例, 如果要选取所有节点,可以这样实现:
from lxml import etree
html = etree.parse('./test.html',etree.HTMLParser())
'''
其中test.html为上述的
  • first item
  • second item
  • third item
  • fourth item
  • fifth item
''' result= html.xpath('//*') print(result)

返回:

XPath是什么?XPath详解教程

        这里使用*代表匹配所有节点,也就是整个 HTML 文本中的所有节点都会被获取 可以看到,返 回形式是一个列表,每个元素是 Element 类型,其后跟了节点的名称,如 html、body、div、ul、li、a等,所有节点都包含在列表中了
        当然 ,此处匹配也可以指定节点名称。如果想获取所有 li 节点,示例如下:
from lxml import etree
html = etree.parse('./test.html',etree.HTMLParser())
'''
其中test.html为上述的
  • first item
  • second item
  • third item
  • fourth item
  • fifth item
''' result= html.xpath('//li') print(result) print(result[0])

返回:

XPath是什么?XPath详解教程

        这里可以看到提取结果是一个列表形式,其中每个元素都是 Element 对象。如果要取出其中一个对象 ,可以直接用中括号加索引,如[0]。

6. 子节点

        我们通过 / 或 // 即可查找元素的子节点或子孙节点。假如现在想选择 li 节点的所有直接a子节点, 可以这样实现:
from lxml import etree
html = etree.parse('./test.html',etree.HTMLParser())
'''
其中test.html为上述的
  • first item
  • second item
  • third item
  • fourth item
  • fifth item
''' result= html.xpath('//li/a') print(result)

返回:

XPath是什么?XPath详解教程        此处的 / 用于选取直接子节点 ,如果要获取所有子孙节点,就可以使用 //  例如,要获取 ul 节点下的所有子孙a节点,可以这样实现:

from lxml import etree
html = etree.parse('./test.html',etree.HTMLParser())
'''
其中test.html为上述的
  • first item
  • second item
  • third item
  • fourth item
  • fifth item
''' result= html.xpath('//ul//a') print(result)

运行结果:

XPath是什么?XPath详解教程

        但是如果这里用 //ul/a  ,就无法获取任何结果了 因为 / 用于获取直接子节点,而在 节点下没 有直接 子节点,只有 li 节点,所以无法获取任何匹配结果,代码如下:
from lxml import etree
html = etree.parse('./test.html',etree.HTMLParser())
'''
其中test.html为上述的
  • first item
  • second item
  • third item
  • fourth item
  • fifth item
''' result= html.xpath('//ul/a') print(result)

运行结果为:

XPath是什么?XPath详解教程

7.父节点

        我们知道通过连续的 / 或 // 可以查找子节点或子孙节点,那么假如我们知道了子节点,怎样来查找父节点呢?这可以用 ..  来实现
        比如,现在首先选中 href 属性为 link4.html 节点,然后再获取其父节点,然后再获取其 cl ass
属性,相关代码如下:
from lxml import etree
html = etree.parse('./test.html',etree.HTMLParser())
'''
其中test.html为上述的
  • first item
  • second item
  • third item
  • fourth item
  • fifth item
''' result= html.xpath('//a[@href="https://blog.csdn.net/qq_25990967/article/details/link4.html"]/../@class') print(result)

返回:

XPath是什么?XPath详解教程

 同时,我们也可以通过 parent:: 来获取父节点:

from lxml import etree
html = etree.parse('./test.html',etree.HTMLParser())
'''
其中test.html为上述的
  • first item
  • second item
  • third item
  • fourth item
  • fifth item
''' result= html.xpath('//a[@href="https://blog.csdn.net/qq_25990967/article/details/link4.html"]/parent::*/@class') print(result)

8.属性匹配

        在选取的时候,我 们还可以用@符号进 行属性过滤。 比如,这里如果要选取 class为 item-1的 li
节点,可以这样实现:
from lxml import etree
html = etree.parse('./test.html',etree.HTMLParser())
'''
其中test.html为上述的
  • first item
  • second item
  • third item
  • fourth item
  • fifth item
''' result= html.xpath('//li[@class="item-0"]') print(result)
        这里我们通过加入[@class= item -0”] ,限制了节点的 class 属性为 item-0 ,而 HTML 文本中符合 条件的 li 节点有两个,所以结果应该返回两个匹配到的元素 结果如下:
XPath是什么?XPath详解教程

 可见,匹配结果正是两个,至于是不是那正确的两个,后面再验证 。

9.文本获取

        用 XPath 中的 text()  方法获取节点中的文本,接下来尝试获取前面 li 节点中的文本,相关

代码如下:
from lxml import etree
html = etree.parse('./test.html',etree.HTMLParser())
'''
其中test.html为上述的
  • first item
  • second item
  • third item
  • fourth item
  • fifth item
''' result= html.xpath('//li[@class="item-0"]/text()') print(result)

运行结果:

XPath是什么?XPath详解教程

        奇怪的是,我们并没有获取到任何文本,却有WIN回车换行,这是为什么呢?因为 XPath中text()前面是/,而此处/的含义是选取直接子节点,很明显li的直接子节点都是a节点,文本都是在a节点内部的,所以这里匹配到的结果就是被修正的li节点内部的符号,因为自动修正的 li 节点的尾标签有WIN回车换行。

XPath是什么?XPath详解教程

        即选中的是这两个节点:

										
  • first item
  • fifth item
        其中一个节点因为向动修正, li 节点的尾标签添加的时候换行了,所以提取文本得到的唯一结果 就是 li 节点的尾标签和a 节点的尾标签之间的换行符。
        因此,如果想获取 li 节点内部的文本,就有两种方式,一种是先选取a节点再获取文本,另一
种就是使用 //   接下来,我们来看下二者的区别:
        首先 ,选取至a 节点再获取文本,代码如下:
from lxml import etree
html = etree.parse('./test.html',etree.HTMLParser())
'''
其中test.html为上述的
  • first item
  • second item
  • third item
  • fourth item
  • fifth item
''' result= html.xpath('//li[@class="item-0"]/a/text()') print(result)

输出为:

XPath是什么?XPath详解教程

        可以看到,这里的返回值是两个,内容都是属性为 item-o的  li 节点的文本,这也印证了前面属 性匹配 的结果是正确的。
        再来看下用另一种方式(即使用 // )选取的结果,代码如下:
from lxml import etree
html = etree.parse('./test.html',etree.HTMLParser())
'''
其中test.html为上述的
  • first item
  • second item
  • third item
  • fourth item
  • fifth item
''' result= html.xpath('//li[@class="item-0"]//text()') print(result)

输出:

XPath是什么?XPath详解教程

        不出所料,这里的返回结果是3个,可想而知,这里是选取所有子孙节点的文本,其中前两个就 li 的子节点a 节点内部的文本,另外 一个就是最后一个 li 节点内部的文本,即换行符。

10.属性获取

        我们知道用 text()  可以获取节点内部文本,那么节点属性该怎样获取呢?其实还是用@符号就可。例如,我们想获取所有 li 节点下所有a 节点的 href 属性,代码如下:
from lxml import etree
html = etree.parse('./test.html',etree.HTMLParser())
'''
其中test.html为上述的
  • first item
  • second item
  • third item
  • fourth item
  • fifth item
''' result= html.xpath('//li/a/@href') print(result)

返回:

XPath是什么?XPath详解教程

注意:此处和属性匹配的方法不同,属性匹配是中括号加属性名和值来限定某个属性,如[@href="https://blog.csdn.net/qq_25990967/article/details/linkl.html ”],而此处的@ href 指的是获取节点的某 个属性,二者需要做好区分

11.属性多值匹配

有时候,某些节点的某个属性可能有多个值,例如:
from lxml import etree 
text = '''
  • first item
  • ''' html = etree .HTML(text) result = html.xpath('//li[contains(@class,"li")]/a/text()') print(result)
        这样通过 contains()  方法,第一个参数传入属性  名称,第二个参数传入属性值,只要此属性包含 所传入的属性值,就可 以完成匹配了,运行结果如下:
XPath是什么?XPath详解教程

 注:此种方式在某个节点的某个属性有多个值时经常用到,如某个节点的 class 属性通常有多个。

12. 多属性匹配

        我们可能还遇到一种情况,那就是根据多个属性确定一个节点,这时就需要同时匹配多个 属性。 此时可以使用运算符 and 来连接,示例如下:
from lxml import etree 
text = '''
  • first item
  • ''' html = etree .HTML(text) result = html.xpath('//li[contains(@class,"li") and @name="item"]/a/text()') print(result)
        这里的 li 节点又增加了1 个属性 na me 要确定这个节点 需要同 时根据 clas和name 属性来选

择,一个条件是 class 属性里面 包含 li 字符串,另一个条件是 name 属性为 item 字符串,二者需要同 时满足,需要用 and 操 作符相连,相连之后置于中括号内进行条件筛选 运行结果 如下:

XPath是什么?XPath详解教程
xpath运算符有哪些呢?
XPath是什么?XPath详解教程

13.按序选择

        有时候,我们在选择的时候某些属性可能同时匹配了多个节点,但是只想要其中的某个节点,如 第二个节点或者最后一 个节点,这时该怎么办呢?
        这时可以利用中括号传入索引的方法获取特定次序的节点,示例如下:
from lxml import etree
text='''
  • first item
  • second item
  • third item
  • fourth item
  • fifth item
''' html = etree.HTML(text) #序号是以1开头的,不是以0开头 result= html.xpath('//li[1]/a/text()') #第一个 li 节点 print(result) result= html.xpath('//li[last()]/a/text()') #最后一个 li 节点 print(result) result= html.xpath('//li[position()<3]/a/text()') #选取位置小于3的 li 节点,也就是1和2的节点 print(result) result= html.xpath('//li[last()-2]/a/text()') #选取倒数第三个的节点,last()是最后一个,所有last()-2就是倒数第三个 print(result)

运行结果为:

XPath是什么?XPath详解教程

14. 节点轴选择

        XPath 提供了很多节点轴选择方法,包括获取子元素 、兄弟元素、父元素、祖先元素等,示例如下:
from lxml import etree
text='''
  • first item
  • second item
  • third item
  • fourth item
  • fifth item
''' html = etree.HTML(text) #序号是以1开头的,不是以0开头 result= html.xpath('//li[1]/ancestor::*') '''第一次选择时,调用了ancestor轴,可以获取所有祖先节点 其后需要跟两个冒号,然后是节点的选择器,这里我们直接使用*,表示匹配所有节点,因此返回结果是第一个 li 节点的所有祖先节点,包括 html、body、div、ul''' print(result) result= html.xpath('//li[1]/ancestor::div') '''第二次选择时,又加了限定条件,这次在冒号后面加了 div ,这样得到的结果就只有 div这个祖先节点了''' print(result) result= html.xpath('//li[1]/attribute::*') '''第三次选择时,调用了 attribute 轴,可以获取所有属性值,其后跟的选择器还是*,这代获取节点的所有属性,返回值就是 li 节点的所有属性值''' print(result) result= html.xpath('//li[1]/child::a[@href="https://blog.csdn.net/qq_25990967/article/details/link1.html"]') '''第四次选择时,调用了 child 轴,可以获取所有直接子节点 这里又加了限定条件,选 href 属性为 linkl.html的a节点''' print(result) result= html.xpath('//li[1]/descendant::span') '''第五次选择时,调用了 descendant 轴,可以获取所有子孙节点 这里又加了限定条件获取 span 节点,所以返回的结果只包含 span 节点而不包含a节点''' print(result) result= html.xpath('//li[1]/following::*[2]') '''第六次选择时,调用 following 轴,可以获取当前节点之后的所有节点 这里虽然使用的是*匹配,但又加了索引选择,所以只获取了第二个后续节点''' print(result) result= html.xpath('//li[1]/following-sibling::*') '''第七次选择时,调用 fo llowing -s ibling ,可以获取当前节点之后的所有同级节点,使用*匹配,所以获取了所有后续同级节点''' print(result)

运行结果:

XPath是什么?XPath详解教程

结语

        到这里,我们基本把会用到的xpath选择器介绍完了。xpath功能非常强大,内置函数非常多,熟练使用后会大大提升HTML信息的提取效率。

如果想查询更多 XPath 的用法,可以查看: XPath 教程
如果想 查询更多 .Pyt on xml 库的用法,可以查看: lxml - Processing XML and HTML with Python
XPath工具推荐:https://tool.tuohang.net/xpath/

到此这篇关于XPath是什么?XPath详解教程的文章就介绍到这了,更多相关内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文地址:https://blog.csdn.net/qq_25990967/article/details/122498476

延伸 · 阅读

精彩推荐