大师兄的Python学习笔记(十九): Python与(XML和JSON)

大师兄的Python学习笔记(十八): Python与HTTP
大师兄的Python学习笔记(二十): 爬虫(一)

一、XML和JSON简介

1. 关于XML
  • XML(Extensible Markup Language, 扩展标记语言) ,是用于标记电子文件使其具有结构性的标记语言。
  • 可以标记数据、定义数据类型,是一种允许用户对自己的标记语言进行定义的源语言。
  • 通常被用来传输和结构化存储数据。
<?xml version="1.0" encoding="utf-8" ?>
<Animal>
  <type>狗</type>
  <Dog category="dog1">
    <name>PP</name>
    <age>10</age>
    <sex>M</sex>
    <colour>lightgray</colour>   
  </Dog>
  <Dog category="dog2">
    <name>QQ</name>
    <age>1.5</age>
    <sex>M</sex>
    <colour>darkgray</colour>   
  </Dog>
  <Dog category="dog3">
    <name>doudou</name>
    <age>0</age>
    <sex>F</sex>
    <colour>gray</colour>   
  </Dog>
</Animal>
2. 关于JSON
  • JSON(JavaScript Object Notation)一种轻量级的数据交换格式。
  • 具有良好的可读和便于快速编写的特性。
  • 采用兼容性很高的、完全独立于语言文本格式,同时也具备类似于C语言的习惯(包括C, C++, C#, Java, JavaScript, Perl, Python等)体系的行为。
  • 通常被用来存储数据或在不同平台之间进行数据交换。
{
    "type":"狗",
    "Dog":[
        {
            "name":"PP",
            "age":10,
            "sex":"M",
            "colour":"lightgray"
        },
        {
            "name":"QQ",
            "age":1.5,
            "sex":"M",
            "colour":"darkgray"
        },
        {
            "name":"doudou",
            "age":0,
            "sex":"F",
            "colour":"gray"
        }
    ]
}
3. XML和JSON的比较
3.1 XML的优缺点

1) XML的优点

  • 与HTML格式相似,有利于页面展示。
  • 容易与其他系统进行远程交互,数据共享比较方便。

2) XML的缺点

  • 文件庞大,文件格式复杂,传输占带宽。
  • 服务器端和客户端都需要花费大量代码来解析XML,导致服务器端和客户端代码变得异常复杂且不易维护。
  • 客户端不同浏览器之间解析XML的方式不一致,需要重复编写很多代码;
  • 数据类型只支持字符串。
3.2 JSON的优缺点

1) JSON的优点

  • 数据格式比较简单,易于读写,格式都是压缩的,占用带宽小;
  • 易于解析,客户端JavaScript可以简单的通过eval()进行JSON数据的读取;
  • 支持多种语言: ActionScript, C, C#, ColdFusion, Java, JavaScript, Perl, PHP, Python, Ruby等。
  • 支持多种数据类型:字符串,数字,数组,布尔值。

2) JSON的缺点

  • 对人来说可读性比XML弱。

二、Python与XML

  • XML包是Python处理XML语言的核心工具。
  • XML包包含四个子模块:
模块 简介
dom - 实现W3C制定的DOM API。
- DOM解析器在任何处理开始之前,必须把基于XML文件生成的树状数据放在内存,所以DOM解析器的内存使用量完全根据输入资料的大小。
sax - 实现SAX API。
- sax牺牲了便捷性来换取速度和内存占用,它是事件驱动的,并不需要一次性读入整个文档,而文档的读入过程也就是SAX的解析过程。
etree - 一个轻量级、Pythonic的API。
- 与DOM相比,他的速度更快,API使用更直接、方便。
- 与SAX相比,ET.iterparse函数同样提供了按需解析的功能,不会一次性在内存中读入整个文档。
- ET的性能与SAX模块大致相仿,但是它的API更加高层次,用户使用起来更加便捷。
parser 封装了XML解析器接口,目前只支持C语言编写的expat解析器。
1. 生成XML
  • 使用xml.dom.minidom模块生成XML代码。
import xml.dom.minidom

# 创建XML内容
>>>def create_Xml():
>>>    # 创建dom文档
>>>    doc = xml.dom.minidom.Document()

>>>    # 创建根节点
>>>    orderlist = doc.createElement('orderlist')

>>>    # 插入dom树
>>>    doc.appendChild(orderlist)

