Собесов

Сценарий: разбор глубоко вложенного JSON без потерь

PythonJSON и веб-скрейпингСредняяMiddle

Условие

JSON приходит с произвольной структурой: словари внутри списков внутри словарей до 5 уровней. Нужно вытащить все пары key:value (где value — скаляр) с полным путём в виде a.b[0].c.

Решение

Рекурсивный обход

def flatten_json(obj, prefix=''):
    rows = []
    if isinstance(obj, dict):
        for k, v in obj.items():
            new_prefix = f'{prefix}.{k}' if prefix else k
            rows.extend(flatten_json(v, new_prefix))
    elif isinstance(obj, list):
        for i, v in enumerate(obj):
            rows.extend(flatten_json(v, f'{prefix}[{i}]'))
    else:
        rows.append((prefix, obj))
    return rows
 
# Использование
import json
data = json.load(open('payload.json'))
flat = flatten_json(data)
df = pd.DataFrame(flat, columns=['path', 'value'])

Альтернатива — flatten_json или pandas.json_normalize

# json_normalize плющит словари, но не списки скаляров
import pandas as pd
pd.json_normalize(data, sep='.')
 
# pip install flatten-json
from flatten_json import flatten
flat_dict = flatten(data, separator='.')
df = pd.DataFrame([flat_dict])

Потоковая обработка большого JSON

Если файл 5 ГБ — json.load упадёт. ijson парсит по токенам:

import ijson
 
with open('big.json', 'rb') as f:
    for obj in ijson.items(f, 'items.item'):
        process(obj)

Подводные камни

  1. Рекурсия глубже 1000 уровней упирается в sys.getrecursionlimit() — для глубоких JSON делать итеративно через стек.
  2. Числа в JSON — int или float; даты — строки. После flatten типы потеряются, нужно типизировать.
  3. Списки разной длины в массиве объектов превращают плоскую таблицу в «рваную». Решение: explode или раздельные таблицы.
  4. NaN в JSON нет — обычно null, который json.load даёт как None. pd.DataFrame сам конвертирует в NaN/None в зависимости от dtype.
  5. UTF-8 BOM в начале файла ломает json.load — открывайте с encoding='utf-8-sig'.

Эталонный ответ

Рекурсивный обход с накоплением полного пути (a.b[0].c) либо json_normalize для регулярных структур. Для гигабайтных JSON — ijson потоково.

Хочешь увидеть разбор?

Зарегистрируйся бесплатно — откроется развёрнутое решение этой задачи и ещё 4 на выбор.

Зарегистрироваться и увидеть разбор
Уже есть аккаунт? Войти