使用Python读取和解析JSON数据教程
使用Python读取和解析JSON数据教程
JSON格式是 网站和API使用的通用标准格式, 现在主流的一些数据库(如PostgreSQL)都支持JSON格式。在本文中,我们将介绍如何使用Python处理JSON数据。首先,让我们先来看看JSON的定义。
什么是JSON?
JSON或JavaScript Object Notation,是一种 使用文本存储数据对象的格式。 换句话说,它是一种 数据结构,将对象用文本形式表示出来。 尽管它来源自JavaScript,但它已成为传输对象的实际标准。
大多数流行的编程语言都支持JSON格式,包括Python。JSON格式的文件经常用于 API传输数据对象。 以下是JSON字符串的示例:
{
"name": "United States",
"population": 331002651,
"capital": "Washington D.C.",
"languages": [
"English",
"Spanish"
}
在这个例子中,JSON数据看起来像一个Python字典。像字典一样, JSON以键值对的形式传递数据。 然而,JSON数据也可以是 字符串、数字、布尔值或列表。
在JSON流行之前,XML一直是以文本格式表示数据对象的常见选择。以下是XML格式的相同信息的示例:
<?xml version="1.0" encoding="UTF-8"?>
<country>
<name>United States</name>
<population>331002651</population>
<capital>Washington D.C.</capital>
<languages>
<language>English</language>
<language>Spanish</language>
</languages>
</country>
很明显,JSON代码量更少。这是JSON如此流行的主要原因之一。如果您想了解有关JSON标准的更多信息,请访问 JSON官方网站 。
Python中的JSON
Python原生支持JSON数据。Python json 模块是标准库的一部分。该 json 模块可以将JSON数据从JSON格式转换到等效的Python对象,例如 dictionary 和 list 。JSON模块还可以将Python对象转换为JSON格式。
Python的 json 模块提供编写自定义编码器和解码器功能, 无需单独安装。 您可以在 此链接 里找到Python json 模块的官方文档。
接下来,我们将研究下这个模块。我们将把JSON转换为 dictionary 和 list。 我们还将尝试处理自定义类。
将JSON字符串转换为Python对象
JSON数据经常存储在 字符串 中。这是使用API时的常见场景。JSON数据在解析之前一般存储在字符串变量中。因此,与JSON相关的最常见任务是将JSON字符串解析为Python字典。JSON模块可以轻松处理此任务。
第一步是导入Python的 json 模块。该模块包含两个重要的功能- loads 和 load。
请注意,第一种方法看起来像复数形式,但事实并非如此。 字母“S”代表“字符串”。
loads 是将字符串解析为JSON数据。请注意,它读作“load-s”。这里的“s”代表“字符串”。 Load 的使用场景是 当数据以字节为单位时。 这部分后面会详细介绍。
让我们从一个简单的例子开始。JSON数据实例如下:
{
"name": "United States",
"population": 331002651,
}
JSON数据可以在解析之前存储为JSON字符串。我们不仅可以使用Python的 三引号 来存储多行字符串,也可以通过 删除换行符 来提高可读性。
# JSON string
country = '{"name": "United States", "population": 331002651}'
print(type(country))
此代码段的输出将确认这确实是一个JSON字符串:
<class 'str'>
我们可以调用该 json.loads() 并将此字符串作为参数。
import json
country = '{"name": "United States", "population": 331002651}'
country_dict = json.loads(country)
print(type(country))
print(type(country_dict))
此代码段的输出将确认作为字符串的JSON数据现在已经是Python字典。
<class 'str'>
<class 'dict'>
这本字典可以像往常一样正常访问:
print(country_dict['name'])
# OUTPUT: United States
需要注意的是, json.loads() 方法并不总是返回字典。返回的数据类型将 取决于输入的字符串。 例如,下面这个JSON字符串将返回一个列表,而不是一个字典。
countries = '["United States", "Canada"]'
counties_list= json.loads(countries)
print(type(counties_list))
# OUTPUT:
同样,如果JSON字符串包含 true ,它将被转换为Python等效的布尔值,即 True 。
import json
bool_string = 'true'
bool_type = json.loads(bool_string)
print(bool_type)
# OUTPUT: True
下表显示了 转换后的JSON对象和Python数据类型。
| JSON | Python |
| object | dict |
| array | list |
| string | str |
| number (integer) | int |
| number (real) | float |
| true | True |
| false | False |
| null | None |
接下来我们将继续下一个主题,将JSON对象解析为Python对象。
将JSON文件转换为Python对象
读取JSON文件,并将JSON数据解析为Python数据,与我们解析存储在字符串中JSON数据的方式非常相似。除了JSON,我们还需要Python的原生函数 open() 。
一般 loads 用于读取JSON字符串,而 load() 用于读取文件中的JSON数据。
load() 方法接收一个文件对象并返回解析为Python对象的JSON数据。
要从文件路径中获取文件对象,可以使用Python的函数 open() 。
将以下JSON数据另存为新文件并将其命名为 united_states.json :
{
"name": "United States",
"population": 331002651,
"capital": "Washington D.C.",
"languages": [
"English",
"Spanish"
}
在新文件中输入此Python脚本:
import json
with open('united_states.json') as f:
data = json.load(f)
print(type(data))
运行此Python文件会输出以下内容:
<class 'dict'>
在此示例中,该 open 函数返回一个文件句柄,该句柄会提供给 load 。
变量 data 包含JSON,作为Python字典。这意味着可以按如下方式检查字典键:
print(data.keys())
# OUTPUT: dict_keys(['name', 'population', 'capital', 'languages'])
使用此信息, name 可以输出如下:
data['name']
# OUTPUT: United States
在前两节中,我们研究了如何将JSON转换为Python对象。现在,我们来看看如何将Python对象转换为JSON对象。
将Python对象转换为JSON字符串
将Python对象转换为JSON对象也称为序列化或JSON编码。可以使用函数 dumps() 来实现。它被读作 dump-s , 字母S代表字符串。
以下是一个简单的例子。将此代码作为Python脚本保存在新文件中:
import json
languages = ["English","French"]
country = {
"name": "Canada",
"population": 37742154,
"languages": languages,
"president": None,
country_string = json.dumps(country)
print(country_string)
使用Python运行此文件时,将输出以下结果:
{"name": "Canada", "population": 37742154, "languages": ["English", "French"],
"president": null}
Python对象现在就是一个JSON对象了。这个简单的例子展示了将Python对象解析为JSON对象的过程,整个过程并不复杂。而此处的Python对象是一个 字典。 这就是它被转换为JSON对象类型的原因。同样,列表也可以转换为JSON。这是对应的Python脚本及其输出:
import json
languages = ["English", "French"]
languages_string = json.dumps(languages)
print(languages_string)
# OUTPUT: ["English", "French"]
它不仅限于字典和列表。 string,int,float,bool甚至None值都可以转换为JSON。
有关详细信息,请参阅下面的转换表。可以看到,只有字典被转换为json对象类型。有关官方文档,请参阅 此链接 。
| Python | JSON |
| dict | object |
| list,tuple | array |
| str | string |
| int,float,int | number |
| True | true |
| False | false |
| None | null |
将Python对象写入JSON文件
用于编写JSON文件的方法是 dump(). 这种方法与 dumps() 方法非常相似。唯一的区别是 dumps() 返回一个字符串, dump() 写入一个文件。
下面是一个简单的演示,将以编辑模式打开文件并将数据写成 JSON格式。 保存此Python脚本并运行它。
import json
# Tuple is encoded to JSON array.
languages = ("English", "French")
# Dictionary is encoded to JSON object.
country = {
"name": "Canada",
"population": 37742154,
"languages": languages,
"president": None,
with open('countries_exported.json', 'w') as f:
json.dump(country, f)
使用Python执行此代码时, countries_exported.json 会创建(或覆盖)文件,内容为以上JSON文件。
但是,您会发现整个JSON都在一行中。为了使它更具可读性,我们可以再传递一个参数给 dump() 函数,如下所示:
json.dump(country, f, indent=4)
这一次,当您运行代码时,格式就正常了,同时还会缩进4个空格:
{
"languages": [
"English",
"French"
"president": null,
"name": "Canada",
"population": 37742154
}
注意, indent 参数也可用于JSON dumps() 方法。JSON dump() 和JSON dumps() 唯一区别是 dump() 需要一个文件对象。
将自定义Python对象转换为JSON对象
让我们检查 dump() 方法的签名:
dump(obj, fp, *, skipkeys=False, ensure_ascii=True, check_circular=True,allow_nan=True, cls=None, indent=None, separators=None,default=None, sort_keys=False, **kw)
重点关注参数
cls
。
如果在调用
dump
方法时没有
Class
,则
dump()
和
dumps()
方法都会默认为
JSONEncoder
该类。此类支持标准的Python类型有:
dict,list,tuple,str,int,float,True,False,和None。
如果我们尝试 json.loads() 在任何其他类型上调用该方法,则此方法将引发 TypeError 的报错信息: Object of typeis not JSON serializable 。
将以下代码另存为Python脚本并运行:
import json
class Country:
def __init__(self, name, population, languages):
self.name = name
self.population = population
self.languages = languages
canada = Country("Canada", 37742154, ["English", "French"])
print(json.dumps(canada))
# OUTPUT: TypeError: Object of type Country is not JSON serializable
要将对象转换为JSON,我们需要编写一个扩展JSONEncoder的新类。在这个类中,需要实现 default() 。此方法将具有返回JSON的自定义代码。
以下是 Country 类的示例编码器。这个类将帮助将Python对象转换为JSON对象:
import json
class CountryEncoder(json.JSONEncoder):
def default(self, o):
if isinstance(o, Country):
# JSON object would be a dictionary.
return {
"name" : o.name,
"population": o.population,
"languages": o.languages
else:
# Base class will raise the TypeError.
return super().default(o)
这段代码在确认提供的对象是 Country 类的实例后会返回一个字典,或者调用父级来处理其余的情况。
这个类可以提供给 json.dump() 和 json.dumps() 方法。
print(json.dumps(canada, cls=CountryEncoder))
# OUTPUT: {“name": "Canada", "population": 37742154, "languages": ["English", "French"]}
从JSON对象创建Python类对象
到目前为止,我们已经讨论了如何使用 json.load() 和 json.loads() 方法创建字典、列表等。如果我们想读取JSON对象并创建自定义类对象又该怎么办?
在本节中,我们将 创建一个自定义JSON解码器, 帮助我们创建自定义对象。这个自定义解码器将允许我们使用 json.load() 和 json.loads() 方法,并返回一个自定义类对象。
我们将使用上一节中使用的 Country 类。使用自定义编码器,我们能够编写如下代码:
# Create an object of class Country
canada = Country("Canada", 37742154, ["English", "French"])
# Use json.dump() to create a JSON file in writing mode
with open('canada.json','w') as f:
json.dump(canada,f, cls=CountryEncoder)
如果我们尝试使用 json.load() 方法解析这个JSON文件,我们将得到一个字典:
with open('canada.json','r') as f:
country_object = json.load(f)
# OUTPUT: <type ‘dict'="">
如果要获取 Country 类的实例而不是字典,我们需要创建一个 自定义解码器。 这个解码器类将 扩展JSONDecoder。 在这个类中,我们将编写 object_hook. 这样可以从字典中读取值来创建 Country 类的对象。
除了编写这个之外,我们还需要调用 __init__基类 并将参数 object_hook 的值设置为这个方法的名称。为简单起见,我们可以使用相同的名称。
import json
class CountryDecoder(json.JSONDecoder):
def __init__(self, object_hook=None,
*args, **kwargs):
super().__init__(object_hook=self.object
_hook, *args, **kwargs)
def object_hook(self, o):
decoded_country = Country(
o.get('name'),
o.get('population'),
o.get('languages'),