网络爬虫学习第五弹:lxml库的使用

lxml库使用

我们可以利用python中的lxml库来使用Xpath对HTML文档进行搜索。

选取节点:
nodename 选取此节点的所有子节点。
/ 从根节点选取。
// 从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置。
. 选取当前节点。
… 选取当前节点的父节点。
@ 选取属性。

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>
</ul>
</div>
'''
# 利用lxml库的etree模块调用HTML类将html文本进行初始化,构造一个Xpath解析对象。
html=etree.HTML(text) 
result=etree.tostring(html) # 调用tostring()的方法可以输出修正后的HTML代码
print(type(result))
print(result.decode('utf-8')) # 结果是bytes类型,利用decode()将其转化为str类型

#以下输出结果中,残缺的html文本被补全,并且自动添加了body、html节点
<class 'bytes'>
<html><body><div>
<ul>
<li class="item-0"><a href="link1.html">first item</a><a/></li>
<li class="item-1"><a href="link2.html">second item</a><a/></li>
<li class="item-inactive"><a href="link3.html">third item</a><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>
</body></html>
# 也可以直接读取文件进行解析
from lxml import etree

html=etree.parse('./test.html',etree.HTMLParser())
result=etree.tostring(html)
print(result.decode('utf-8'))
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html><body><p>from lxml import etree&#13;
text = '''&#13;
</p><div>&#13;
    <ul>&#13;
         <li class="item-0"><a href="link1.html">first item</a></li>&#13;
         <li class="item-1"><a href="link2.html">second item</a></li>&#13;
         <li class="item-inactive"><a href="link3.html">third item</a></li>&#13;
         <li class="item-1"><a href="link4.html">fourth item</a></li>&#13;
         <li class="item-0"><a href="link5.html">fifth item</a>&#13;
     </li></ul>&#13;
 </div>&#13;
'''&#13;
html = etree.HTML(text)&#13;
result = etree.tostring(html)&#13;
print(result)</body></html>

所有节点

一般用 // 开头的XPath规则来选择所有符合要求的节点。

from lxml import etree
'''这里使用*来匹配所有节点,整个html文本的所有节点都会被获取。
   返回一个列表,每个元素是Element类型,其后跟了节点的名称。'''
html=etree.parse('./test.html',etree.HTMLParser())
result=html.xpath('//*') 
print(result)
[<Element html at 0x280b7673808>, <Element body at 0x280b764be48>, <Element p at 0x280b764bb88>, <Element div at 0x280b75d54c8>, <Element ul at 0x280b76736c8>, <Element li at 0x280b76738c8>, <Element a at 0x280b76735c8>, <Element li at 0x280b7673308>, <Element a at 0x280b7673848>, <Element li at 0x280b7673908>, <Element a at 0x280b7673508>, <Element li at 0x280b7673448>, <Element a at 0x280b7673408>, <Element li at 0x280b7673a48>, <Element a at 0x280b7673cc8>]
from lxml import etree

html=etree.parse('./test.html',etree.HTMLParser())
# 选取所有li节点,可以使用//,直接加上节点名称即可,调用时直接使用xpath()方法
result=html.xpath('//li')
print(result)
[<Element li at 0x280b7626d08>, <Element li at 0x280b7673a08>, <Element li at 0x280b7673f48>, <Element li at 0x280b7673f88>, <Element li at 0x280b7673fc8>]

子节点

通过 / 或 // 来查找元素的节点或子孙节点

from lxml import etree

html=etree.parse('./test.html',etree.HTMLParser())
result=html.xpath('//li/a') # 查找li节点中的所有直接a子节点
print(result)
[<Element a at 0x280b75d5408>, <Element a at 0x280b7673f08>, <Element a at 0x280b7673dc8>, <Element a at 0x280b76735c8>, <Element a at 0x280b7673308>]
from lxml import etree

html=etree.parse('./test.html',etree.HTMLParser())
result=html.xpath('//ul//a') # 查找ul节点下的所有a节点。
print(result)
# 如果用//ul/a就不会返回结果,因为a不是ul的直接节点
[<Element a at 0x280b764b448>, <Element a at 0x280b7673e48>, <Element a at 0x280b7673d08>, <Element a at 0x280b7673e08>, <Element a at 0x280b7673408>]

父节点

当我们知道了子节点后,我们可以用 … 来查找父节点

from lxml import etree

html=etree.parse('./test.html',etree.HTMLParser())
# 查找顺序:<a href='link4.html'>-->(直接父节点<li>)-->直接属性class的内容
result=html.xpath('//a[@href="link4.html"]/../@class')
print(result)
['item-1']
from lxml import etree

html=etree.parse('./test.html',etree.HTMLParser())
result=html.xpath('//a[@href="link4.html"]/parent::*/@class') #也可以用parent::来获取
print(result)
['item-1']

属性匹配

我们可以通过@符号进行属性过滤

from lxml import etree

html=etree.parse('./test.html',etree.HTMLParser())
result=html.xpath('//li[@class="item-0"]') # 选取属性class为'item-0'的li节点
print(result)
[<Element li at 0x280b7671bc8>, <Element li at 0x280b7673f08>]

文本获取

利用text()方法获取节点中文本

from lxml import etree
# 获取所有<li class='item-0'>节点的文本,法一:
html=etree.parse('./test.html',etree.HTMLParser())
# 因为文本内容实际在a节点内,所以先要进入a节点,再用text()方法进行提取文本
result=html.xpath('//li[@class="item-0"]/a/text()')
print(result)
['first item', 'fifth item']
from lxml import etree
# 获取所有<li class='item-0'>节点的文本,法二:
html=etree.parse('./test.html',etree.HTMLParser())
#使用//获取其节点下所有文本内容,其中\r\n是补全后li节点内的内容
result=html.xpath('//li[@class="item-0"]//text()')
print(result)
['first item', 'fifth item', '\r\n     ']

属性获取

同样用@可以用来获取属性

from lxml import etree

html=etree.parse('./test.html',etree.HTMLParser())
result=html.xpath('//li/a/@href') # 匹配所有li节点下a节点的href属性
print(result)
['link1.html', 'link2.html', 'link3.html', 'link4.html', 'link5.html']

属性多值匹配

当某些节点的属性包含多个值时,就无法单纯的用xpath()方法匹配,此时需要用contains()方法,第一个参数传入属性名称,第二个参数传入属性值。

from lxml import etree

text='''
<li class="li li-first"><a href="link.html">first item</a></li>
'''
html=etree.HTML(text)
result=html.xpath('//li[contains(@class,"li")]/a/text()')
print(result)
['first item']

多属性匹配

当多个属性确定一个节点时,我们需要同时匹配多个属性,此时可以用运算符 and 来连接

from lxml import etree

text='''
<li class="li li-first" name="item"><a href="link.html">first item</a></i>
'''
html=etree.HTML(text)
result=html.xpath('//li[contains(@class,li) and @name="item"]/a/text()')
print(result)
['first item']

按序选择

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"><span class="bold">third item</span></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>
'''
html=etree.HTML(text)
result=html.xpath('//li[1]/a/text()') # 查找第一个li节点内的文本
print(result)
result=html.xpath('//li[last()]/a/text()') # 查找最后一个节点内的文本
print(result)
result=html.xpath('//li[position()<3]/a/text()') # 查找位置小于3的文本
print(result)
result=html.xpath('//li[last()-2]/a/text()') # 查找倒数第三位的节点
print(result)
['first item']
['fifth item']
['first item', 'second item']
[]

