当前位置:   article > 正文

使用XPath来解析网页数据

使用XPath来解析网页数据

阅读指导:
这篇文章详细讲解了XPath解析的方法。每个方法都配有相应的代码示例,读者可以通过本文更深入地了解XPath。由于文章篇幅较长,建议通过目录选择您感兴趣的部分进行学习。

1. XPath

       XPath(XML Path Language)是一种用于在 XML 文档中查找和选取节点的语言。它提供了一种通过路径表达式来导航 XML 文档的方法。

其优点在于:

  • 强大的定位能力
  • 灵活的路径表达式
  • 高效的节点选择

1.1 节点的访问

1.1.1 节点的访问规则

表达式描述
//从当前节点,选取其子孙结点
/从当前节点,选取其直接子节点
.选取当前节点
..选取当前节点的父节点
@选取属性
nodename选取此节点的所有子节点

1.1.2 访问所有节点

通过 // 方式来获取所有符合要求的结点
比如:
//* 选取所有节点
//li 选取所有 li 节点
//ul 选取所有 ul 节点
//a 选取多有 a 节点

获取到节点后,返回的是列表元素,每个元素都是ELement类型,可以通过索引的方式获取

示例HTML:

<!-- ./test.html文件 -->
<div>
    <ul>
         <li class="item-0"><a href="link1.html">first item</a></li>
         <li class="item-1"><a href="link2.html">second item</a></li>
         <li class="item-inactive"><a href="link3.html">third item</a></li>
         <li class="item-1"><a href="link4.html">fourth item</a></li>
         <li class="item-0"><a href="link5.html">fifth item</a>
     </ul>
 </div>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

获取 li 元素下的 a 元素

from lxml import etree

html = etree.parse('./test.html', etree.HTMLParser())
result = html.xpath('//li')
print(result)
print(type(result))
print(result[0])
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

输出:

[<Element li at 0x1905f6f6640>, <Element li at 0x1905f6f6680>, <Element li at 0x1905f6f66c0>, <Element li at 0x1905f6f6700>, <Element li at 0x1905f6f6740>]
<class 'list'>
<Element li at 0x1905f6f6640>
  • 1
  • 2
  • 3

1.1.3 子节点

通过 / 和 // 来获取当前元素的子,子孙节点
但是要注意
/ 只获取直接子节点, // 用于获取子孙节点

获取所有 li 元素的 a 标签

from lxml import etree

html = etree.parse('./test.html', etree.HTMLParser())
result = html.xpath('//li/a')
print(result)
print(result[0])
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

输出:

[<Element a at 0x1a676cd6500>, <Element a at 0x1a676cd6540>, <Element a at 0x1a676cd6580>, <Element a at 0x1a676cd65c0>, <Element a at 0x1a676cd6600>]
<Element a at 0x1a676cd6500>
  • 1
  • 2

1.1.4 父节点

通过 .. 的方式获取

比如:
获取 li 的class属性值

 <li class="item-1"><a href="link4.html">fourth item</a></li>
  • 1

获取代码:

from lxml import etree

html = etree.parse('./test.html', etree.HTMLParser())
result = html.xpath('//a[@href="link4.html"]/../@class')
print(result)
  • 1
  • 2
  • 3
  • 4
  • 5

输出:

['item-1']
  • 1

代码解释:
       首先是定位到超链接为“link4.html”的 a 标签,然后向上翻一级,也就是到了 li 元素,然后再查找这个 a 标签对应的 li 的 class 属性值,即最后的输出为[‘item-1’]

1.2.属性访问

1.2.1 属性匹配

       像1.1.4所示,该节点使用 @ 符号来定位其属性,所以通过 @ 符号可以实现属性的过滤。

基本语法:[@a = “b”]
比如 [@class = “abc”],[@herf= “link”]

例:
获取class为“item-0”的 li 标签

<li class="item-0"><a href="link1.html">first item</a></li>
<li class="item-0"><a href="link5.html">fifth item</a>
  • 1
  • 2

获取代码:

from lxml import etree
html = etree.parse('./test.html', etree.HTMLParser())
result = html.xpath('//li[@class="item-0"]')
print(result)
  • 1
  • 2
  • 3
  • 4

输出:

[<Element li at 0x1d7dde06680>, <Element li at 0x1d7dde066c0>]
  • 1

1.2.2 属性值获取

属性值的获取也是用 @ 符号,但是与属性匹配不同的是,属性匹配需要用总括号加属性名和值来限定某个属性