>>>    node_type = doc.createElement('type')
>>>    orderlist.appendChild(node_type)
>>>    # 插入文字节点
>>>    node_type_text = doc.createTextNode("dogs")
>>>    node_type.appendChild(node_type_text)

>>>    # 创建子节点
>>>    node_dog_1 = doc.createElement('dog')
>>>    node_dog_name = doc.createElement('name')
>>>    node_dog_age = doc.createElement('age')
>>>    node_dog_colour = doc.createElement('colour')
>>>    orderlist.appendChild(node_dog_1)
>>>    node_dog_1.appendChild(node_dog_name)
>>>    node_dog_1.appendChild(node_dog_age)
>>>    node_dog_1.appendChild(node_dog_colour)
>>>    # 增加属性
>>>    node_dog_1.setAttribute("category", "dog1")

>>>    # 插入文字节点
>>>    node_dog_1_name = doc.createTextNode("pp")
>>>    node_dog_name.appendChild(node_dog_1_name)
>>>    node_dog_1_age = doc.createTextNode("10")
>>>    node_dog_age.appendChild(node_dog_1_age)
>>>    node_dog_1_colour = doc.createTextNode("darkgray")
>>>    node_dog_colour.appendChild(node_dog_1_colour)
>>>    return doc.toprettyxml(indent='\t')

>>>if __name__ == '__main__':
>>>    print(create_Xml())

<?xml version="1.0" ?>
<orderlist>
    <type>dogs</type>
    <dog category="dog1">
        <name>pp</name>
        <age>10</age>
        <colour>darkgray</colour>
    </dog>
</orderlist>
2. 解析XML
2.1 使用DOM解析XML
>>>import xml.dom.minidom,os
>>>from xml.dom.minidom import parse

>>># 读取XML文档
>>>path = os.path.join('D:\\','sample.xml')
>>>DOMTree = parse(path)
>>>animal = DOMTree.documentElement

>>># 获取子节点
>>>dogs = animal.getElementsByTagName("Dog")
>>>for dog in dogs:
>>>    # 获得属性
>>>    if dog.hasAttribute("category"):
>>>        print(f'category:{dog.getAttribute("category")}')
>>>    # 获得子节点
>>>    name = dog.getElementsByTagName("name")[0]
>>>    print(f'name:{name.childNodes[0].data}')

>>>    age = dog.getElementsByTagName("age")[0]
>>>    print(f'age:{age.childNodes[0].data}')

>>>    sex = dog.getElementsByTagName("sex")[0]
>>>    print(f'sex:{sex.childNodes[0].data}')

>>>    colour = dog.getElementsByTagName("colour")[0]
>>>    print(f'colour:{colour.childNodes[0].data}')

>>>    print(f"{'*'*20}")
category:dog1
name:PP
age:10
sex:M
colour:lightgray
********************
category:dog2
name:QQ
age:1.5
sex:M
colour:darkgray
********************
category:dog3
name:doudou
age:0
sex:F
colour:gray
********************
2.2 使用SAX解析XML
  • SAX基于事件驱动,解析XML文档涉及两个部分,解析器和事件处理器:

1) 解析器 xml.sax.parse()

  • 负责读取XML文档,并向事件处理器发送事件,如元素开始跟元素结束事件。
  • xml.sax.make_parser(parser_list): 创建并返回一个解析器对象。
  • xml.sax.parse( xmlfile, contenthandler, errorhandler):创建一个 SAX 解析器并解析xml文档。
  • xml.sax.parseString(xmlstring, contenthandler, errorhandler):创建一个XML解析器并解析xml字符串。

2) 事件处理器 xml.sax.handler.ContentHandler()

  • 负责对事件作出响应,对传递的XML数据进行处理。
  • characters(content): 遇到标签间内容时调用。
  • startDocument(): 文档启动的时候调用。
  • endDocument(): 解析器到达文档结尾时调用。
  • startElement(name, attrs) : 遇到XML开始标签时调用,name为标签名,attrs为标签属性值。
  • endElement(name): 遇到XML结束标签时调用。
>>>import xml.sax,os
>>>from xml.sax import make_parser

>>>class AnimalHandler(xml.sax.ContentHandler):
>>>    def __init__(self):
>>>        self.CurrentData = ""
>>>        self.type = ""
>>>        self.name = ""
>>>        self.age =""
>>>        self.sex = ""
>>>        self.colour = ""

