XML(Extensible Markup Language)指可扩展标记语言,被设计用来传输和存储数据。详细信息可参考 http://www.w3school.com.cn/xml。
HTML指的是超文本标记语言 (Hyper Text Markup Language),是WWW上用于编写网页的主要工具,详细信息请参考 http://www.w3school.com.cn/html
XML和HTML都是一种标记语言 (markup language),使用标记标签来描述数据,这些标签可用于查找和定位数据。
下面是 xml 文档的一个例子:
<?xml version="1.0" encoding="ISO-8859-1"?>
<bookstore>
<book>
<title lang="eng">Harry Potter</title>
<price>29.99</price>
</book>
<book>
<title lang="eng">Learning XML</title>
<price>39.95</price>
</book>
</bookstore>
- 父(Parent)每个元素以及属性都有一个父,上例中book 元素是 title、price 元素的父结点;
- 子(Children)元素节点可有零个、一个或多个子,上例中 title、price 元素都是 book 元素的子结点;
- 同胞(Sibling)拥有相同的父的节点,上例中title、price 为同胞结点;
- 先辈(Ancestor)某节点的父、父的父等等,上例中title、price 的先辈结点是bookstore。
- 后代(Descendant)某个节点的子,子的子,上例中bookstore的后代结点为 book、title、price。
XPath 语法
XPath (XML Path Language) 是一门在 XML 文档中查找信息的语言,可用来在 XML 文档中对元素和属性进行遍历。细节可以参考W3School官方文档:http://www.w3school.com.cn/xpath/index.asp
XPath 使用路径表达式来选取 XML 文档中的节点或节点集。节点是通过沿着路径 (path) 或者步 (steps) 来选取的。
XPath 开发工具有:
- 开源的XPath表达式编辑工具:XMLQuire(XML格式文件可用)
- Chrome插件 XPath Helper
- Firefox插件 XPath Checker
# XPath 常用路径表达式学习
'''
<bookstore>
<book>
<title lang="eng">Harry Potter</title>
<price>29.99</price>
</book>
<book>
<title lang="eng">Learning XML</title>
<price>39.95</price>
</book>
</bookstore>
'''
# 下面列出了最常用的路径表达式
'bookstore' # 选取 bookstore 元素的所有子节点
'/bookstore' # 选取根元素 bookstore (假如路径起始于 / ,则此路径始终代表到某元素的绝对路径)
'bookstore/book' # 选取属于 bookstore 的子元素的所有的 book 元素
'//book' # 选取所有的 book 元素,不管其位置在哪
'bookstore//book' # 选择 bookstore 后代元素中的所有 book 元素
'//@lang' # 选取名为 lang 的所有属性
# 谓语
'/bookstore/book[1]' # 选取属于 bookstore 子元素的第一个book 元素
'/bookstore/book[last()]' # 选取属于 bookstore 子元素的最后一个 book 元素
'/bookstore/book[last()-1]' # 选取属于 bookstore 子元素的倒数第二个 book 元素
'/bookstore/book[position < 3]' # 选取属于 bookstore 子元素的前两个 book 元素
'//title[@lang]' # 选取所有拥有名为 lang 的属性的 title 元素
'//title[@lang="lang"]' # 选取所有 lang 属性值为 eng 的 title 元素
'/bookstore/book[price > 35.00]' # 选取 bookstore 下,所有 price 元素值大于 35.00 的 book 元素
'/bookstore/book[price > 35.00]/title' # 选取 bookstore 下,所有 price 元素值大于 35.00 的 book 元素的 title 子元素
# XPath 通配符
'/bookstore/*' # 选取 bookstore 元素的所有子元素
'//*' # 选取文档中的所有元素
'//title[@*]' # 选取所有带属性的 title 元素
# | 运算符,可以选择若干条路径
'//book/title | //book/price' # 选取 book 元素的所有 title 和 price 元素
'//title | //price' # 选取文档中的所有 title 和 price 元素
'/bookstore/book/title | //price' # 选取 bookstore/book 下的所有 title 元素,以及文档中所有的 price 元素
lxml 库
xml 是 一个HTML/XML的解析器,主要的功能是如何解析和提取HTML/XML 数据。lxml和正则一样,也是用 C 实现的,是一款高性能的Python HTML/XML 解析器,我们可以利用之前学习的XPath语法,来快速的定位特定元素以及节点信息。
# lxml 解析 xml 文档的使用示例
from lxml import etree
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>
'''
# 利用 etree.HTML,将字符串解析为 HTML 文档
html = etree.HTML(text)
# 按字符串序列化 HTML 文档
result = etree.tostring(html)
print(result.decode('utf-8'))
# 注意:lxml 会自动补全缺少的 </li>闭合标签
运行结果:
<html><body><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>
</li></ul>
</div>
</body></html>
除了直接读取字符串,lxml 还支持从文件里读取内容
# lxml 读取 xml 文档 的示例
from lxml import etree
# 读取外部文件 axmldoc.xml
html = etree.parse('./axmldoc.xml')
result = etree.tostring(html,pretty_print=True)
print(result.decode('utf-8'))
XPath选取信息实践
- 获取所有的 li 标签
- 获取 li 标签的所有 class 属性
- 继续获取 li 标签下href为 link1.html 的 a 标签
- 获取li 标签下的所有span 标签
- 获取 li 标签下的 a 标签里的所有 class
- 获取最后一个li 的 a 的 href
- 获取倒数第二个元素的内容
- 获取 class 值为 bold 的标签名
from lxml import etree
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"><span class="bold">third item</span></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></li>
</ul>
</div>
'''
html = etree.HTML(text)
# 获取所有的 li 标签
result = html.xpath('//li')
print(result)
print('---'*10)
# 获取 li 标签的所有 class 属性
result = html.xpath('//li/@class')
print(result)
print('---'*10)
# 继续获取 li 标签下href为 link1.html 的 a 标签
result = html.xpath('//li/a[@href="link1.html"]')
print(result)
print('---'*10)
# 获取li 标签下的所有span 标签
result = html.xpath('//li//span')
print(result)
print('---'*10)
# 获取 li 标签下的 a 标签里的所有 class
result = html.xpath('//li/a//@class')
print(result)
print('---'*10)
# 获取最后一个li 的 a 的 href
result = html.xpath('//li[last()]/a/@href')
print(result)
print('---'*10)
# 获取倒数第二个元素的内容
result = html.xpath('//li[last()-1]/a/text()')
print(result)
print('---'*10)
# 获取 class 值为 bold 的标签名
result = html.xpath('//*[@class="bold"]')
print(result[0].tag)
运行结果:
[<Element li at 0x1ef3eea6608>, <Element li at 0x1ef3eebd1c8>, <Element li at 0x1ef3eebd208>, <Element li at 0x1ef3eebd248>, <Element li at 0x1ef3eebd288>]
------------------------------
['item-0', 'item-1', 'item-inactive', 'item-1', 'item-0']
------------------------------
[<Element a at 0x1ef3eebd308>]
------------------------------
[<Element span at 0x1ef3ee0e088>]
------------------------------
['bold']
------------------------------
['link5.html']
------------------------------
['fourth item']
------------------------------
span