节点轴选择

ancestor:匹配当前节点的所有祖先节点
attribute:匹配当前节点的所有属性值
child:匹配当前节点的所有子节点
decendant:匹配当前节点的所有子孙节点
following:匹配当前节点之后的所有节点
following-sibling:匹配当前节点之后的所有同级节点

from lxml import etree

text='''
<div>
    <ul>
         <li class="item-0"><a href="link1.html"><span>first item</span></a></li>
         <li class="item-1"><a href="link2.html">second item</a></li>
         <li class="item-inactive"><a href="link3.html"><span class="bold">third item</span></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>
'''
html=etree.HTML(text)
result=html.xpath('//li[1]/ancestor::*') # 调用ancestor轴,匹配第一个li节点的所有祖先节点
print(result)
result=html.xpath('//li[1]/ancestor::div') # 调用ancestor轴,匹配第一个li节点的祖先节点中的div节点
print(result)
result=html.xpath('//li[1]/attribute::*') # 调用attribute轴,匹配第一个li节点的所有属性值
print(result)
result=html.xpath('//li[1]/child::a[@href="link1.html"]') # 调用child轴,匹配第一个li节点的中特定属性的a节点
print(result)
result=html.xpath('//li[1]/descendant::span') # 调用descendant轴,匹配第一个节点的所有子孙节点中的span节点
print(result)
result=html.xpath('//li[1]/following::*[2]') # 调用following轴,匹配第一个节点的后续节点的第二个节点
print(result)
result=html.xpath('//li[1]/following-sibling::*') # 调用following-sibling轴,获取第一个li节点的所有同级节点
print(result)
[<Element html at 0x280b765ee08>, <Element body at 0x280b7673408>, <Element div at 0x280b767c708>, <Element ul at 0x280b767cdc8>]
[<Element div at 0x280b767c708>]
['item-0']
[<Element a at 0x280b7687cc8>]
[<Element span at 0x280b7680208>]
[<Element a at 0x280b767c708>]
[<Element li at 0x280b7673408>, <Element li at 0x280b7680208>, <Element li at 0x280b7680248>, <Element li at 0x280b7680348>]

参考:崔庆才《python3网络爬虫开发实战》

  • 6
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值