>>>    # 处理开始元素事件
>>>    def startElement(self,tag,attributes):
>>>        self.CurrentData = tag
>>>        if tag == "Dog":
>>>            print(f"{'*'*20}")
>>>            print(f'category:{attributes["category"]}')

>>>    # 处理结束元素事件
>>>    def endElement(self,tag):
>>>        if self.CurrentData == "type":
>>>            print(f"type:{self.type}")
>>>        elif self.CurrentData == "name":
>>>            print(f"name:{self.name}")
>>>        elif self.CurrentData == "age":
>>>            print(f"age:{self.age}")
>>>        elif self.CurrentData == "sex":
>>>            print(f"sex:{self.sex}")
>>>        elif self.CurrentData == "colour":
>>>            print(f"colour:{self.colour}")
>>>        self.CurrentData = ""

>>>    # 文档结束时
>>>    def endDocument(self):
>>>        print(f"{'*'*20}")

>>>    # 内容事件处理
>>>    def characters(self,content):
>>>        if self.CurrentData == "type":
>>>            self.type = content
>>>        elif self.CurrentData == "name":
>>>            self.name = content
>>>        elif self.CurrentData == "age":
>>>            self.age = content
>>>        elif self.CurrentData == "sex":
>>>            self.sex = content
>>>        elif self.CurrentData == "colour":
>>>            self.colour = content

>>>if __name__ == '__main__':
>>>    path = os.path.join('D:\\', 'sample.xml')
>>>    parser = make_parser() # 创建reader
>>>    parser.setFeature(xml.sax.handler.feature_namespaces,0) # 去掉空格
>>>    handler = AnimalHandler()
>>>    parser.setContentHandler(handler)
>>>    parser.parse(path)
type:狗
********************
category:dog1
name:PP
age:10
sex:M
colour:lightgray
********************
category:dog2
name:QQ
age:1.5
sex:M
colour:darkgray
********************
category:dog3
name:doudou
age:0
sex:F
colour:gray
********************
2.3 使用ETREE解析XML
>>>import xml.etree.ElementTree as et
>>>import os

>>>path = os.path.join('D:\\', 'sample.xml')

>>>tree = et.parse(path) # 获得etree对象
>>>root = tree.getroot() # 获取根节点

>>># 遍历XML文件
>>>for child in root:
>>>    print(f"{'*'*20}\n{child.tag}:{child.attrib if child.attrib else child.text}")
>>>    for sub in child:
>>>        print(f'{sub.tag}:{sub.text}')
********************
type:狗
********************
Dog:{'category': 'dog1'}
name:PP
age:10
sex:M
colour:lightgray
********************
Dog:{'category': 'dog2'}
name:QQ
age:1.5
sex:M
colour:darkgray
********************
Dog:{'category': 'dog3'}
name:doudou
age:0
sex:F
colour:gray
3. 查找XML节点
  • 使用etree查找节点。
>>>import xml.etree.ElementTree as et
>>>import os

>>>path = os.path.join('D:\\', 'sample.xml')

>>>tree = et.parse(path) # 获得etree对象
>>>root = tree.getroot() # 获取根节点

>>>aim_node = root.find('Dog') # 查找第一个Dog节点
>>>print(aim_node.tag,aim_node.attrib)
Dog {'category': 'dog1'}

>>>aim_nodes = root.findall('Dog') # 查找所有Dog节点
>>>print(aim_nodes[1].tag,aim_nodes[1].attrib)
Dog {'category': 'dog2'}
4. 删除XML节点
  • 使用etree删除节点。
>>>import xml.etree.ElementTree as et
>>>import os

>>>path = os.path.join('D:\\', 'sample.xml')

>>>tree = et.parse(path) # 获得etree对象
>>>root = tree.getroot() # 获取根节点

>>>aim_node = root.find('Dog') # 查找第一个Dog节点
>>>root.remove(aim_node) # 删除节点
>>>tree.write('temp.xml')
<Animal>
<type>狗</type>
<Dog category="dog2">
<name>QQ</name>
<age>1.5</age>
<sex>M</sex>
<colour>darkgray</colour>
  
</Dog>
<Dog category="dog3">
<name>doudou</name>
<age>0</age>
<sex>F</sex>
<colour>gray</colour>
  
</Dog>
</Animal>

三、Python与JSON

  • json包是Python的基础包,用于处理JSON格式文档或对象。
  • json包中常用以下四个方法:
