作者:闲欢
来源:Python 技术
大家在写爬虫时,往往获取到网页之后,需要从网页中提取我们需要的信息。这时候就需要用到 xpath 或者 css 选择器来定位页面元素信息。但是,由于这两者都是非人性化的语法,导致好多人望而生畏,经常为这个发愁。
今天我就尝试用一篇文章来道尽 xpath 解析 HTML 的方方面面,希望大家看完这篇文章后,从此不再害怕 xpath 解析。
路径表达式
- nodename:选取此节点的所有子节点
- /:从当前节点选取直接子节点
- //:从当前接点选取子孙节点
- .:选取当前节点
- ..:选取当前接点的父节点
- @:选取属性
我们先放上一段 HTML 代码:
Xpath test page
百度
新闻频道
体育频道
接下来,我们针对这段 HTML 代码来进行 xpath 解析。
要进行 xpath 解析,我们先要将 HTML 文本转化成对象:
from lxml import etree
text = '''
first item
second item
third item
fourth item
fifth item # 注意,此处缺少一个 闭合标签
'''
# 调用HTML类进行初始化,这样就成功构造了一个XPath解析对象。
page = etree.HTML(text)
print(type(page))
我们可以看到打印的结果:
nodename
nodename 表示根据标签名字选取标签,注意只会选择子标签!比如:如果是儿子的儿子则选取不到。
print(page.xpath("body"))
//[]
print(page.xpath("ul"))
// []
这个 nodename 我有点不是太清楚,当我使用 body 时,可以找到出 body 节点元素,但是使用 ul 时,找不到 ul 节点元素,打印的是空。这个网上搜索也没有什么准确的答案,如果你知道这里面的原理,还请告诉我。
/
/ 表示从根节点选取一级一级筛选(不能跳)。
print(page.xpath("/html"))
// []
print(page.xpath("/body"))
// []
可以看到,我选取根节点 html ,可以打印出根节点元素,而我选取 body 打印时,是找不到的,这个符号只能从根节点开始找。
//
// 表示从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置。注意:是所有符合条件的。
print(page.xpath("//li"))
// [, , , , ]
.
. 表示选取当前标签。
ul = page.xpath("//ul")
print(ul)
print(ul[0].xpath("."))
print(ul[0].xpath("./li"))
// []
// []
// [, , , , ]
我们先定位到 ul 元素节点,这里的结果是一个列表,然后再打印当前节点列表的第一个 ul,接着我们打印这个 ul 节点的子节点 li。
..
.. 表示选取当前标签的父节点。
print(ul[0].xpath(".."))
// []
这里打印第一个 ul 节点的父元素,也就是 div 。
@
@ 表示获取标签的属性值。
print(ul[0].xpath("@id"))
// ['ultest']
我们打印第一个 ul 节点的 id 属性,可以看到结果是 ‘ultest’。
谓语
谓语用来查找某个或某些特定的节点或者包含某个指定值的节点。谓语被嵌在方括号中。
//a[n] n为大于零的整数,代表子元素排在第n个位置的元素
//a[last()] last() 代表子元素排在最后个位置的元素
//a[last()-] 和上面同理,代表倒数第二个
//a[position()2] price值大于2的元素
同样的,我们来举一些例子:
# 第三个li标签
print(page.xpath('//ul/li[3]'))
# 最后一个li标签
print(page.xpath('//ul/li[last()]'))
# 倒数第二个li标签
print(page.xpath('//ul/li[last()-1]'))
# 序号小于3的li标签
print(page.xpath('//ul/li[position()