python3爬虫(4)--使用XPath(lxml)解析数据(27种典型的爬虫匹配用法)

XPath,全称XML Path Language,即XML路径语言,它是一门在XML文档中查找信息的语言。它最初是用来搜寻XML文档的,但是它同样适用于HTML文档的搜索。所以在做爬虫时,我们完全可以使用XPath来做相应的信息抽取。

一、XPath的几个常用规则。

表达式描述
nodename选取此节点的所有子节点
/从当前节点选取直接子节点
//从当前节点选取子孙节点
.选取当前节点
..选取当前节点的父节点
@选取属性

示例如下:
//title[@name="description"]
这个XPath规则表示选择所有名称为title,同时属性name的值为description的节点。

二、python爬虫利用XPath进行HTML的解析

pip install lxml    #在Python中引用lxml库,利用XPath进行HTML的解析。

from lxml import etree        #导入lxml库的etree模块

2.1、tostring()方法修正HTML代码

import requests
from lxml import etree
text = '''
<div>
<ul>
    <li class="item-0"><a href="link1.html"> first item</a></1i> 
    <1i class="item-1"><a href="link2.html"> second item</a></1i>
    <li class="item-inactive"><a href="link3.html"> third item</a></1i>
    <1i class="item-1"><a href="link4.html"> fourth item</a></1i>
    <1i class="item-0"><a href="link5.html"> fifth item</a>
</ul>
</div>   
'''
html=etree.HTML(text) #直接输出HTML内容,发现最后一个li少一个</1i>
print(html) #输出:<Element html at 0x206c959d388>
result0=etree.tostring(html) #tostring()方法即可输出修正后的HTML代码
#print(result0)  #但格式输出bytes类型。
result= result0.decode('utf-8') #转化为容易阅读的HTML
print(type(result),'\n',result) #易于阅读的<class 'str'>

#写入
f = open('test.html', 'w')
f.write(result)
f.close()

#读取
html=etree.parse('./test.html',etree.HTMLParser())
print(html) #<lxml.etree._ElementTree object at 0x000001DFCD13D908>

2.2、XPath进行HTML的解析(27种典型用法)

from lxml import etree
import re
text = '''
<div>
    <td class="nobr player desktop">
        <a href="bucks" class="ng-binding" target="_parent" 
        href1="/teams/#!/bucks"><!-- ngIf: row.clinched -->密尔沃基&nbsp;雄鹿<b>nba</b></a>
    </td>
    <tr data-ng-repeat="(i, row) in page" index="0" class="ng-scope">
        <td class="nobr center bold ng-binding" href="href01">6</td>
        <td class="nobr center bold desktop ng-binding">18&nbsp;-&nbsp;4</td>
        <td class="nobr center bold desktop ng-binding">胜 6</td>
        <td class="nobr center bold desktop ng-binding">119.5</td>
    </tr>
</div>  
'''
html=etree.HTML(text) #利用 etree.HTML 初始化

r1=html.xpath('//*') #获取所有节点,*代表匹配所有节点,返回列表,每个元素都是一个Element对象
print(r1) #输出:[<Element html at 0x129bbb0f8c8>, <Element body at 0x129bbfbf188>, <Element div at 0x129bbfbf108>, <Element td at 0x129bbfbf0c8>, <Element a at 0x129bbfbf1c8>, <Element tr at 0x129bbfbf248>, <Element td at 0x129bbfbf288>, <Element td at 0x129bbfbf2c8>, <Element td at 0x129bbfbf308>, <Element td at 0x129bbfbf208>]

r2=html.xpath('//td') #获取所有的td节点
print(r2)#输出列表有5个元素:[<Element td at 0x1e072ddc488>, <Element td at 0x1e072ddc588>, <Element td at 0x1e072ddc5c8>, <Element td at 0x1e072ddc608>, <Element td at 0x1e072ddc508>]
print(r2[0]) #索引列表的第1个元素:<Element td at 0x1e072ddc488>

r3=html.xpath('//td/a') #获取td节点的子节点a,注意/为直属子节点,不能跳跃,如:"//div/a"则无返回值
print(r3) #输出列表有1个元素:[<Element a at 0x259d913c4c8>]

r4=html.xpath('//td//a') #获取td节点的所有子孙节点a
print(r4)#输出列表有1个元素:[<Element a at 0x259d913c4c8>]

r5=html.xpath('//div//a') #获取div节点的所有子孙节点a,/子节点不可以跳级,//子孙节点可以跳级
print(r5)#输出列表有1个元素:[<Element a at 0x259d913c4c8>]

