一个文件中的多个Json对象由python提取

use*_*396 31 python parsing json pandas

我是Json文件的新手.如果我有一个带有多个json对象的json文件,如下所示:

{"ID":"12345","Timestamp":"20140101", "Usefulness":"Yes",
  "Code":[{"event1":"A","result":"1"},…]}
{"ID":"1A35B","Timestamp":"20140102", "Usefulness":"No",
  "Code":[{"event1":"B","result":"1"},…]}
{"ID":"AA356","Timestamp":"20140103", "Usefulness":"No",
  "Code":[{"event1":"B","result":"0"},…]}
…
Run Code Online (Sandbox Code Playgroud)

我想将所有"时间戳"和"有用性"提取到数据框中:

    Timestamp    Usefulness
 0   20140101      Yes
 1   20140102      No
 2   20140103      No
 …
Run Code Online (Sandbox Code Playgroud)

有谁知道处理这些问题的一般方法?谢谢!

Dun*_*nes 67

您可以使用json.JSONDecoder.raw_decode任意解码大量"堆叠"JSON字符串(只要它们可以适合内存).raw_decode一旦它有一个有效的对象就停止,并返回不在解析对象中的最后一个位置.它没有记录,但您可以将此位置传回,raw_decode并从该位置再次开始解析.不幸的是,Python json模块不接受具有前缀空格的字符串.所以我们需要搜索以找到文档的第一个非空白部分.

from json import JSONDecoder, JSONDecodeError
import re

NOT_WHITESPACE = re.compile(r'[^\s]')

def decode_stacked(document, pos=0, decoder=JSONDecoder()):
    while True:
        match = NOT_WHITESPACE.search(document, pos)
        if not match:
            return
        pos = match.start()

        try:
            obj, pos = decoder.raw_decode(document, pos)
        except JSONDecodeError:
            # do something sensible if there's some error
            raise
        yield obj

s = """

{"a": 1}  


   [
1
,   
2
]


"""

for obj in decode_stacked(s):
    print(obj)
Run Code Online (Sandbox Code Playgroud)

打印:

{'a': 1}
[1, 2]
Run Code Online (Sandbox Code Playgroud)

  • 这篇文章应该得到更多的关注.这是堆叠json的完美解决方案,例如`{json1} {json2} {json3}` - 如果jsons只是附加到单个文件,这种结构很容易发生,没有显式嵌套(例如外部`{}`和`条目之间的逗号.非常感谢! (12认同)
  • 仅供参考:对于非空白字符有一个简单的转义:`\S`。大写变体是小写变体的否定(因此 `\W = [^\w]`、`\D=[^\d]` 等等。) (2认同)

dan*_*nca 23

使用json数组,格式为:

[
{"ID":"12345","Timestamp":"20140101", "Usefulness":"Yes",
  "Code":[{"event1":"A","result":"1"},…]},
{"ID":"1A35B","Timestamp":"20140102", "Usefulness":"No",
  "Code":[{"event1":"B","result":"1"},…]},
{"ID":"AA356","Timestamp":"20140103", "Usefulness":"No",
  "Code":[{"event1":"B","result":"0"},…]},
...
]
Run Code Online (Sandbox Code Playgroud)

然后将其导入您的python代码

import json

with open('file.json') as json_file:

    data = json.load(json_file)
Run Code Online (Sandbox Code Playgroud)

现在,数据的内容是一个数组,其中的字典代表每个元素.

您可以轻松访问它,即:

data[0]["ID"]
Run Code Online (Sandbox Code Playgroud)

  • 这很酷,但是阻止您将文件用作无尽的流(例如,类似日志的附加文件数据)并消耗更多内存. (22认同)
  • 在某些情况下,很多……比……我拥有的记忆更多。 (2认同)

Dan*_*kin 8

因此,正如在几个注释中提到的那样,将数据包含在数组中比较简单,但是随着数据集大小的增加,该解决方案在效率方面无法很好地扩展。当您要访问数组中的随机对象时,实际上仅应使用迭代器,否则,生成器是您的理想之选。下面,我原型化了一个读取器函数,该函数分别读取每个json对象并返回一个生成器。

基本思想是向读者发出信号,让他们分割回车符“ \ n”(对于Windows,则为“ \ r \ n”)。Python可以使用文件 .readline()函数来完成此操作。

import json
def json_readr(file):
    for line in open(file, mode="r"):
        yield json.loads(line)
Run Code Online (Sandbox Code Playgroud)

但是,只有在按原样写入文件时,此方法才真正起作用-每个对象都用换行符分隔。在下面,我写了一个编写器的示例,该示例将json对象数组分开并将每个对象保存在新行中。

def json_writr(file, json_objects):
    f = open(file, mode="w")
    for jsonobj in json_objects:
        jsonstr = json.dumps(jsonobj)
        f.write(jsonstr+"\n")
    f.flush()
    f.close()
Run Code Online (Sandbox Code Playgroud)

您还可以对文件 .writelines()和列表理解进行相同的操作

...
    jsobjs = [json.dumps(j)+"\n" for j in json_objects]
    f.writelines(jsobjs)
...
Run Code Online (Sandbox Code Playgroud)

如果您想追加数据而不是写入新文件,只需将'mode =“ w”'更改为'mode =“ a”'。

最后,我发现这不仅在尝试在文本编辑器中打开json文件时提高了可读性,而且在更有效地使用内存方面也有很大帮助。

关于这一点,如果您在某个时候改变了主意,并且希望将列表从阅读器中删除,Python允许您将生成器函数放在列表中,并自动填充列表。换句话说,只要写

lst = list(json_readr(file))
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助。抱歉,如果有点冗长。


Fan*_*ing 6

根据@dunes的答案添加了流媒体支持:

import re
from json import JSONDecoder, JSONDecodeError

NOT_WHITESPACE = re.compile(r"[^\s]")


def stream_json(file_obj, buf_size=1024, decoder=JSONDecoder()):
    buf = ""
    ex = None
    while True:
        block = file_obj.read(buf_size)
        if not block:
            break
        buf += block
        pos = 0
        while True:
            match = NOT_WHITESPACE.search(buf, pos)
            if not match:
                break
            pos = match.start()
            try:
                obj, pos = decoder.raw_decode(buf, pos)
            except JSONDecodeError as e:
                ex = e
                break
            else:
                ex = None
                yield obj
        buf = buf[pos:]
    if ex is not None:
        raise ex
Run Code Online (Sandbox Code Playgroud)