使用 XPath 解析 HTML 文档

XPath 简介

XPath 的全称是 XML Path Language,即 XML 路径语言,它是一种在结构化文档(比如 XML 和 HTML 文档)中定位信息的语言,关于 XPath 的介绍可以参考 https://www.w3.org/TR/xpath/。

语法

HTML 实例文档

后面我们将以下面的 HTML 文档介绍 XPath 的使用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<html>
<head>
<base href='http://example.com/' />
<title>Example website</title>
</head>
<body>
<div id='images'>
<a href='image1.html'>Name: My image 1 <br/><img src='image1_thumb.jpg'/></a>
<a href='image2.html'>Name: My image 2 <br/><img src='image2_thumb.jpg'/></a>
<a href='image3.html'>Name: My image 3 <br/><img src='image3_thumb.jpg'/></a>
<a href='image4.html'>Name: My image 4 <br/><img src='image4_thumb.jpg'/></a>
<a>Name: My image 5 <br/><img src='image5_thumb.jpg'/></a>
</div>
</body>
</html>

选取节点

下表是 XPath 常用的语法,实例对应的是上面的 HTML 文档。

表达式 描述 实例 结果
nodename 选取此节点的所有子节点 body 选取 body 元素的所有子节点
/ 从根节点选取 /html 选取根元素 html
// 匹配选择的当前节点,不考虑位置 //img 选取所有 img 元素,而不管它们在文档的位置
. 选取当前节点 ./img 选取当前节点下的 img 节点
.. 选取当前节点的父节点 ../img 选取当前节点的父节点下的 title
@ 选取属性 //a[@href=”image1.html”] 选取所有 href 属性为 “image1.html” 的 a 节点
//a/@href 获取所有 a 节点的 href 属性的值

谓语

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

路径表达式 结果
//body//a[1] 选取属于 body 子元素的第一个 a 元素
//body//a[last()] 选取属于 body 子元素的最好一个 a 元素
//a[@href] 选取所有拥有名为 href 的属性的 a 元素
//a[@href=’image2.html’] 选取所有 href 属性等于 “image2.html” 的 a 元素

在 Python 中使用

python 中使用 XPath 需要安装相应的库,这里推荐使用 lxml 库。

代码示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# -*- coding: utf-8 -*-
from lxml import etree
html = """
<html>
<head>
<base href='http://example.com/' />
<title>Example website</title>
</head>
<body>
<div id='images'>
<a href='image1.html'>Name: My image 1 <br/><img src='image1_thumb.jpg'/></a>
<a href='image2.html'>Name: My image 2 <br/><img src='image2_thumb.jpg'/></a>
<a href='image3.html'>Name: My image 3 <br/><img src='image3_thumb.jpg'/></a>
<a href='image4.html'>Name: My image 4 <br/><img src='image4_thumb.jpg'/></a>
<a>Name: My image 5 <br/><img src='image5_thumb.jpg'/></a>
</div>
</body>
</html>
"""
page_source = etree.HTML(html.decode('utf-8'))
title = page_source.xpath("//title/text()")
all_href = page_source.xpath("//a/@href")
a_image1_text = page_source.xpath("//body//a[1]/text()")
a_image1_src = page_source.xpath("//a[@href='image1.html']/img/@src")
a_image3_href = page_source.xpath("//a[contains(@href, '3')]/@href")
a_last = page_source.xpath("//body//a[last()]/img/@src")
all_img_src = page_source.xpath("//img/@src")
print "Title", title
print "all href", all_href
print "a_image1_text", a_image1_text
print "a_image1_src", a_image1_src
print 'a_image3_href', a_image3_href
print "a_last", a_last
print "all_img_src", all_img_src

输出结果如下:

1
2
3
4
5
6
7
Title ['Example website']
all href ['image1.html', 'image2.html', 'image3.html', 'image4.html']
a_image1_text ['Name: My image 1 ']
a_image1_src ['image1_thumb.jpg']
a_image3_href ['image3.html']
a_last ['image5_thumb.jpg']
all_img_src ['image1_thumb.jpg', 'image2_thumb.jpg', 'image3_thumb.jpg', 'image4_thumb.jpg', 'image5_thumb.jpg']

要注意的是,如果 xpath() 找到了匹配的数据,返回的结果是一个数组,不管是一个还是多个,比如结果中的 Title

参考资料