r6=html.xpath('//a[@href="bucks"]') #定位到a节点
print(r6)#输出列表有1个元素:[<Element a at 0x259d913c4c8>]

r7=html.xpath('//a[@href="bucks"]/..') #获取a节点的父节点,父节点用/..
print(r7)#输出列表有1个元素:[<Element td at 0x1e072ddc488>]

r8=html.xpath('//a[@href="bucks"]/../@class') #获取a节点的父节点的class属性值
print(r8)#输出:['nobr player desktop']
r9=html.xpath('//a[@href="bucks"]/parent::*/@class')#也可以通过/parent::*来获取父节点
print(r9)#输出:['nobr player desktop']

r10=html.xpath('//td[@class="nobr center bold desktop ng-binding"]')#用@符号进行属性过滤
print(r10)#输出列表有3个元素,因为最后3个td节点的class属性值一样,[<Element td at 0x1e072ddc5c8>, <Element td at 0x1e072ddc608>, <Element td at 0x1e072ddc508>]
print(r10[0])#列表索引获取其中一个[<Element td at 0x1e072ddc5c8>]

r11=html.xpath('//a[@href="bucks"]/text()')#获取标签节点中的文本/text(),返回列表
print(r11)#输出:['密尔沃基\xa0雄鹿']

r12=html.xpath('//a[@href="bucks"]//text()')#获取标签节点和子孙节点的文本//text(),返回列表
print(r12)#输出:['密尔沃基\xa0雄鹿', 'nba']

r13=html.xpath('//a[@href="bucks"]/@href1') #获取属性的值/@属性名,返回列表
print(r13) #输出:['/teams/#!/bucks']

r14=html.xpath('//td[contains(@class,"nobr center bold")]/text()')#属性多值(模糊)匹配,contains()
print(r14) #输出:['6', '18\xa0-\xa04', '胜 6', '119.5']

r15=html.xpath('//td[contains(@class,"nobr") and @href="href01"]/text()')#多属性匹配
print(r15) #输出:['6']

#按序选择
r16=html.xpath('//td[1]/a//text()')#选择第1个td节点的a子接到的全部文本
print(r16)#输出:['密尔沃基\xa0雄鹿', 'nba']

r17=html.xpath('//td[last()]//text()')#选择最后一个td节点的全部文本
print(r17) #输出:['\n   ', '密尔沃基\xa0雄鹿', 'nba', '\n    ', '119.5'],可以想想为什么不是['119.5']

r18=html.xpath('//tr/td[position()<3]//text()')#选取了位置小于3的td节点
print(r18)#['6', '18\xa0-\xa04']

r19=html.xpath('//td[last()-2]//text()')#选择倒数第3个td节点的全部文本
print(r19)#['18\xa0-\xa04']

#节点轴选择
#XPath提供了很多节点轴选择方法,包括获取子元素、兄弟元素、父元素、祖先元素等
r20=html.xpath('//td[1]/ancestor::*')#调用了ancestor轴,可以获取所有祖先节点
print(r20)#[<Element html at 0x244f7b4a348>, <Element body at 0x244f7fe11c8>, <Element div at 0x244f7fe1148>, <Element tr at 0x244f7fe12c8>]

r21=html.xpath('//td[1]/ancestor::tr/@index')#加上限定条件的祖先节点
print(r21)#['0']

r22=html.xpath('//td[1]/attribute::*') #调用attribute轴,获取所有标签值
print(r22) #['nobr player desktop', 'nobr center bold ng-binding', 'href01']

r23=html.xpath('//tr/child::*/text()') #调用child轴,获取全部直属子节点
print(r23)#['6', '18\xa0-\xa04', '胜 6', '119.5']
#更多用法可以参考:https://www.w3school.com.cn/xpath/xpath_functions.asp
r24=html.xpath('//tr/child::td[@href="href01"]/text()')#获取限定条件的子节点
print(r24) #['6']

r25=html.xpath('//div/descendant::a/text()')#调用descendant轴,获取子孙节点
print(r25)#['密尔沃基\xa0雄鹿']

r26=html.xpath('//tr/td[1]/following::*[2]/text()')#调用了following轴,可以获取当前节点之后的所有节点。
print(r26)#['胜 6'],这里我们虽然使用的是*匹配,但又加了索引选择,所以只获取了第二个后续节点。

r27=html.xpath('//tr/td[1]/following-sibling::*[3]/text()')#following-sibling获取当前节点之后的所有同级节点。
print(r27) #['119.5'] ,用的是*匹配全部,但这里我们又加了索引选择

#更多用法可以参考:https://www.w3school.com.cn/xpath/xpath_functions.asp

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值