Python标准库系列之xml模块
Python’s interfaces for processing XML are grouped in the xml package.
带分隔符的文件仅有两维的数据:行和列。如果你想在程序之间交换数据结构,需要一种方法把层次结构、序列、集合和其他的结构编码成文本。
XML
是最突出的处理这种转换的标记(markup)格式,它使用标签(tag)分个数据,如下面的实例文件menu.xml所示:
<?xmlversion="1.0"encoding="utf-8"?> <Feedxmlns="http://www.w3.org/2005/Atom"> <title>安生'sBlog</title> <subtitle>大好时光!</subtitle> <linkhref="/atom.xml"rel="self"/> <linkhref="https://blog.ansheng.me/"/> <updated>2016-05-24T15:29:19.000Z</updated> <id> <author> <name>安生</name> </author> </Feed>
XML的一些重要特性
忽略空格
- 大好时光!
标签之间是可以存在多级嵌套的
标签中可以包含值(value)
如果一个命名为
thing
的标签内没有内容或者子标签,那么它可以用在右尖括号的前面添加斜杠的简单标签所表示,例如代替开始和结束都存在的标签。
XML通常用于数据传送和消息,它存在一些子格式,如RSS和Atom,例如:https://blog.ansheng.me/atom.xml
在Python中解析XML最简单的方法是使用ElementTree
。
模块 | 说明 |
---|---|
xml.etree.ElementTree | the ElementTree API,a simple and lightweight XML processor |
创建xml文件
导入ElementTree方法,起一个别名为ET
>>>fromxml.etreeimportElementTreeasET
创建顶级标签
>>>level_1=ET.Element("famliy")
>>>level_2=ET.SubElement(level_1,"name",attrib={"enrolled":"yes"})
创建三级标签
>>>level_3=ET.SubElement(level_2,"age",attrib={"checked":"no"})
生成文档
>>>tree=ET.ElementTree(level_1)
写入文件中
>>>tree.write('oooo.xml',encoding='utf-8',short_empty_elements=False)
导入os模块,用os模块中的system方法执行shell命令查看刚才创建的oooo.xml文件
>>>importos >>>os.system("catoooo.xml") #生成出来的文档是没有换行的 <famliy><nameenrolled="yes"><agechecked="no"></age></name></famliy>0
把刚才生成的文件下载到本地,然后用浏览器打开就可以看到分级层次了。
创建一个有换行的XML文件
fromxml.etreeimportElementTreeasET fromxml.domimportminidom root=ET.Element('level1',{"age":"1"}) son=ET.SubElement(root,"level2",{"age":"2"}) ET.SubElement(son,"level3",{"age":"3"}) #tree=ET.ElementTree(root) #tree.write("abc.xml",encoding="utf-8",xml_declaration=True,short_empty_elements=False) defprettify(root): rough_string=ET.tostring(root,'utf-8') reparsed=minidom.parseString(rough_string) returnreparsed.toprettyxml(indent="\t") new_str=prettify(root) f=open("new_out.xml","w") f.write(new_str) f.close()
<?xmlversion="1.0"?> <level1age="1"> <level2age="2"> <level3age="3"/> </level2> </level1>
解析XML
<data> <countryname="Liechtenstein"> <rankupdated="yes">2</rank> <yearage="19">2025</year> <gdppc>141100</gdppc> <neighbordirection="E"name="Austria"/> <neighbordirection="W"name="Switzerland"/> </country> <countryname="Singapore"> <rankupdated="yes">5</rank> <yearage="19">2028</year> <gdppc>59900</gdppc> <neighbordirection="N"name="Malaysia"/> </country> <countryname="Panama"> <rankupdated="yes">69</rank> <yearage="19">2028</year> <gdppc>13600</gdppc> <neighbordirection="W"name="CostaRica"/> <neighbordirection="E"name="Colombia"/> </country> </data>
first.xml
文件在/root
目录下
利用ElementTree.XML将字符串解析成xml对象
>>>fromxml.etreeimportElementTreeasET #打开文件,读取XML内容,将字符串解析成xml特殊对象,root代指xml文件的根节点 >>>root=ET.XML(open('first.xml','r').read()) >>>root.tag 'data' >>>fornodeinroot: ...print(node.tag,node.attrib) ... ('country',{'name':'Liechtenstein'}) ('country',{'name':'Singapore'}) ('country',{'name':'Panama'}) >>>print(node.find('rank').text) 69
利用ElementTree.parse将文件直接解析成xml对象
>>>fromxml.etreeimportElementTreeasET #直接解析xml文件 >>>tree=ET.parse("first.xml") #获取xml文件的根节点 >>>root=tree.getroot() >>>root.tag 'data'
遍历XML中指定的节点
>>>fromxml.etreeimportElementTreeasET >>>tree=ET.parse("first.xml") >>>root=tree.getroot() >>>fornodeinroot.iter('year'): #输出node的tag和内容 ...print(node.tag,node.text) ... year2025 year2028 year2028
增、删、改XML
>>>fromxml.etreeimportElementTreeasET >>>tree=ET.parse("first.xml") >>>root=tree.getroot() >>>fornodeinroot.iter("year"): #查看原来的属性 ...print(node.attrib) ... {} {} {} >>>fornodeinroot.iter("year"): #添加属性 ...node.set("OS","Linux") ... >>>fornodeinroot.iter("year"): #查看添加的属性 ...print(node.attrib) ... {'OS':'Linux'} {'OS':'Linux'} {'OS':'Linux'} #把内容写入文件 >>>tree.write("first.xml")
>>>fromxml.etreeimportElementTreeasET >>>tree=ET.parse("first.xml") >>>root=tree.getroot() >>>fornodeinroot.iter("year"): #删除节点的OS属性 ...delnode.attrib['OS'] ... #写入到文件当中 >>>tree.write("first.xml")
查看属性
>>>fromxml.etreeimportElementTreeasET >>>tree=ET.parse("first.xml") >>>root=tree.getroot() >>>fornodeinroot.iter("year"): ...print(node.attrib) ... #节点内容为空 {} {} {}
修改year
内的数字自加1
>>>fromxml.etreeimportElementTreeasET >>>tree=ET.parse("first.xml") >>>root=tree.getroot() >>>fornodeinroot.iter("year"): #输出原来year的内容 ...print(node.text) #原来的值自加+ ...new_year=int(node.text)+1 ...node.text=str(new_year) ... 2025 2028 2028 #写入文件中 >>>tree.write("first.xml") >>>fornodeinroot.iter("year"): #输出写入文件之后year的内容 ...print(node.text) ... 2026 2029 2029
对节点操作的方法
>>>fromxml.etreeimportElementTreeasET >>>tree=ET.parse("first.xml") >>>root=tree.getroot() >>>print(dir(root)) ['__class__','__copy__','__deepcopy__','__delattr__','__delitem__','__dir__','__doc__','__eq__','__format__','__ge__','__getattribute__','__getitem__','__getstate__','__gt__','__hash__','__init__','__le__','__len__','__lt__','__ne__','__new__','__reduce__','__reduce_ex__','__repr__','__setattr__','__setitem__','__setstate__','__sizeof__','__str__','__subclasshook__','append','clear','extend','find','findall','findtext','get','getchildren','getiterator','insert','items','iter','iterfind','itertext','keys','makeelement','remove','set']
方法有这么多,那么我们常用的也就是下面的几个
tag | 获取tag标签名 | |
attrib | 获取节点的属性 | |
find | 获取节点的内容 | |
iter | 进行迭代 | |
set | 设置属性 | |
get | 获取属性 |
实例
判断QQ是否在线
腾讯提供了能够查看QQ号码是否在线的API,Y
=在线;N
=离线;E
=QQ号码错误;A
=商业用户验证失败;V
=免费用户超过数量
>>>importrequests >>>fromxml.etreeimportElementTreeasET >>>r=requests.get("http://www.webxml.com.cn//webservices/qqOnlineWebService.asmx/qqCheckOnline?qqCode=6087414") >>>result=r.text >>>fromxml.etreeimportElementTreeasET >>>node=ET.XML(result) >>>ifnode.text=="Y": ...print("在线") ...else: ...print("离线") ... 在线
获取列车起止时间
r=requests.get("http://www.webxml.com.cn/WebServices/TrainTimeWebService.asmx/getDetailInfoByTrainCode?TrainCode=K234&UserID=") result=r.text root=ET.XML(result) fornodeinroot.iter('TrainDetailInfo'): print(node.find('TrainStation').text,node.find('ArriveTime').text,node.find("StartTime").text)
执行结果
C:\Python35\python.exeF:/Python_code/sublime/Week5/Day01/xml_mod.py 上海(车次:K234\K235)None11:12:00 #地点停止启动 昆山11:45:0011:48:00 苏州12:12:0012:16:00 无锡12:44:0012:55:00 常州13:22:0013:26:00 镇江14:13:0014:16:00 南京15:04:0015:16:00 蚌埠17:27:0017:50:00 徐州19:38:0019:58:00 商丘22:12:0022:17:00 开封23:49:0023:53:00 郑州00:37:0001:14:00 新乡02:20:0002:22:00 鹤壁03:01:0003:03:00 安阳03:33:0003:36:00 邯郸04:11:0004:16:00 邢台04:47:0004:51:00 石家庄06:05:00None Processfinishedwithexitcode0