
3.4.4 lxml和XPath的结合使用
使用lxml来解析HTML代码,如以下实例所示。
【例3-28】使用lxml解析HTML代码
# 使用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文档 html = etree.HTML(text) # 按字符串序列化HTML文档 result = etree.tostring(html) print(result)
这里体现了lxml的一个非常实用的功能,就是自动修正HTML代码,大家应该注意到了,最后一个li标签,其实是把尾标签删掉了,是不闭合的。不过,因为继承了libxml2的特性,所以lxml具有自动修正HTML代码的功能。
因此运行结果如下:
<html> <body> <div> <ul> <li class="class-0"><a href="http://www.baidu.com">first item</a></li> <li class="class-1"><a href="http://www.douban.com">second item</a></li> <li class="class-2"><a href="http://www.weibo.com"><span class="se">th ird item</span></a></li> <li class="class-3"><a href="http://www.google.com">fourth item</a></li> <li class="class-4"><a href="http://www.zhihu.com">fifth item</a></li> </ul> </div> </body> </html>
lxml不仅能直接读取字符串,还支持从文件读取内容。比如我们新建一个文件,叫作test.html,内容为:
<div> <ul> <li class="class-0"><a href="http://www.baidu.com">first item</a></li> <li class="class-1"><a href="http://www.douban.com">second item</a></li> <li class="class-2"><a href="http://www.weibo.com"><span class="bold">th ird item</span></a></li> <li class="class-3"><a href="http://www.google.com">fourth item</a></li> <li class="class-4"><a href="http://www.zhihu.com">fifth item</a></li> </ul> </div>
下面以lxml与XPath结合使用的10个实例来展示XPath的强大之处。
【例3-29】利用parse方法来读取文件
1 from lxml import etree 2 html = etree.parse('test.html') 3 result = etree.tostring(html, pretty_print=True) 4 print(result)
此方法也能得到相同的结果。
若test.html内容与例3-28中标签内容相同,那么例3-29同样也能得到相同的结果。
【例3-30】获取所有的<li>标签
1 from lxml import etree 2 html = etree.parse('test.html') 3 print (type(html)) 4 result = html.xpath('//li') 5 print (result) 6 print (len(result)) 7 print (type(result)) 8 print (type(result[0]))
运行结果如下:
<class 'lxml.etree._ElementTree'> [<Element li at 0x1f5809048c8>, <Element li at 0x1f580904988>, <Element li at 0 x1f5809049c8>, <Element li at 0x1f580904a08>, <Element li at 0x1f580904a48>] 5 <class 'list'> <class 'lxml.etree._Element'>
由运行结果可知,etree.parse的类型是ElementTree,通过调用XPath(第4得到了一个列表(result是一个数组列表),其包含5个<li>元素,每个元素都是Element类型。
【例3-31】获取<li>标签的所有class
1 from lxml import etree 2 html = etree.parse('test.html') 3 print (type(html)) 4 result = html.xpath('//li/@class') 5 print (result)
运行结果如下:
<class 'lxml.etree._ElementTree'> ['class-0', 'class-1', 'class-2', 'class-3', 'class-4']
【例3-32】获取<li>标签下href为http://www.baidu.com的<a>标签
1 from lxml import etree 2 html = etree.parse('test.html') 3 result = html.xpath('//li/a[@href="http://www.baidu.com"]') 4 print (result)
运行结果如下:
[<Element a at 0x25d9c8038c8>]
【例3-33】获取<li>标签下的所有<span>标签
1 from lxml import etree 2 html = etree.parse('test.html') 3 result = html.xpath('//li//span') 4 print (result)
注意,这里为了获取<span>标签,使用的是双斜杠“//”。
运行结果如下:
[<Element span at 0x11fd9132908>]
【例3-34】获取<li>标签下的所有class,不包括<li>
1 from lxml import etree 2 html = etree.parse('test.html') 3 result = html.xpath('//li/a//@class') 4 print (result)
运行结果如下:
['se']
【例3-35】获取第一个<li>的<a>的href
1 from lxml import etree 2 html = etree.parse('test.html') 3 result = html.xpath('//li[1]/a/@href') 4 print (result)
运行结果如下:
['http://www.baidu.com']
【例3-36】获取最后一个<li>的<a>的href
1 from lxml import etree 2 html = etree.parse('test.html') 3 result = html.xpath('//li[last()]/a/@href') 4 print (result)
运行结果如下:
['http://www.zhihu.com']
【例3-37】获取倒数第二个<li>的<a>的内容
1 from lxml import etree 2 html = etree.parse('test.html') 3 result = html.xpath('//li[last()-1]/a') 4 print (result[0].text)
运行结果如下:
fourth item
【例3-38】获取class为"class-2"的标签名
1 from lxml import etree 2 html = etree.parse('test.html') 3 result = html.xpath('//*[@class="class-2"]') 4 print (result[0].tag)
运行结果如下:
li