xpath语法是解析网页最常用的方法之一,本文讲解一下如何在lxml库中使用xpath语法进行网页的解析。
本文分为如下几个部分
- 解析html流程说明
- 提取内容
- 识别标签
解析html流程说明
我们先看一个例子了解使用lxml的流程
在下面的html代码中其提取如下部分
- 标题
- 文字1
- 文字1和文字2
- 列表1第1项 列表1第2项
a = '''<title>标题</title>
<body>
<ul class='list1'>
<li>列表1第1项</li>
<li>列表1第2项</li>
</ul>
<p class='first'>文字1</p>
<p class='second'>文字2</p>
<ul class='list2'>
<li>列表2第1项</li>
<li>列表2第2项</li>
</ul>
</body>'''
from lxml import etree
html = etree.HTML(a)
html.xpath('//title/text()')[0] # '标题'
html.xpath("//p[@class='first']//text()")[0] # '文字1'
html.xpath("//p/text()") # ['文字1', '文字2']
html.xpath("//ul[@class='list1']/li/text()") # ['列表1第1项', '列表1第2项']
可以先总结一下xpath语法的一些规律
- 用xpath语法提取基于节点路径,每次只要输入一个字符串,字符串按照格式填写就能完成提取
- 格式是一层层的节点,用
/
分离,通过[]
在后面加入该节点的属性判断来唯一确定节点位置 - 提取的结果永远是list,最后都要用索引提取
- 不特殊指定的情况下会自动寻找所有满足条件的结果,可以在提取结果中用索引筛选,也可以在xpath内部使用索引
- 语法中分隔节点有两种方法
/
和//
,它们之间的差别在于,前者只寻找子节点,后者会寻找子孙所有后代的节点,将所有满足条件的全都找到 - 刚开始总是用
//
是因为我们不会从第一个节点一个一个写,写到我们想要的节点上去,这样代码就太长了。所以直接从中间找到一个便于唯一确定我们要找的位置的节点,再往后找就行了 - xpath好像不能查看一个节点所有属性以及专门去判断有没有某属性等
接下来我们来讲提取细节,首先加载库
from lxml import etree
提取内容
因为xpath提取到的整个标签展现形式是这样的[<Element h1 at 0x2122e994748>]
,所以先讲如何提取内容,之后讲如何提取标签时,才好根据输出内容来区分提出来的是什么东西。
提取内容分为两个部分
- 提取标签内容,用
/text()
- 提取标签属性值,用
/@属性名
见如下代码
a = '''
<body>
<h><a href='www.biaoti.com'>head</a></h>
<p>段落1</p>
<p>段落2</p>
</body>
'''
html = etree.HTML(a)
html.xpath('//h') # [<Element h at 0x2122e64e4c8>]
# 用//text() 提取标签内容
html.xpath('//h//text()') # ['head']
# /text()和//text()的区别在于不可以提取孙节点的内容
html.xpath('//h/a/text()') # ['head']
# xpath语法默认提取全部
html.xpath('//p/text()') # ['段落1', '段落2']
html.xpath('//p[1]/text()') # ['段落1']
# html.xpath('//body//text()') # ['\n ', 'head', '\n ', '段落1', '\n ', '段落2', '\n']
# 提取标签属性
html.xpath('//h/a/@href') # ['www.biaoti.com']
识别标签
只根据标签来识别
xpath语法对正则表达式支持比较弱,正则的使用主要体现在属性的筛选上,所以这里就不使用正则了
a = '''
<body>
<h1>head</h1>
<h2>标题2</h2>
<h2>标题3</h2>
</body>
'''
html = etree.HTML(a)
# 只提取标签时地址形式,用tostring转化为字符串形式,但是对中文转化会乱码
html.xpath('//h1') # [<Element h1 at 0x2122e6d8dc8>]
etree.tostring(html.xpath('//h1')[0]) # b'<h1>head</h1>\n '
# 简单提取标签
html.xpath('//h1/text()') # 一个列表 ['head']
html.xpath('//h1/text()')[0] # 提取出成字符串 'head'
# 使用“或”运算符
html.xpath('(//h1|//h2)/text()')
同时根据标签和属性识别
a = '''
<p id='p1'>段落1</p>
<p id='p2'>段落2</p>
<p class='p3'>段落3</p>
<p class='p3' id='pp'>段落4</p>
'''
html = etree.HTML(a)
html.xpath('//p[@id="p1"]/text()') # ['段落1']
html.xpath('//p[@class]/text()') # 含有这个属性 ['段落3', '段落4']
html.xpath('//p[@class="p3" and @id="pp"]/text()') # 使用多个属性同时满足 ['段落4']
html.xpath('//p[@class or @id="p1"]/text()') # 多个属性满足一个即可 ['段落1', '段落3', '段落4']
html.xpath('//p[@id="p1" or @id="p2"]/text()') # ['段落1', '段落2']
html.xpath('//p[not(@id) and @class="p3"]/text()') # 不含有id属性 ['段落3']
html.xpath('//*[@id="p1"]/text()') # 不需要任意标签名皆可 ['段落1']
# 类似正则表达式
html.xpath('//p[starts-with(@id,"p")]/text()') # 匹配开头 ['段落1', '段落2', '段落4']
html.xpath('//p[contains(@id,"1")]/text()') # 包含即可 ['段落1']
# 正则表达式
html.xpath(r'//p[re:match(@id, "^p")]/text()', namespaces={"re": "http://exslt.org/regular-expressions"}) # 这里的match是包含的意思
根据标签内内容来识别
根据内容来识别和根据属性非常相似
a = '''
<p id='p1'>段落1</p>
<p class='p3'>段落2</p>
<p class='p3'>文章</p>
<p></p>
'''
html = etree.HTML(a)
html.xpath('//p[text()="文章"]/@class') # ['p3']
html.xpath('//p[text()="段落1" or text()="段落2"]/@*') # 提取任意属性 ['p1', 'p3']
html.xpath('//p[starts-with(text(),"段落")]/@*') # ['p1', 'p3']
html.xpath(r'//p[re:match(text(), "^段落")]/@*', namespaces={"re": "http://exslt.org/regular-expressions"}) # ['p1', 'p3']
根据位置识别
相比于Beautifulsoup,xpath对位置的把握更加灵活
a = '''<title>标题</title>
<body>
<ul class='list1'>
<li>列表1第1项</li>
<li>列表1第2项</li>
</ul>
<p class='first'>文字1</p>
<p class='second'>文字2</p>
<ul class='list2'>
<li>列表2第1项</li>
<li>列表2第2项</li>
</ul>
</body>'''
html = etree.HTML(a)
html.xpath('//ul[2]/li/text()') # 在xpath语句中使用索引,限制只在第二个ul中寻找
html.xpath('//ul/li[1]/text()') # 在每个ul中取第一个li
# ['列表2第1项', '列表2第2项']
html.xpath('//ul[last()]/li/text()') # 取最后一个
html.xpath('//ul[last()-1]/li/text()') # 倒数第二个
html.xpath('//ul[position()<3]/li/text()') # 前两个
另外,如果想看xpath语句的列表,可以参考如下资料
因为网页结构繁多,不可能总结一篇覆盖所有可能情况,所以实际使用时如果无法找到匹配的方法,可以借助搜索引擎。
使用xpath进行真实网页的爬虫练习可以看这篇文章xpath+mongodb抓取伯乐在线实战
专栏信息
专栏主页:python编程
专栏目录:目录
爬虫目录:爬虫系列目录
版本说明:软件及包版本说明