Собесов

Сценарий: pandas json_normalize для вложенного JSON

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

Условие

API возвращает массив JSON-объектов:

[
  {"order_id": 1, "user": {"id": 42, "city": "Moscow"},
   "items": [{"sku": "A", "qty": 2}, {"sku": "B", "qty": 1}]},
  ...
]

Нужно получить плоскую таблицу order_id, user_id, city, sku, qty.

Решение

json_normalize

import pandas as pd
 
# meta — поля сверху, record_path — путь до массива
flat = pd.json_normalize(
    data,
    record_path='items',
    meta=['order_id', ['user', 'id'], ['user', 'city']],
    record_prefix='item_',
)
 
flat = flat.rename(columns={
    'user.id': 'user_id',
    'user.city': 'city',
    'item_sku': 'sku',
    'item_qty': 'qty',
})

Если массивы лежат глубже

# data = {"orders": [...]}
pd.json_normalize(data, record_path=['orders', 'items'], meta=[['orders', 'order_id']])

Список нерегулярных JSON

Если у некоторых записей нет itemsrecord_path падает. Решение: errors='ignore' или пред-фильтрация.

data_valid = [d for d in data if 'items' in d and d['items']]
flat = pd.json_normalize(data_valid, record_path='items', meta=['order_id'])

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

  1. meta принимает либо строку ('order_id'), либо список путей (['user', 'id']). Перепутать = тихий KeyError.
  2. По умолчанию вложенные ключи становятся user.id — точка в имени мешает SQL/df.user.id не работает. Переименовывать.
  3. Если в items встречаются пустые массивы, json_normalize пропускает запись — заказ исчезнет из результата. Решение: предварительно подставить [{}].
  4. Большие JSON (>1 ГБ) лучше парсить потоково через ijson, а не загружать целиком.
  5. Для глубоких структур (3+ уровня) часто проще написать руками генератор словарей и pd.DataFrame(list).

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

pd.json_normalize(data, record_path='items', meta=['order_id', ['user','id']]) для развёртки одного уровня массивов и переноса родительских полей.

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

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

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