XPath原理:先将HTML文档转为XML文档,再用XPath查找HTML节点或元素
什么是XML?
1,XML指可扩展标记语言
2,XML是一种标记语言,类似于HTML
3,XML的设计宗旨是传输数据,而非显示数据
4,XML标签需要我们自己自定义
5,XML被设计为具有自我描述性
XML和HTML的区别?
1,XML被设计为传输和存储数据,其焦点是数据的内容
2,HTML是显示数据以及如何更好的显示数据
# XML文档示例
# 这里面的标签都是自定义的
<?xml version="1.0" encoding="utf-8"?>
<bookstore>
<book category="cooking">
<title lang="en">Everyday Italian</title>
<author>Giada De Laurentiis</author>
<year>2005</year>
<price>30.00</price>
</book>
<book category="children">
<title lang="en">Harry Potter</title>
<author>J K. Rowling</author>
<year>2005</year>
<price>29.99</price>
</book>
<book category="web">
<title lang="en">XQuery Kick Start</title>
<author>James McGovern</author>
<author>Per Bothner</author>
<author>Kurt Cagle</author>
<author>James Linn</author>
<author>Vaidyanathan Nagarajan</author>
<year>2003</year>
<price>49.99</price>
</book>
<book category="web" cover="paperback">
<title lang="en">Learning XML</title>
<author>Erik T. Ray</author>
<year>2003</year>
<price>39.95</price>
</book>
</bookstore>
一、XML的节点关系
1,父(parent)
每个元素及属性都有一个父
下面这个XML例子中,book元是title,author,year,price元素的父
<?xml version="1.0" encoding="utf-8"?>
<book>
<title>Harry Potter</title>
<author>J K. Rowling</author>
<year>2005</year>
<price>29.99</price>
</book>
2,子(children)
元素节点可能有零个,一个或者多个子
在下面的例子中 title,author,year,price都是book元素的子
<?xml version="1.0" encoding="utf-8"?>
<book>
<title>Harry Potter</title>
<author>J K. Rowling</author>
<year>2005</year>
<price>29.99</price>
</book>
3,同胞(sibling)
拥有相同的父的节点
在下面例子中 title,author,year,price元素都是同胞
<?xml version="1.0" encoding="utf-8"?>
<book>
<title>Harry Potter</title>
<author>J K. Rowling</author>
<year>2005</year>
<price>29.99</price>
</book>
4,先辈(ancestor)
某节点的父,父的父,等等
下面例子中,title元素的先辈是book和bookstore
<?xml version="1.0" encoding="utf-8"?>
<bookstore>
<book>
<title>Harry Potter</title>
<author>J K. Rowling</author>
<year>2005</year>
<price>29.99</price>
</book>
</bookstore>
5,后代
某节点的子,子的子,等等
下面例子中,bookstore后代是book,title,author,year,price元素
<?xml version="1.0" encoding="utf-8"?>
<bookstore>
<book>
<title>Harry Potter</title>
<author>J K. Rowling</author>
<year>2005</year>
<price>29.99</price>
</book>
</bookstore>
什么是XPath?
XPath(XML Path Language)是一门在XML文档中查找信息的语言,可以用来在XML文档对元素和属性进行遍历
XML Path Language : XML路径语言
选取节点
XPath使用路径表达式来选取XML文档中的节点或者节点集,这些路径表达式和我们在常规的电脑文件系统里看到的表达式非常相似
下面列出了最常用的路径表达式:
表达式 | 描述 |
---|---|
nodename | 选取此节点的所有子节点。 |
/ | 从根节点选取。 |
// | 从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置。 |
. | 选取当前节点。 |
.. | 选取当前节点的父节点。 |
@ | 选取属性。 |
在下面的表格中,我们已列出了一些路径表达式以及表达式的结果:
bookstore | 选取 bookstore 元素的所有子节点。 |
/bookstore | 选取根元素 bookstore。注释:假如路径起始于正斜杠( / ),则此路径始终代表到某元素的绝对路径! |
bookstore/book | 选取属于 bookstore 的子元素的所有 book 元素。 |
//book | 选取所有 book 子元素,而不管它们在文档中的位置。 |
bookstore//book | 选择属于 bookstore 元素的后代的所有 book 元素,而不管它们位于 bookstore 之下的什么位置。 |
//@lang | 选取名为 lang 的所有属性。 |
选取未知节点
XPath 通配符可用来选取未知的 XML 元素。
通配符 | 描述 |
---|---|
* | 匹配任何元素节点。 |
@* | 匹配任何属性节点。 |
node() | 匹配任何类型的节点。 |
在下面的表格中,我们列出了一些路径表达式,以及这些表达式的结果:
路径表达式 | 结果 |
---|---|
/bookstore/* | 选取 bookstore 元素的所有子元素。 |
//* | 选取文档中的所有元素。 |
html/node()/meta/@* | 选择html下面任意节点下的meta节点的所有属性 |
//title[@*] | 选取所有带有属性的 title 元素。 |
选取若干路径
通过在路径表达式中使用“|”运算符,您可以选取若干个路径。
在下面的表格中,我们列出了一些路径表达式,以及这些表达式的结果:
路径表达式 | 结果 |
---|---|
//book/title | //book/price | 选取 book 元素的所有 title 和 price 元素。 |
//title | //price | 选取文档中的所有 title 和 price 元素。 |
/bookstore/book/title | //price | 选取属于 bookstore 元素的 book 元素的所有 title 元素,以及文档中所有的 price 元素。 |
这些就是XPath的语法内容,在运用到Python抓取时要先转换为xml。
lxml库
1,lxml库是一个HTML/XML的解析器,主要功能是如何解析和提取HTML/XML数据
2,lxml和正则一样,都是通过C语言实现的,它是一款高性能的Python HTML/XML的解析器,我们可以利用之前所学习的XPath语法,来快速定位特定元素以及节点信息
3,lxml python 的官方文档:lxml - Processing XML and HTML with Python
4,需要安装C语言库,pip install lxml
初步使用
我们利用它来解析 HTML 代码,简单示例:
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>
</div>
'''
# 1,使用lxml的etree类
from lxml import etree
#,2,利用etree.HTML()构造一个xpath解析对象(转为xml文档)
xml_doc=etree.HTML(html)
print(xml_doc)
print('-----'*10)
# etree.tostring()输出转换后的html代码,
html_doc = etree.tostring(xml_doc)
print(html_doc) #自动补全了body,html标签
print(type(html_doc)) # bytes类型
# print('-----'*10)
print(html_doc.decode()) # 利用decode()方法将其转成str类型,
print(type(html_doc.decode()))
lxml可以自动修正HTML代码 ,例子里不仅补全了li标签,还添加了body,html标签
1.XPath实例测试
1. 获取所有的 <li>
标签
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></li>
</ul>
</div>
'''
from lxml import etree
xml_doc = etree.HTML(html) # xml
result = xml_doc.xpath('//li')
print(result)
print(type(result))
for i in result:
print(i)
r = etree.tostring(i)
print(r)
2. 继续获取<li>
标签的所有 class
属性
re = xml_doc.xpath('//li/@class')
print(re)
3. 获取 <li>
标签下的<a>
标签里的所有 href
r = xml_doc.xpath('//a/@href')
print(r)
4. 继续获取<li>
标签下href
为 link1.html
的 <a>
标签 的文本内容
r =xml_doc.xpath('//a[@href="link1.html"]/text()')
print(r)
# print(etree.tostring(r[0]))
注意:
1,只要涉及到条件,加 []
2,只要获取属性值,加 @
3,通过text()取内容