XPath 的使用
XPath,全称XML Path Language,即XML路径语言,它是一门在XML文档中查找信息的语言,最初用于搜寻XML文档,但是也同样适用于HTML文档的搜索。前面我们在解析或抽取网页信息时,使用的是正则表达式,虽然这是一个万能的方法,但是编写太麻烦了,一旦表达式写错就得不到正确的结果,还有就是可读性不强,写完后估计自己也不知道这是啥回事了,所以在爬虫时可以使用XPath来做相应数据的抽取。
先列举XPath的常用规则:
举例:
//title[@lang='eng'] 代表选择所有名称为 title,同时属性lang的值为eng的节点。
1. 实例
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> ''' # 实例化一个XPath对象 etree.HTML(html文档) html = etree.HTML(text) result = etree.tostring(html) print(result.decode('utf-8'))
首先导入lxml库的etree模块,然后声明了一段HTML文本,调用etree.HTML()初始化,这样就构造了一个XPath解析对象了。
2. 所有节点
使用//开头的XPath规则来选择所有符合的几点,以上面的HTML文本为例,如果要选取所有节点,可以这样实现:
from lxml import etree html = etree.parse('./test.html',etree.HTMLParser()) result = html.xpath('//*') print(result)
这里使用*代表所有节点,也就是整个HTML文本中的所有节点都会被获取。返回的是一个列表,每个元素都是一个Element类型。
当然,此处匹配也可以指定节点:
from lxml import etree html = etree.parse('./test.html',etree.HTMLParser()) result = html.xpath('//li') print(result)
这里选取的是所有li节点,使用//然后直接加上节点名称即可,调用时直接使用xpath()方法即可。
3. 子节点
可以使用//或/来获取子节点,前者包括子孙节点,而后者仅仅是直接子节点:
from lxml import etree html = etree.parse('./test.html',etree.HTMLParser()) result = html.xpath('//li/a') print(result)
上面得到的是一个包含所有li元素里面的直接子节点a的一个列表。
from lxml import etree html = etree.parse('./test.html',etree.HTMLParser()) result = html.xpath('//ul//a')
上面获取到的是所有ul节点中的所有a节点。
注意/和//的区别,/用于获取直接子节点,//用于获取子孙节点
4. 父节点
使用..可以查找父节点:
from lxml import etree html = etree.parse('./test.html',etree.HTTPParser()) result = html.xpath('//a[@href="link4.html"]/../@class') print(result)
上面获取到的就是href属性为link4.html的所有a节点的父节点的class属性
除此以外,还可以使用parent::来获取父节点:
from lxml import etree html = etree.parse('./test.html',etree.HTTPParser()) result = html.xpath('//a[@href="link4.html"]/parent::*/@class')
5. 属性匹配
使用@符号进行属性过滤,比如要选取class为item-1的li节点,可以这样实现:
from lxml import etree html = etree.parse('./test.html',etree.HTTPParser()) result = html.xpath('//li[@class="item-1"]')
6. 文本获取
使用text()方法既可获取节点中的文本(标签体):
from lxml import etree html = etree.parse('./test.html',etree.HTMLParser()) result = html.xpath('//li[@class="item-0"]/a/text()') print(result)