方法 简介
dump 将Python对象序列化,转为符合JSON格式的String,并写入文件。
dumps 将Python对象序列化,转为符合JSON格式的String。
load 读取JSON文件,并创建dict。
loads 将符合JSON格式的String转为dict。
1. json.dump(obj,fp)
  • 将Python对象序列化,转为符合JSON格式的String,并写入文件。
>>>import json,os

>>>data = {
>>>    "type":"狗",
>>>    "Dog":[
>>>        {
>>>            "name":"PP",
>>>            "age":10,
>>>            "sex":"M",
>>>            "colour":"lightgray"
>>>        },
>>>        {
>>>            "name":"QQ",
>>>            "age":1.5,
>>>            "sex":"M",
>>>            "colour":"darkgray"
>>>        },
>>>        {
>>>            "name":"doudou",
>>>            "age":0,
>>>            "sex":"F",
>>>            "colour":"gray"
>>>        }
>>>    ]
>>>}
>>>with open("sample1.json","w") as f:
>>>    json.dump(data,f) # 将数据储存到json文件中
>>>os.system("type sample1.json") # 控制台打印文件内容
{"type": "\u72d7", "Dog": [{"name": "PP", "age": 10, "sex": "M", "colour": "lightgray"}, {"name": "QQ", "age": 1.5, "sex": "M", "colour": "darkgray"}, {"name": "doudou", "age": 0, "sex": "F", "colour": "gray"}]}
2. json.dumps(obj)
  • 将Python对象序列化,转为符合JSON格式的String。
>>>import json

>>>data = {
>>>    "type":"狗",
>>>    "Dog":[
>>>        {
>>>            "name":"PP",
>>>            "age":10,
>>>            "sex":"M",
>>>            "colour":"lightgray"
>>>        },
>>>        {
>>>            "name":"QQ",
>>>            "age":1.5,
>>>            "sex":"M",
>>>            "colour":"darkgray"
>>>        },
>>>        {
>>>            "name":"doudou",
>>>            "age":0,
>>>            "sex":"F",
>>>            "colour":"gray"
>>>        }
>>>    ]
>>>}
>>>data_json = json.dumps(data)
>>>print(f"type:{type(data_json)}")
>>>print(data_json)
type:<class 'str'>
{"type": "\u72d7", "Dog": [{"name": "PP", "age": 10, "sex": "M", "colour": "lightgray"}, {"name": "QQ", "age": 1.5, "sex": "M", "colour": "darkgray"}, {"name": "doudou", "age": 0, "sex": "F", "colour": "gray"}]}
3. json.load(fp)
  • 读取JSON文件,并创建dict。
>>>import json,os

>>>path = os.path.join("sample1.json")
>>>with open(path,'r') as f: # 读取文件并获得文件对象
>>>    data = json.load(f) # 读取json文件并创建dict
>>>print(f"type:{type(data)}")
>>>print(data)
type:<class 'dict'>
{'type': '狗', 'Dog': [{'name': 'PP', 'age': 10, 'sex': 'M', 'colour': 'lightgray'}, {'name': 'QQ', 'age': 1.5, 'sex': 'M', 'colour': 'darkgray'}, {'name': 'doudou', 'age': 0, 'sex': 'F', 'colour': 'gray'}]}
4. json.loads(s)
  • 将符合JSON格式的String转为dict。
>>>import json

>>>s = '{"type": "\u72d7", "Dog": [{"name": "PP", "age": 10, "sex": "M", "colour": "lightgray"}, {"name": "QQ", "age": 1.5, "sex": "M", "colour": "darkgray"}, {"name": "doudou", "age": 0, "sex": "F", "colour": "gray"}]}'
>>>data = json.loads(s)
>>>print(f"type:{type(data)}")
>>>print(data)
type:<class 'dict'>
{'type': '狗', 'Dog': [{'name': 'PP', 'age': 10, 'sex': 'M', 'colour': 'lightgray'}, {'name': 'QQ', 'age': 1.5, 'sex': 'M', 'colour': 'darkgray'}, {'name': 'doudou', 'age': 0, 'sex': 'F', 'colour': 'gray'}]}

参考资料



本文作者:大师兄(superkmi)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,635评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,628评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,971评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,986评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,006评论 6 394
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,784评论 1 307
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,475评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,364评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,860评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,008评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,152评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,829评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,490评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,035评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,156评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,428评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,127评论 2 356