XPath语法详解

Xpath语法和lxml模块

什么是XPath?

xpath (XML Path Language)是一门在XML和HTML文档中查找信息的语言,可用来在XML和HTML文档中对元素和属性进行遍历。

XPath开发工具

  1. Chrom插件XPath Helper
  2. FireFox插件XPath Checker

XPath语法

选取节点:

Xpath使用路径表达式选取XML文档中的节点或 节点集。

表达式 描述 示例 结果
nodename 选取此节点的所有结点 bookstore 选取bookstore下所有的节点
/ 如果是在最前面,代表从根节点选取。否者选取某节点下的某个节点 /bookstore 选取根元素下所有的bookstore节点
// 从全局节点中选择节点 //book 选取所有的bookstore节点
@ 选取某个节点的属性 //book[@id] 选取所有拥有id属性的book节点
谓语:

谓语用来查找某个特定的节点或者包含某个指定的值的节点,被嵌在方括号中。

路径表达式 描述
/bookstore/book[1] 选取bookstore下的第一个book元素
/bookstore/book[last()] 选取bookstore下的倒数第二个book元素
/bookstore/book[position() < 3] 选取bookstore下前两个book元素
//book[@id] 选取拥有id属性的所有book元素
//book[@id=10] 选取所有id=10的所有book元素
通配符:

* 表示通配符

通配符 描述 示例 结果
* 匹配任意节点 /bookstore/* 选取bookstore下所有的子元素
@* 匹配节点中的任何属性 //book[@*] 选取所有带有属性的book元素
选取多个路径:

通过在路径表达式中使用“|”运算符,可以选取若干路径。

示例:

1
2
//bookstore/book | //book/title
### 选取所有book元素以及book元素下所有的title元素
运算符
运算符 描述 实例 返回值
| 计算两个节点集 //book | //cd 返回所有拥有book 和cd元素的节点集
+ 加法 6+4 10
- 减法 6-4 2
* 乘法 6*4 24
div 除法 8 div 4 2
= 等于 id=101 如果id=101,则返回True,否则返回False
!= 不等于 id != 101 如果id != 101,则返回True,否则返回False
< 小于 id < 101 如果id > 101,则返回True,否则返回False
<= 小于或等于 id <= 101 如果id <= 101,则返回True,否则返回False
> 大于 id > 101 如果id > 101,则返回True,否则返回False
>= 大于或等于 id >= 101 如果id >= 101,则返回True,否则返回False
or id =100 or id = 101 如果id = 100 或id=101,返回True, 否则返回False
and id > 100 and id < 150 如果100 < id < 101,返回True,否则返回False
mod 计算除法的余数 5 mod 2 1

注意:

  1. /和//的区别:/代表只获取直接子节点, //代表获取子孙节点。

  2. contains:有时某个属性中包含多个值,可以使用模糊匹配的方式获取。

    1
    //div[contaions(@class, 'job_detail')]

lxml库

lxml是一个HTML/XML的解析器,主要的功能是如何解析和提取HTML/XML数据。

lxml和正则一样,也是C实现的,是一款高性能的Python HTML/XML解析器,它可以用来快速的定位特定元素以及节点信息。

安装:pip install lxml

基本使用:

在用lxml解析HTML代码的时候,如果HTML代码不规范,lxml库会自动的将其补全。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 使用lxml的etree库
from lxml import etree

text = '''
<div>
<ul>
<li class="item-0"><a href="link0.html">First item</a></li>
<li class="item-1"><a href="link1.html">Second item</a></li>
<li class="item-inactive"><a href="link2.html">Third item</a></li>
<li class="item-1"><a href="link3.html">Fourth item</a></li>
<li class="item-0"><a href="link4.html">Fifth item</a>
</ul>
</div>
'''

html = etree.HTML(text)

def print_result(html):
result = etree.tostring(html, encoding='utf-8').decode('utf-8')
print(result)

print_result(html)

结果如下:

1
2
3
4
5
6
7
8
9
10
<html><body><div>
<ul>
<li class="item-0"><a href="link0.html">First item</a></li>
<li class="item-1"><a href="link1.html">Second item</a></li>
<li class="item-inactive"><a href="link2.html">Third item</a></li>
<li class="item-1"><a href="link3.html">Fourth item</a></li>
<li class="item-0"><a href="link4.html">Fifth item</a>
</li></ul>
</div>
</body></html>

在解析html文件时,如果使用的lxml.etree.parse解析。该函数默认使用的解析器是XML解析器,所以,如果html文件中缺少相应标签,解析就会出错,此时可以自行创建解析器。

lxml的使用

以上文的text为例:

  • 获取ul标签

    1
    2
    3
    uls = html.xpath('//ul')
    for ut in uls:
    print_result(ut)
  • 获取<li class=”item-1”>标签

    1
    2
    3
    li_items_1 = html.xpath("//li[@class='item-1']")
    for li_item_1 in li_items_1:
    print_result(li_item_1)
  • 获取所有<li class=”item-1”>中a标签中的链接

    1
    2
    3
    li_items_1_as_href = html.xpath("//li[@class='item-1']/a/@href")
    for li_items_1_a_href in li_items_1_as_href:
    print(li_items_1_a_href)
  • 获取所有a标签中的文字

    1
    2
    3
    as_text = html.xpath("//a/text()")
    for a_text in as_text:
    print(a_text)