【问题标题】:python ijson not working on multiple element at oncepython ijson不能一次处理多个元素
【发布时间】:2022-01-10 11:46:02
【问题描述】:

我有数千个非常大的 JSON 文件,需要对特定元素进行处理。为了避免内存过载,我使用了一个名为 ijson 的 python 库,当我只处理 json 文件中的单个元素但当我尝试一次处理多个元素时,它可以正常工作

IncompleteJSONError:解析错误:过早的 EOF

部分 JSON:

{
  "info": {
    "added": 1631536344.112968,
    "started": 1631537322.81162,
    "duration": 14,
    "ended": 1631537337.342377
  },
  "network": {
    "domains": [
      {
        "ip": "231.90.255.25",
        "domain": "dns.msfcsi.com"
      },
      {
        "ip": "12.23.25.44",
        "domain": "teo.microsoft.com"
      },
      {
        "ip": "87.101.90.42",
        "domain": "www.msf.com"
      }
    ]
  }
}

工作代码:(打开多个文件)

my_file_list = [f for f in glob.glob("data/jsons/*.json")]
final_result = []
for filename in my_file_list:
    row = {}
    with open(filename, 'r') as f:
        info = ijson.items(f, 'info')
        for o in info:
             row['added']= float(o.get('added'))
             row['started']= float(o.get('started'))
             row['duration']= o.get('duration')
             row['ended']= float(o.get('ended'))
    
    with open(filename, 'r') as f:
        domains = ijson.items(f, 'network.domains.item')
        domain_count = 0
        for domain in domains:
            domain_count+=1
        row['domain_count'] = domain_count

失败代码:(单个文件打开)

my_file_list = [f for f in glob.glob("data/jsons/*.json")]
final_result = []
for filename in my_file_list:
    row = {}
    with open(filename, 'r') as f:
        info = ijson.items(f, 'info')
        for o in info:
             row['added']= float(o.get('added'))
             row['started']= float(o.get('started'))
             row['duration']= o.get('duration')
             row['ended']= float(o.get('ended'))
    
        domains = ijson.items(f, 'network.domains.item')
        domain_count = 0
        for domain in domains:
            domain_count+=1
        row['domain_count'] = domain_count

不确定这是否是原因 Using python ijson to read a large json file with multiple json objects ijson 无法同时处理多个 json 元素。

另外,请告诉我任何其他 python 包或任何可以处理大尺寸 json 而没有内存问题的示例示例。

【问题讨论】:

  • 我过去曾使用pypi.org/project/json-stream 完成这项任务。工作得很好。如果您没有获得有关 ijson 的帮助,可以尝试一下。非易失性。我认为这是一个 TextIO 阅读问题。答案部分的详细信息。

标签: python json ijson


【解决方案1】:

我认为发生这种情况是因为您已经完成了从文件中读取 IO 流,您已经到了最后,并且已经在请求另一个查询。

你可以做的是在第二次查询之前将光标重置为0位置:

f.seek(0)

在评论中我说您也应该尝试json-stream,但这不是ijsonjson-stream 错误,它是TextIO 功能。

这相当于您再次打开文件。

如果您不想这样做,那么也许您应该考虑遍历 JSON 的每个部分,然后确定每个对象是否具有 infonetwork.domains.item

【讨论】:

  • f.seek(0) 似乎工作:)
  • 顺便说一句,我有另一个查询,你能建议我如何在不迭代 ijson 的情况下获取元素计数,例如获取domain_count i,e 3,不愿意使用 for循环以仅获取元素计数
  • 好吧,既然您仍然需要解析和识别这些元素,看来迭代它们是唯一的方法。您可以考虑以更结构化的格式加载数据。
【解决方案2】:

虽然上面的答案是正确的,但您可以做得更好:如果您知道 JSON 文件的结构并且可以依赖它,那么您可以利用这一点并只读取文件一次。

ijson 有一个偶数interception mechanism,其中的示例与您想要实现的非常相似。在您的情况下,您想要获取 info 值,然后遍历 network.domains.item 并计算它们。应该这样做:

row = {}
with open(filename, 'r') as f:
    parse_events = ijson.parse(f, use_float=True)
    for prefix, event, value in parse_events:
        if prefix == 'info.added':
            row['added'] = value
        elif prefix == 'info.started':
            row['started'] = value
        elif prefix == 'info.duration':
             row['duration'] = value
        elif prefix == 'info.ended':
             row['ended'] = value
        elif prefix == 'info' and event == 'end_map':
            break
    row['domain_count'] = sum(1 for _ in ijson.items(parse_events, 'network.domains.item'))

注意方法:

  • ijson.items 得到 ijson.parse 的结果。
  • use_float=True 使您不必自己将值转换为 float
  • sum()-ing 1 可以对来自ijson.items 的每个项目进行计数,因此您不必手动循环自己。

【讨论】:

  • 非常感谢您的回答先生。一定要试试这个。
  • 只有一个查询,如果我想获取value 并对其进行迭代怎么办,因为我有一些嵌套数组/对象元素必须稍后在我的 json 中解析
  • 上述解决方案有效,但多行总和不起作用,只有 domain_count 返回预期结果,其他计数返回 0,但如果我注释掉 domain_count 则完全计数
  • 您共享的代码运行良好,但是当我尝试在 row['domain_count'] 之后添加另一个字段计数时,它总是返回 0,例如,如果我尝试 row['network_count'] 它返回 0 但如果注释掉第一个然后它返回正确的计数。
猜你喜欢
  • 2022-01-23
  • 1970-01-01
  • 2014-03-03
  • 2013-10-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多