python解析库lxml的简单使⽤
阅读⽬录
lxml是python的⼀个解析库,⽀持HTML和XML的解析,⽀持XPath解析⽅式,⽽且解析效率⾮常⾼
XPath,全称XML Path Language,即XML路径语⾔,它是⼀门在XML⽂档中查信息的语⾔,它最初是⽤来搜寻XML⽂档的,但是它同样适⽤于HTML⽂档的搜索
XPath的选择功能⼗分强⼤,它提供了⾮常简明的路径选择表达式,另外,它还提供了超过100个内建函数,⽤于字符串、数值、时间的匹配以及节点、序列的处理等,⼏乎所有我们想要定位的节点,都可以⽤XPath来选择XPath于1999年11⽉16⽇成为W3C标准,它被设计为供XSLT、XPointer以及其他XML解析软件使⽤,更多的⽂档可以访问其官⽅⽹站:
1、python库lxml的安装
windows系统下的安装:
#pip安装
pip3 install lxml
#wheel安装
#下载对应系统版本的wheel⽂件:www.lfd.uci.edu/~gohlke/pythonlibs/#lxml
pip3 install lxml-4.2.1-cp36-cp36m-win_amd64.whl
linux下安装:
yum install -y epel-release libxslt-devel libxml2-devel openssl-devel
pip3 install lxml
验证安装:
$python3
>>>import lxml
2、XPath常⽤规则
表达式描述
nodename选取此节点的所有⼦节点
/从当前节点选取直接⼦节点
//从当前节点选取⼦孙节点
.选取当前节点
..选取当前节点的⽗节点
@选取属性
*通配符,选择所有元素节点与元素名
@*选取所有属性
[@attrib]选取具有给定属性的所有元素
[@attrib='value']选取给定属性具有给定值的所有元素
[tag]选取所有具有指定元素的直接⼦节点
[tag='text']选取所有具有指定元素并且⽂本内容是text节点
(1)读取⽂本解析节点
from lxml import etree
text='''
<div>
<ul>
<li class="item-0"><a href="link1.html">第⼀个</a></li>
<li class="item-1"><a href="link2.html">second item</a></li>
<li class="item-0"><a href="link5.html">a属性</a>
</ul>
</div>
'''
html=etree.HTML(text) #初始化⽣成⼀个XPath解析对象
string(html,encoding='utf-8') #解析对象输出代码
print(type(html))
print(type(result))
print(result.decode('utf-8'))
#etree会修复HTML⽂本节点
<_Element'>
<class'bytes'>
<html><body><div>
<ul>
<li class="item-0"><a href="link1.html">第⼀个</a></li>
<li class="item-1"><a href="link2.html">second item</a></li>
<li class="item-0"><a href="link5.html">a属性</a>
</li></ul>
</div>
</body></html>
(2)读取HTML⽂件进⾏解析
from lxml import etree
html=etree.parse('test.html',etree.HTMLParser()) #指定解析器HTMLParser会根据⽂件修复HTML⽂件中缺失的如声明信息
string(html) #解析成字节
#stringlist(html) #解析成列表
print(type(html))
print(type(result))
print(result)
#
<_ElementTree'>
<class'bytes'>
b'<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "/TR/REC-html40/loose.dtd">\n<html><body><div>
\n <ul>
\n <li class="item-0"><a href="link1.html">first item</a></li>
\n <li class="item-1"><a href=(3)获取所有节点
返回⼀个列表每个元素都是Element类型,所有节点都包含在其中
from lxml import etree
html=etree.parse('test',etree.HTMLParser())
result=html.xpath('//*') #//代表获取⼦孙节点,*代表获取所有
print(type(html))
print(type(result))
print(result)
#
<_ElementTree'>
<class'list'>
[<Element html at 0x754b210048>, <Element body at 0x754b210108>, <Element div at 0x754b210148>, <Element ul at 0x754b210188>, <Element li at 0x754b2101c8>, <Element a at 0x754b210248>, <Element li at 0x754b210288>, <Element a at 0x754b2102c 如要获取li节点,可以使⽤//后⾯加上节点名称,然后调⽤xpath()⽅法
html.xpath('//li') #获取所有⼦孙节点的li节点
(4)获取⼦节点
通过/或者//即可查元素的⼦节点或者⼦孙节点,如果想选择li节点的所有直接a节点,可以这样使⽤
result=html.xpath('//li/a') #通过追加/a选择所有li节点的所有直接a节点,因为//li⽤于选中所有li节点,/a⽤于选中li节点的所有直接⼦节点a
(5)获取⽗节点
我们知道通过连续的/或者//可以查⼦节点或⼦孙节点,那么要查⽗节点可以使⽤..来实现也可以使⽤parent::来获取⽗节点
from lxml import etree
import HTMLParser
text='''
<div>
<ul>
<li class="item-0"><a href="link1.html">第⼀个</a></li>
<li class="item-1"><a href="link2.html">second item</a></li>
</ul>
</div>
'''
html=etree.HTML(text,etree.HTMLParser())
result=html.xpath('//a[@href="link2.html"]/../@class')
result1=html.xpath('//a[@href="link2.html"]/parent::*/@class')
print(result)
print(result1)
#
['item-1']
['item-1']
(6)属性匹配
在选取的时候,我们还可以⽤@符号进⾏属性过滤。⽐如,这⾥如果要选取class为item-1的li节点,可以这样实现:
from lxml import etree
import HTMLParser
text='''
<div>
<ul>
<li class="item-0"><a href="link1.html">第⼀个</a></li>
<li class="item-1"><a href="link2.html">second item</a></li>
</ul>
</div>
'''
html=etree.HTML(text,etree.HTMLParser())
result=html.xpath('//li[@class="item-1"]')
print(result)
(7)⽂本获取
我们⽤XPath中的text()⽅法获取节点中的⽂本
from lxml import etree
text='''
<div>
<ul>
<li class="item-0"><a href="link1.html">第⼀个</a></li>
<li class="item-1"><a href="link2.html">second item</a></li>
</ul>
</div>
'''
html=etree.HTML(text,etree.HTMLParser())
result=html.xpath('//li[@class="item-1"]/a/text()') #获取a节点下的内容
result1=html.xpath('//li[@class="item-1"]//text()') #获取li下所有⼦孙节点的内容
print(result)
print(result1)
(8)属性获取
使⽤@符号即可获取节点的属性,如下:获取所有li节点下所有a节点的href属性
result=html.xpath('//li/a/@href') #获取a的href属性
result=html.xpath('//li//@href') #获取所有li⼦孙节点的href属性
(9)属性多值匹配
如果某个属性的值有多个时,我们可以使⽤contains()函数来获取
from lxml import etree
text1='''
<div>
<ul>
<li class="aaa item-0"><a href="link1.html">第⼀个</a></li>
<li class="bbb item-1"><a href="link2.html">second item</a></li>
</ul>
</div>
'''
html=etree.HTML(text1,etree.HTMLParser())
result=html.xpath('//li[@class="aaa"]/a/text()')
result1=html.xpath('//li[contains(@class,"aaa")]/a/text()')
print(result)
print(result1)
#通过第⼀种⽅法没有取到值,通过contains()就能精确匹配到节点了
[]
['第⼀个']
(10)多属性匹配
另外我们还可能遇到⼀种情况,那就是根据多个属性确定⼀个节点,这时就需要同时匹配多个属性,此时可⽤运⽤and运算符来连接使⽤:
from lxml import etree
text1='''
<div>
<ul>
<li class="aaa" name="item"><a href="link1.html">第⼀个</a></li>
<li class="aaa" name="fore"><a href="link2.html">second item</a></li>
</ul>
</div>
'''
html=etree.HTML(text1,etree.HTMLParser())
result=html.xpath('//li[@class="aaa" and @name="fore"]/a/text()')
result1=html.xpath('//li[contains(@class,"aaa") and @name="fore"]/a/text()')
print(result)
print(result1)
#
['second item']
['second item']
(11)XPath中的运算符
运算符描述实例返回值
or或age=19 or age=20如果age等于19或者等于20则返回true反正返回false
and与age>19 and age<21如果age等于20则返回true,否则返回false
mod取余 5 mod 21
|取两个节点的集合//book | //cd返回所有拥有book和cd元素的节点集合
+加6+410
-减6-42
*乘6*424
div除法8 div 42
=等于age=19true
!=不等于age!=19true
<⼩于age<19true
<=⼩于或等于age<=19true
>⼤于age>19true
>= ⼤于或等于age>=19true
此表参考来源:
(12)按序选择
有时候,我们在选择的时候某些属性可能同时匹配多个节点,但我们只想要其中的某个节点,如第⼆个节点或者最后⼀个节点,这时可以利⽤中括号引⼊索引的⽅法获取特定次序的节点:from lxml import etree
text1='''
<div>
<ul>
<li class="aaa" name="item"><a href="link1.html">第⼀个</a></li>
<li class="aaa" name="item"><a href="link1.html">第⼆个</a></li>
<li class="aaa" name="item"><a href="link1.html">第三个</a></li>
<li class="aaa" name="item"><a href="link1.html">第四个</a></li>
</ul>
</div>
'''
html=etree.HTML(text1,etree.HTMLParser())
result=html.xpath('//li[contains(@class,"aaa")]/a/text()') #获取所有li节点下a节点的内容
result1=html.xpath('//li[1][contains(@class,"aaa")]/a/text()') #获取第⼀个
result2=html.xpath('//li[last()][contains(@class,"aaa")]/a/text()') #获取最后⼀个
result3=html.xpath('//li[position()>2 and position()<4][contains(@class,"aaa")]/a/text()') #获取第⼀个
result4=html.xpath('//li[last()-2][contains(@class,"aaa")]/a/text()') #获取倒数第三个
print(result)
print(result1)
print(result2)
print(result3)
print(result4)
#
['第⼀个', '第⼆个', '第三个', '第四个']
['第⼀个']
['第四个']
['第三个']
['第⼆个']
这⾥使⽤了last()、position()函数,在XPath中,提供了100多个函数,包括存取、数值、字符串、逻辑、节点、序列等处理功能,它们的具体作⽤可参考:
(13)节点轴选择
XPath提供了很多节点选择⽅法,包括获取⼦元素、兄弟元素、⽗元素、祖先元素等,⽰例如下:
from lxml import etree
text1='''
<div>
<ul>
<li class="aaa" name="item"><a href="link1.html">第⼀个</a></li>
<li class="aaa" name="item"><a href="link1.html">第⼆个</a></li>
<li class="aaa" name="item"><a href="link1.html">第三个</a></li>
<li class="aaa" name="item"><a href="link1.html">第四个</a></li>
</ul>
</div>
'''
html=etree.HTML(text1,etree.HTMLParser())
result=html.xpath('//li[1]/ancestor::*') #获取所有祖先节点
result1=html.xpath('//li[1]/ancestor::div') #获取div祖先节点
result2=html.xpath('//li[1]/attribute::*') #获取所有属性值
result3=html.xpath('//li[1]/child::*') #获取所有直接⼦节点
result4=html.xpath('//li[1]/descendant::a') #获取所有⼦孙节点的a节点
result5=html.xpath('//li[1]/following::*') #获取当前⼦节之后的所有节点
result6=html.xpath('//li[1]/following-sibling::*') #获取当前节点的所有同级节点
#
[<Element html at 0x3ca6b960c8>, <Element body at 0x3ca6b96088>, <Element div at 0x3ca6b96188>, <Element ul at 0x3ca6b961c8>]
[<Element div at 0x3ca6b96188>]
['aaa', 'item']
[<Element a at 0x3ca6b96248>]
[<Element a at 0x3ca6b96248>]
[<Element li at 0x3ca6b96308>, <Element a at 0x3ca6b96348>, <Element li at 0x3ca6b96388>, <Element a at 0x3ca6b963c8>, <Element li at 0x3ca6b96408>, <Element a at 0x3ca6b96488>] [<Element li at 0x3ca6b96308>, <Element li at 0x3ca6b96388>, <Element li at 0x3ca6b96408>]
以上使⽤的是XPath轴的⽤法,更多轴的⽤法可参考:
(14)案例应⽤:抓取TIOBE指数前20名排⾏开发语⾔
#!/usr/bin/env python
#coding:utf-8
import requests
ptions import RequestException
from lxml import etree
import ParseError
import json
def one_to_page(html):
headers={
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.62 Safari/537.36'
}xpath语法 python
try:
(html,headers=headers)
#获取⽹页内容
except RequestException as e:
print('request is error!',e)
try:
html=etree.HTML(body,etree.HTMLParser()) #解析HTML⽂本内容
result=html.xpath('//table[contains(@class,"table-top20")]/tbody/tr//text()') #获取列表数据
pos = 0
for i in range(20):
if i == 0:
yield result[i:5]
else:
yield result[pos:pos+5] #返回排名⽣成器数据
pos+=5
except ParseError as e:
print(e.position)
def write_file(data): #将数据重新组合成字典写⼊⽂件并输出
for i in data:
sul={
'2018年6⽉排⾏':i[0],
'2017年6排⾏':i[1],
'开发语⾔':i[2],
'评级':i[3],
'变化率':i[4]
}
with open('','a',encoding='utf-8') as f:
f.write(json.dumps(sul,ensure_ascii=False) + '\n') #必须格式化数据
f.close()
print(sul)
return None
def main():
url='www.tiobe/tiobe-index/'
data=one_to_page(url)
revaule=write_file(data)
if revaule == None:
print('ok')
if__name__ == '__main__':
main()
#
{'2018年6⽉排⾏': '1', '2017年6排⾏': '1', '开发语⾔': 'Java', '评级': '15.368%', '变化率': '+0.88%'}
{'2018年6⽉排⾏': '2', '2017年6排⾏': '2', '开发语⾔': 'C', '评级': '14.936%', '变化率': '+8.09%'}
{'2018年6⽉排⾏': '3', '2017年6排⾏': '3', '开发语⾔': 'C++', '评级': '8.337%', '变化率': '+2.61%'}
{'2018年6⽉排⾏': '4', '2017年6排⾏': '4', '开发语⾔': 'Python', '评级': '5.761%', '变化率': '+1.43%'}
{'2018年6⽉排⾏': '5', '2017年6排⾏': '5', '开发语⾔': 'C#', '评级': '4.314%', '变化率': '+0.78%'}
{'2018年6⽉排⾏': '6', '2017年6排⾏': '6', '开发语⾔': 'Visual Basic .NET', '评级': '3.762%', '变化率': '+0.65%'}
{'2018年6⽉排⾏': '7', '2017年6排⾏': '8', '开发语⾔': 'PHP', '评级': '2.881%', '变化率': '+0.11%'}
{'2018年6⽉排⾏': '8', '2017年6排⾏': '7', '开发语⾔': 'JavaScript', '评级': '2.495%', '变化率': '-0.53%'}
{'2018年6⽉排⾏': '9', '2017年6排⾏': '-', '开发语⾔': 'SQL', '评级': '2.339%', '变化率': '+2.34%'}
{'2018年6⽉排⾏': '10', '2017年6排⾏': '14', '开发语⾔': 'R', '评级': '1.452%', '变化率': '-0.70%'}
{'2018年6⽉排⾏': '11', '2017年6排⾏': '11', '开发语⾔': 'Ruby', '评级': '1.253%', '变化率': '-0.97%'}
{'2018年6⽉排⾏': '12', '2017年6排⾏': '18', '开发语⾔': 'Objective-C', '评级': '1.181%', '变化率': '-0.78%'}
{'2018年6⽉排⾏': '13', '2017年6排⾏': '16', '开发语⾔': 'Visual Basic', '评级': '1.154%', '变化率': '-0.86%'}
{'2018年6⽉排⾏': '14', '2017年6排⾏': '9', '开发语⾔': 'Perl', '评级': '1.147%', '变化率': '-1.16%'}
{'2018年6⽉排⾏': '15', '2017年6排⾏': '12', '开发语⾔': 'Swift', '评级': '1.145%', '变化率': '-1.06%'}
{'2018年6⽉排⾏': '16', '2017年6排⾏': '10', '开发语⾔': 'Assembly language', '评级': '0.915%', '变化率': '-1.34%'}
{'2018年6⽉排⾏': '17', '2017年6排⾏': '17', '开发语⾔': 'MATLAB', '评级': '0.894%', '变化率': '-1.10%'}
{'2018年6⽉排⾏': '18', '2017年6排⾏': '15', '开发语⾔': 'Go', '评级': '0.879%', '变化率': '-1.17%'}
{'2018年6⽉排⾏': '19', '2017年6排⾏': '13', '开发语⾔': 'Delphi/Object Pascal', '评级': '0.875%', '变化率': '-1.28%'}
{'2018年6⽉排⾏': '20', '2017年6排⾏': '20', '开发语⾔': 'PL/SQL', '评级': '0.848%', '变化率': '-0.72%'}
XPath的更多⽤法参考:
python lxml库的更多⽤法参考:
出处:
==========================================================================================
Python-- lxml⽤法
⽬录
lxml库(lxml安装可查看上⼀篇⽂章)
python的HTML/XML的解析器
官⽅⽂档:
功能:
解析HTML
⽂件读取
etree和XPath的配合使⽤
围绕三个问题:
问题1:有⼀个XML⽂件,如何解析
问题2:解析后,如果查、定位某个标签
问题3:定位后如何操作标签,⽐如访问属性、⽂本内容等
导⼊模块,该库常⽤的XML处理功能都在中
from lxml import etree
Element类
Element是XML处理的核⼼类,Element对象可以直观的理解为XML的节点,⼤部分XML节点的处理都是围绕该类进⾏的。这部分包括三个内容:节点的操作、节点属性的操作、节点内⽂本的操作。
1、节点操作
1、创建Element对象
使⽤Element⽅法,参数即节点名称。
1.
>>> root = etree.Element('root')
2.
>>> print(root)
3.
<Element root at 0x2da0708>
2、获取节点名称
使⽤tag属性,获取节点的名称。
1.
>>> print(root.tag)
2.
root
3、输出XML内容
使⽤tostring⽅法输出XML内容,参数为Element对象。
1.
>>> string(root))
2.
b'<root><child1/><child2/><child3/></root>'
4、添加⼦节点
使⽤SubElement⽅法创建⼦节点,第⼀个参数为⽗节点(Element对象),第⼆个参数为⼦节点名称。
1.
>>> child1 = etree.SubElement(root, 'child1')
2.
>>> child2 = etree.SubElement(root, 'child2')
3.
>>> child3 = etree.SubElement(root, 'child3')
5、删除⼦节点
使⽤remove⽅法删除指定节点,参数为Element对象。clear⽅法清空所有节点。
1.
>>> ve(child1) # 删除指定⼦节点
2.
>>> string(root))
3.
b'<root><child2/><child3/></root>'
4.
>>> root.clear() # 清除所有⼦节点
5.
>>> string(root))
6.
b'<root/>'
6、以列表的⽅式操作⼦节点
可以将Element对象的⼦节点视为列表进⾏各种操作:
1.
>>> child = root[0] # 下标访问
2.
>>> print(child.tag)
3.
child1
4.
5.
>>> print(len(root)) # ⼦节点数量
6.
3
7.
8.
>>> root.index(child2) # 获取索引号
9.
1
10.
11.
>>> for child in root: # 遍历
12.
... print(child.tag)
13.
child1
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论