如何在Python中加载多个JSON对象

4
我有成千上万个 JSON 对象,它们以以下格式存储在一个 JSON 文件中:
{ "a": 1,
  "b" : 2,
  "c" : {
          "d":3
        }
}{ "e" : 4,
  "f" : 5,
  "g" : {
         "h":6
        }
}

如何将它们作为 JSON 对象加载?
我尝试过两种方法,但都出现了错误:
方法一:
>>> with open('test1.json') as jsonfile:
...     for line in jsonfile:
...             data = json.loads(line)
... 

错误:
Traceback (most recent call last):
  File "<stdin>", line 3, in <module>
  File "/usr/lib/python3.5/json/__init__.py", line 319, in loads
    return _default_decoder.decode(s)
  File "/usr/lib/python3.5/json/decoder.py", line 339, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
  File "/usr/lib/python3.5/json/decoder.py", line 355, in raw_decode
    obj, end = self.scan_once(s, idx)
json.decoder.JSONDecodeError: Expecting property name enclosed in double quotes: line 2 column 1 (char 10)

方法二:
>>> with open('test1.json') as jsonfile:
...     data = json.load(jsonfile)      
... 

错误:
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
  File "/usr/lib/python3.5/json/__init__.py", line 268, in load
    parse_constant=parse_constant, object_pairs_hook=object_pairs_hook, **kw)
  File "/usr/lib/python3.5/json/__init__.py", line 319, in loads
    return _default_decoder.decode(s)
  File "/usr/lib/python3.5/json/decoder.py", line 342, in decode
    raise JSONDecodeError("Extra data", s, end)
json.decoder.JSONDecodeError: Extra data: line 7 column 1 (char 46)
>>> 

我已经阅读了相关的问题,但它们都没有帮助。

你发布的第一段代码包含两个JSON对象,而不是一个。这可能是json.load错误的原因。 - Aquarthur
1
对象之间总是有空行吗?这些是唯一的空行吗? - Daniel Roseman
1
有没有可能更改生成JSON文件的过程,使每个JSON之间插入2个或更多换行符?这样@DanielRoseman所想的方法就能够起作用。 - Mauro Baraldi
如果您可以更改生成文件的方式,我建议以一种方式进行更改,即在开头添加 [,在每个对象之间添加 ,,并在结尾处添加 ] - Massimo Costa
1
@krishna 将其序列化为对象列表,或使用不同的格式,如json-lines。 - juanpa.arrivillaga
显示剩余4条评论
6个回答

6
您所描述的文件内容不是一个有效的JSON对象,这就是为什么两种方法都无法工作的原因。
要转换成可以使用 json.load(fd) 加载的格式,您需要:
  1. 在文件开头添加 [
  2. 在每个对象之间添加 ,
  3. 在文件结尾处添加 ]
然后您就可以使用第二种方法了。例如:
[ { "a": 1,
    "b" : 2,
    "c" : {
      "d":3
    }
  }, { "e" : 4,
       "f" : 5,
       "g" : {
         "h":6
       }
  }
]

这是一个有效的JSON数组。

如果文件格式正好符合您描述的要求,您可以执行以下操作:

with open(filename, 'r') as infile:
    data = infile.read()
    new_data = data.replace('}{', '},{')
    json_data = json.loads(f'[{new_data}]')

你的第二个方法很有帮助。非常感谢。 - Krishna

4

我认为,如果你不想改变源文件,最好的方法是使用json.JSONDecoder.raw_decode(),它可以让你逐个迭代文件中的每个有效的JSON对象。

from json import JSONDecoder, JSONDecodeError

decoder = JSONDecoder()
content = '{ "a": 1,  "b": 2,  "c": { "d":3 }}{ "e": 4, "f": 5,  "g": {"h":6 } }'

pos = 0
while True:
    try:
        o, pos = decoder.raw_decode(content, pos)
        print(o)
    except JSONDecodeError:
        break

将打印您的两个JSON对象


需要增加pos,参见下面@noredistribution的代码示例。 - salmin
似乎raw_decode的第二个位置参数消失了。:( - undefined

3

正如 Daniel 在评论中所说,重点在于 JSON 块的开头/结尾模式。正如您更新的那样,该模式为 }{

将所有数据加载到一个字符串中,将此模式替换为您可以处理的模式,并将其拆分为有效 JSON 数据字符串的列表。最后,遍历列表即可。

{ "a": 1,
"b" : 2,
"c" : {
        "d":3
        }
}{ "e" : 4,
"f" : 5,
"g" : {
        "h":6
        }
}

将数据加载到一组有效的JSON字符串列表中。
with open('/home/mauro/workspace/test.json') as fp:
    data = fp.read()

替换模式

data = data.replace('}{', '}\n\n{')

然后,将其拆分为有效的JSON字符串列表。
data = data.split('\n\n')

最终,遍历JSON字符串列表。
for i in data:
    print json.loads(i)

1
我创建了一个脚本,利用异常机制来包含json结尾处的字符:
import json
from json.decoder import JSONDecodeError

with open("file.json", 'r') as file:
    contents = file.read()
start=0
end=len(contents)
json_objects=[]
while start < len(contents):
    try:
        json_objects.append(json.loads(contents[start:end]))
        print(f"Loaded from {start} to {end}")
        start=end
        end=len(contents)
    except JSONDecodeError as e:
        end=start+e.pos
for json_object in json_objects:
    print(len(json.dumps(json_object)))

这种方法并不高效,需要将整个文件加载到内存中,但它确实可以工作。


1

@Thiago的答案对我有用,但仅当pos增加一时才有效,否则它将始终只打印一个对象。

像这样:

from json import JSONDecoder, JSONDecodeError

def json_decoder(data):
    decoder = JSONDecoder()
    pos = 0
    result = []
    while True:
        try:
            o, pos = decoder.raw_decode(data, pos)
            result.append(o)
            pos +=1
        except JSONDecodeError:
            break
    return result

0
[
    { 
      "a": 1,
      "b" : 2,
      "c" : {
              "d":3
            }
    },
    { 
      "e" : 4,
      "f" : 5,
      "g" : {
             "h":6
            }
    }
]

首先,你的 JSON 文件应该长成这样,其次,像这样加载文件:json.loads(file.read())


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接