获取所有 li 标签下的 a 标签的 herf 的值

from lxml import etree

html = etree.parse('./test.html', etree.HTMLParser())
result = html.xpath('//li/a/@href')
print(result)
  • 1
  • 2
  • 3
  • 4
  • 5

输出:

['link1.html', 'link2.html', 'link3.html', 'link4.html', 'link5.html']
  • 1

1.2.3 属性多值匹配

对于一个节点的某个属性含多个属性值时,使用contains方法定位元素。
contains()传两个参数,第一个是属性名,第二个是属性名中的其中一个属性值。

例:
获取class属性值里面含 “li” 的 li 标签的 a 标签下的文字

<!--./text-->
<li class="li li-first"><a href="link.html">first item</a></li>
  • 1
  • 2

获取代码:

from lxml import etree
html = etree.HTML(./text)
result = html.xpath('//li[contains(@class, "li")]/a/text()')
print(result)
  • 1
  • 2
  • 3
  • 4

输出:

['first item']
  • 1

1.2.4 多属性匹配

对于一个节点具有多个属性时,使用 and 运算符连接多个属性

例:
获取class属性值含 “li” 和 name 属性值为 “item” 的 li 标签下的 a 标签的文字部分

<!--./text-->
<li class="li li-first" name="item"><a href="link.html">first item</a></li>
  • 1
  • 2

获取代码:

from lxml import etree
html = etree.HTML(./text)
result = html.xpath('//li[contains(@class, "li") and @name="item"]/a/text()')
print(result)
  • 1
  • 2
  • 3
  • 4

输出:

['first item']
  • 1

1.3 节点的选择

当某个属性对应多个节点时,就需要对节点进行选择

1.3.1 按序选择

字面意思,即是通过索引的方式进行选择,但是不同于代码思维的一点就是,索引的第一个数是1,不是0

例:
以索引的形式,获取 li 标签下的 a 标签的文字内容

<!--./text-->
<div>
    <ul>
         <li class="item-0"><a href="link1.html">first item</a></li>
         <li class="item-1"><a href="link2.html">second item</a></li>
         <li class="item-inactive"><a href="link3.html">third item</a></li>
         <li class="item-1"><a href="link4.html">fourth item</a></li>
         <li class="item-0"><a href="link5.html">fifth item</a>
     </ul>
 </div>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

获取代码:

from lxml import etree
html = etree.HTML(./text)
result = html.xpath('//li[1]/a/text()')
print(result)
result = html.xpath('//li[last()]/a/text()')
print(result)
result = html.xpath('//li[position()<3]/a/text()')
print(result)
result = html.xpath('//li[last()-2]/a/text()')
print(result)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

输出:

['first item']
['fifth item']
['first item', 'second item']
['third item']
  • 1
  • 2
  • 3
  • 4

1.4 文本获取

<!-- ./test.html文件 -->
<div>
    <ul>
         <li class="item-0"><a href="link1.html">first item</a></li>
         <li class="item-1"><a href="link2.html">second item</a></li>
         <li class="item-inactive"><a href="link3.html">third item</a></li>
         <li class="item-1"><a href="link4.html">fourth item</a></li>
         <li class="item-0"><a href="link5.html">fifth item</a>
     </ul>
 </div>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

使用text()方式,获取该元素下的直接文字内容
比较下面三种方式获取文字的信息

获取代码:

from lxml import etree

html = etree.parse('./test.html', etree.HTMLParser())

result = html.xpath('//li[@class="item-0"]/text()')
print(result)

result = html.xpath('//li[@class="item-0"]/a/text()')
print(result)

result = html.xpath('//li[@class="item-0"]//text()')
print(result)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

输出:

['\n     ']
['first item', 'fifth item']
['first item', 'fifth item', '\n     ']
  • 1
  • 2
  • 3

代码解释:
       第一种是访问class属性为“item-0”的 li 标签下的文字,但是在这行代码里面,li 标签的下一级是 a 标签,没有文字,只有换行符,所以输出也就是['\n ']
       第二种这是访问class属性为“item-0”的 li 标签的 a 标签下的文字,所以输出是[‘first item’, ‘fifth item’]
       第三种是访问class属性为“item-0”的 li 标签下所有子孙节点的文本,同时也包含了转义字符,所以输出为[‘first item’, ‘fifth item’, '\n ']

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Gausst松鼠会/article/detail/599457
推荐阅读
  

闽ICP备14008679号