一、什么是XML?
-
XML 指可扩展标记语言(EXtensible Markup Language)
-
XML 是一种标记语言,很类似 HTML
-
XML 的设计宗旨是传输数据,而非显示数据
-
XML 的标签需要我们自行定义。
-
XML 被设计为具有自我描述性。
-
XML 是 W3C 的推荐标准
W3School官方文档:https://www.w3school.com.cn/xml/index.asp
二、XML和HTML的区别
1.语法要求不同
-
在html中不区分大小写,在xml中严格区分。
-
在HTML中,有时不严格,如果上下文清楚地显示出段落或者列表键在何处结尾,那么你可以省略</p>或者</li>之类的结束标记。在XML中,是严格的树状结构,绝对不能省略掉结束标记。
-
在XML中,拥有单个标记而没有匹配的结束标记的元素必须用一个/ 字符作为结尾。这样分析器就知道不用查找结束标记了。
-
在XML中,属性值必须分装在引号中。在HTML中,引号是可用可不用的。
-
在HTML中,可以拥有不带值的属性名。在XML中,所有的属性都必须带有相应的值。
-
在XML文档中,空白部分不会被解析器自动删除;但是html是过滤掉空格的。
2.设计目标不同
-
XML被设计为传输和存储数据,其焦点是数据的内容。
-
HTML显示数据以及如何更好显示数据。
三、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.后代(Descendant)
某个节点的子,子的子,等等。
在下面的例子中,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文档中查找信息的语言。
使用XPath来对网页进行解析,首先导入lxml库的etree模块,然后声明了一段HTML文本,调用HTML类进行初始化,这样就成功构造了一个XPath解析对象。etree模块可以自动修正HTML文本。
W3School官方文档:https://www.w3school.com.cn/xpath/index.asp
1.Xpath开发工具
-
开源的XPath表达式编辑工具:XMLQuire(XML格式文件可用)
-
Chrome插件 XPath Helper
-
Firefox插件 XPath Checker
2.Xpath常用规则
1)选取节点
XPath 使用路径表达式来选取 XML 文档中的节点或者节点集。这些路径表达式和我们在常规的电脑文件系统中看到的表达式非常相似。
表达式 | 描述 |
---|---|
nodename | 选取此节点的所有子节点 |
/ | 从当前节点选取直接子节点 |
// | 从当前节点选取子孙节点 |
. | 选取当前节点 |
.. | 选取当前节点的父节点 |
@ | 选取属性 |
2)谓语
谓语用来查找某个特定的节点或者包含某个指定的值的节点。谓语被嵌在方括号中。
路径表达式 | 结果 |
---|---|
/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='eng'] | 选取所有 title 元素,且这些元素拥有值为 eng 的 lang 属性。 |
/bookstore/book[price>35.00] | 选取 bookstore 元素的所有 book 元素,且其中的 price 元素的值须大于 35.00。 |
/bookstore/book[price>35.00]/title | 选取 bookstore 元素中的 book 元素的所有 title 元素,且其中的 price 元素的值须大于 35.00。 |
3)选取未知节点
XPath 通配符可用来选取未知的 XML 元素。
通配符 | 描述 |
---|---|
* | 匹配任何元素节点。 |
@* | 匹配任何属性节点。 |
node() | 匹配任何类型的节点。 |
4)选取若干路径
通过在路径表达式中使用“|”运算符,您可以选取若干个路径。
路径表达式 | 结果 |
---|---|
//book/title | //book/price | 选取 book 元素的所有 title 和 price 元素。 |
//title | //price | 选取文档中的所有 title 和 price 元素。 |
/bookstore/book/title | //price | 选取属于 bookstore 元素的 book 元素的所有 title 元素,以及文档中所有的 price 元素。 |
3.常用Xpath表达式
属性定位: #找到class属性值为song的div标签 //div[@class="song"] 层级&索引定位: #找到class属性值为tang的div的直系子标签ul下的第二个子标签li下的直系子标签a //div[@class="tang"]/ul/li[2]/a 逻辑运算: #找到href属性值为空且class属性值为du的a标签 //a[@href="" and @class="du"] 模糊匹配: //div[contains(@class, "ng")] //div[starts-with(@class, "ta")] 取文本: # /表示获取某个标签下的文本内容 # //表示获取某个标签下的文本内容和所有子标签下的文本内容 //div[@class="song"]/p[1]/text() //div[@class="tang"]//text() 取属性: //div[@class="tang"]//li[2]/a/@href
六、lxml库
1.etree模块使用
# 使用 lxml 的 etree 库 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> # 注意,此处缺少一个 </li> 闭合标签 </ul> </div> ''' #利用etree.HTML,将字符串解析为HTML文档,etree模块可自动修正HTML文本 html = etree.HTML(text) # 按字符串序列化HTML文档 ret = etree.tostring(html) # torstring()方法返回的结果是bytes类型,这里用decode()方法将其转化为字符串 print(ret.decode('utf-8'))
输出结果:
<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>
etree
模块可以自动修正 html 代码,例子里不仅补全了 li 标签,还添加了 body,html 标签。
2.文件读取
使用etree.parse()方法来读取文件。
from lxml import etree html = etree.parse('./test.html',HTMLParser()) ret = etree.tostring(html) print(ret.decode('utf-8'))
输出结果:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd"> <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>
输出结果多了一个DOCTYPE声明,对解析结果没影响。
七、Xpath与lxml应用实例
1.获取所有的 li
标签
# xpath_li.py from lxml import etree html = etree.parse('hello.html') print type(html) # 显示etree.parse() 返回类型 result = html.xpath('//li') print result # 打印<li>标签的元素集合 print len(result) print type(result) print type(result[0])
输出结果:
<type 'lxml.etree._ElementTree'> [<Element li at 0x1014e0e18>, <Element li at 0x1014e0ef0>, <Element li at 0x1014e0f38>, <Element li at 0x1014e0f80>, <Element li at 0x1014e0fc8>] 5 <type 'list'> <type 'lxml.etree._Element'>
2.继续获取li
标签的所有 class
属性
# xpath_li.py from lxml import etree html = etree.parse('hello.html') result = html.xpath('//li/@class') print result
输出结果:['item-0', 'item-1', 'item-inactive', 'item-1', 'item-0']
3.继续获取li
标签下hre
为 link1.html
的 a
标签
# xpath_li.py from lxml import etree html = etree.parse('hello.html') result = html.xpath('//li/a[@href="link1.html"]') print result
输出结果:[<Element a at 0x10ffaae18>]
4.获取li
标签下的所有 span
标签
# xpath_li.py from lxml import etree html = etree.parse('hello.html') #result = html.xpath('//li/span') #注意这么写是不对的: #因为 / 是用来获取子元素的,而 <span> 并不是 <li> 的子元素,所以,要用双斜杠 result = html.xpath('//li//span') print result
运行结果:[<Element span at 0x10d698e18>]
5.获取 li
标签下的a
标签里的所有 class
# xpath_li.py from lxml import etree html = etree.parse('hello.html') result = html.xpath('//li/a//@class') print result
输出结果:['blod']
6.获取最后一个 li
的 a
的 href
# xpath_li.py from lxml import etree html = etree.parse('hello.html') result = html.xpath('//li[last()]/a/@href') # 谓语 [last()] 可以找到最后一个元素 print result
输出结果:['link5.html']
7.获取倒数第二个元素的内容
# xpath_li.py from lxml import etree html = etree.parse('hello.html') result = html.xpath('//li[last()-1]/a') # text 方法可以获取元素内容 print result[0].text
输出结果:fourth item
8.获取 class
值为 bold
的标签名
# xpath_li.py from lxml import etree html = etree.parse('hello.html') result = html.xpath('//*[@class="bold"]') # tag方法可以获取标签名 print result[0].tag
输出结果:span