JSON у CSV на Python — Приклади DictWriter і pandas

·Backend Developer·ПеревіреноPriya Sharma·Опубліковано

Використовуйте безкоштовний JSON to CSV прямо в браузері — без встановлення.

Спробувати JSON to CSV онлайн →

Майже кожен конвеєр даних рано чи пізно стикається з одним і тим самим кроком: API повертає JSON, але наступний споживач — електронна таблиця, скрипт імпорту, команда Redshift COPY — потребує CSV. Конвертація JSON у CSV на Python здається тривіальною, поки ви не натрапите на вкладені об'єкти, непослідовні ключі або значення datetime, що потребують спеціальної обробки. Python надає два надійних шляхи: вбудовані модулі json + csv для скриптів без залежностей та pandas для вирівнювання вкладених структур і великих наборів даних — або онлайн-конвертер JSON у CSV для швидких разових конвертацій без будь-якого коду. Цей посібник охоплює обидва підходи від початку до кінця з готовими до запуску прикладами для Python 3.8+.

  • csv.DictWriter конвертує список словників у CSV без залежностей — використовуйте json.load() для парсингу, потім writeheader() + writerows().
  • Завжди відкривайте CSV-файли з newline="" на Windows, щоб запобігти порожнім рядкам між рядками даних.
  • pd.json_normalize() вирівнює вкладений JSON у плаский DataFrame перед викликом to_csv() — автоматично обробляє багаторівневу вкладеність.
  • Передавайте index=False у DataFrame.to_csv() — без цього pandas записує небажаний стовпець з номерами рядків.
  • Для файлів понад 500 МБ використовуйте ijson для потокового парсингу JSON разом із csv.DictWriter для постійного використання пам'яті.

Що таке конвертація JSON у CSV?

Конвертація JSON у CSV перетворює масив JSON-об'єктів у табличний формат, де кожен об'єкт стає рядком, а кожен ключ — заголовком стовпця. JSON є ієрархічним — об'єкти можуть бути вкладені на довільну глибину. CSV є плоским — кожне значення розміщується в сітці рядків і стовпців. Конвертація працює чисто, коли кожен об'єкт має однаковий набір ключів верхнього рівня. Вкладені об'єкти, масиви та непослідовні ключі — ось де все стає цікавішим. Самі дані залишаються ідентичними; змінюється лише структура.

Before · json
After · json
[{"order_id":"ord_91a3","total":149.99,"status":"shipped"},
 {"order_id":"ord_b7f2","total":34.50,"status":"pending"}]
order_id,total,status
ord_91a3,149.99,shipped
ord_b7f2,34.50,pending

csv.DictWriter — конвертація JSON у CSV без pandas

Модуль csv постачається з кожною інсталяцією Python. Жодного pip install, жодних труднощів з віртуальним середовищем. csv.DictWriter приймає список словників і записує кожен з них як рядок CSV, відображаючи ключі словника на заголовки стовпців. Параметр fieldnames контролює як порядок стовпців, так і те, які ключі включаються.

Python 3.8+ — мінімальний приклад json to csv
import json
import csv

# Приклад JSON-даних — масив об'єктів замовлень
json_string = """
[
  {"order_id": "ord_91a3", "product": "Wireless Keyboard", "quantity": 2, "unit_price": 74.99},
  {"order_id": "ord_b7f2", "product": "USB-C Hub", "quantity": 1, "unit_price": 34.50},
  {"order_id": "ord_c4e8", "product": "Monitor Stand", "quantity": 3, "unit_price": 29.95}
]
"""

records = json.loads(json_string)

with open("orders.csv", "w", newline="", encoding="utf-8") as csvfile:
    writer = csv.DictWriter(csvfile, fieldnames=records[0].keys())
    writer.writeheader()
    writer.writerows(records)

# orders.csv:
# order_id,product,quantity,unit_price
# ord_91a3,Wireless Keyboard,2,74.99
# ord_b7f2,USB-C Hub,1,34.50
# ord_c4e8,Monitor Stand,3,29.95

Аргумент newline="" у open() не є необов'язковим на Windows. Без нього ви отримаєте подвійні символи повернення каретки — які відображаються як порожні рядки між кожним рядком даних у Excel. На macOS та Linux це нешкідливо, тому просто завжди включайте його.

Код вище використовує json.loads() для рядка. Використовуйте json.load() (без кінцевої s) при читанні з файлового дескриптора. Це постійно плутає людей — один читає рядок, інший читає файловий об'єкт.

Python 3.8+ — зчитати JSON-файл, записати CSV-файл
import json
import csv

with open("server_metrics.json", encoding="utf-8") as jf:
    metrics = json.load(jf)  # json.load() для файлових об'єктів

# Явні fieldnames контролюють порядок стовпців
columns = ["timestamp", "hostname", "cpu_percent", "memory_mb", "disk_io_ops"]

with open("server_metrics.csv", "w", newline="", encoding="utf-8") as cf:
    writer = csv.DictWriter(cf, fieldnames=columns, extrasaction="ignore")
    writer.writeheader()
    writer.writerows(metrics)

# З'являються лише п'ять зазначених стовпців, саме в такому порядку

Встановлення extrasaction="ignore" мовчки відкидає всі ключі у словниках, яких немає у вашому списку fieldnames. За замовчуванням "raise", що кидає ValueError якщо будь-який словник має несподіваний ключ. Обирайте те, що відповідає вашій толерантності до несподіванок.

Примітка:csv.DictWriter проти csv.writer: DictWriter автоматично відображає ключі словника на позиції стовпців. csv.writer записує сирі списки як рядки — ви самі відповідаєте за порядок стовпців. DictWriter майже завжди є правильним вибором для JSON-to-CSV, оскільки JSON-записи вже є словниками.

Модуль csv Python постачається з трьома іменованими діалектами: excel (кома-роздільник, CRLF-закінчення рядків — за замовчуванням), excel-tab (таб-роздільник, CRLF-закінчення) та unix (LF-закінчення рядків, лапки навколо всіх нечислових полів). Передайте назву діалекту як аргумент dialect у csv.DictWriter. Ви також можете визначити власний діалект за допомогою csv.register_dialect() якщо ваша цільова система має незвичні правила лапок або роздільників. Для більшості робочих процесів JSON-to-CSV діалект excel є правильним, але перемикайтеся на unix при записі файлів, які оброблятимуться POSIX-інструментами, такими як awk або sort.

Обробка нестандартних типів: datetime, UUID та Decimal

JSON з API часто містить дати у вигляді ISO-рядків, UUID як рядки з дефісами та грошові значення як числа з плаваючою крапкою. Коли ви парсите їх у Python-об'єкти для обробки перед записом у CSV, вам потрібно конвертувати їх назад у рядки. Модуль csv викликає str() для кожного значення, тому більшість типів просто працює. Але об'єкти datetime дають брудні рядкові представлення за замовчуванням, а значення Decimal потребують явного форматування, щоб уникнути наукової нотації.

Python 3.8+ — попередня обробка datetime та Decimal перед записом CSV
import json
import csv
from datetime import datetime, timezone
from decimal import Decimal
from uuid import UUID

# Імітація відповіді API з Python-типами
transactions = [
    {
        "txn_id": UUID("a1b2c3d4-e5f6-7890-abcd-ef1234567890"),
        "created_at": datetime(2026, 3, 15, 9, 30, 0, tzinfo=timezone.utc),
        "amount": Decimal("1249.99"),
        "currency": "USD",
        "merchant": "CloudHost Inc.",
    },
    {
        "txn_id": UUID("b2c3d4e5-f6a7-8901-bcde-f12345678901"),
        "created_at": datetime(2026, 3, 15, 14, 12, 0, tzinfo=timezone.utc),
        "amount": Decimal("87.50"),
        "currency": "EUR",
        "merchant": "DataSync GmbH",
    },
]

def prepare_row(record: dict) -> dict:
    """Конвертувати нерядкові типи у CSV-сумісні рядки."""
    return {
        "txn_id": str(record["txn_id"]),
        "created_at": record["created_at"].isoformat(),
        "amount": f"{record['amount']:.2f}",
        "currency": record["currency"],
        "merchant": record["merchant"],
    }

with open("transactions.csv", "w", newline="", encoding="utf-8") as f:
    writer = csv.DictWriter(f, fieldnames=["txn_id", "created_at", "amount", "currency", "merchant"])
    writer.writeheader()
    for txn in transactions:
        writer.writerow(prepare_row(txn))

# transactions.csv:
# txn_id,created_at,amount,currency,merchant
# a1b2c3d4-e5f6-7890-abcd-ef1234567890,2026-03-15T09:30:00+00:00,1249.99,USD,CloudHost Inc.
# b2c3d4e5-f6a7-8901-bcde-f12345678901,2026-03-15T14:12:00+00:00,87.50,EUR,DataSync GmbH

Функція prepare_row() є правильним підходом тут. Замість того, щоб намагатися навчити csv.DictWriter про власні типи, ви нормалізуєте кожен запис у рядки перед записом. Я надаю перевагу явному виклику .isoformat() для об'єктів datetime, а не покладаючись на str() — формат виводу більш передбачуваний, і парсери нижнього рівня надійно обробляють ISO 8601.

Попередження:Якщо ви пропустите значення Decimal без форматування, дуже малі або дуже великі числа можуть відображатися в науковій нотації (наприклад, 1.5E+7). Завжди форматуйте Decimal з явним f-рядком, як f"{value:.2f}" при записі фінансових даних у CSV.

Альтернативний шаблон для конвеєрів з багатьма власними типами — розширити json.JSONEncoder. Успадкуйте від нього, перевизначте метод default() так, щоб він повертав JSON-серіалізоване значення для кожного власного типу, потім передайте підклас як аргумент cls у json.dumps(). Повторне кодування через власний енкодер перед записом у CSV нормалізує всі типи за один крок без виклику prepare_row() для кожного рядка. Шаблон prepare_row() показаний вище простіший для разових скриптів; підхід з підкласом JSONEncoder краще масштабується, коли та сама доменна модель з власними типами використовується на кількох етапах конвеєра або в мікросервісах.

Довідник параметрів csv.DictWriter

Повна сигнатура конструктора: csv.DictWriter(f, fieldnames, restval="", extrasaction="raise", dialect="excel", **fmtparams). Більшість із них мають розумні значення за замовчуванням. Ті, які ви реально змінюватимете: fieldnames, delimiter та extrasaction.

Параметр
Тип
За замовч.
Опис
f
file object
(обов'язк.)
Будь-який об'єкт з методом write() — зазвичай з open()
fieldnames
sequence
(обов'язк.)
Список ключів, що визначає порядок стовпців у CSV
restval
str
""
Значення, що записується, коли у словнику відсутній ключ із fieldnames
extrasaction
str
"raise"
"raise" кидає ValueError для зайвих ключів; "ignore" мовчки їх ігнорує
dialect
str / Dialect
"excel"
Попередньо визначені правила форматування — "excel", "excel-tab" або "unix"
delimiter
str
","
Один символ-роздільник полів — використовуйте "\t" для TSV
quotechar
str
"
Символ для взяття полів у лапки, якщо вони містять роздільник
quoting
int
csv.QUOTE_MINIMAL
Контролює, коли застосовується екранування — MINIMAL, ALL, NONNUMERIC, NONE
lineterminator
str
"\r\n"
Рядок, що додається після кожного рядка — замініть на "\n" для Unix-стилю

pandas — конвертація JSON у CSV з DataFrames

Якщо ви вже працюєте в кодовій базі, де активно використовується pandas, або ваш JSON має вкладені об'єкти, які потрібно вирівняти, підхід pandas вимагає значно менше коду, ніж версія із stdlib. Компроміс: pandas — це залежність ~30 МБ. Для одноразового скрипту це нормально. Для Docker-образу, який ви відправляєте у виробництво, підхід із stdlib тримає все легшим.

Python 3.8+ — pandas read_json потім to_csv
import pandas as pd

# Зчитати JSON-масив безпосередньо у DataFrame
df = pd.read_json("warehouse_inventory.json")

# Записати у CSV — index=False запобігає автоматично генерованим номерам рядків
df.to_csv("warehouse_inventory.csv", index=False)

# Ось і все. Два рядки. pandas автоматично визначає типи стовпців.

Прапор index=False — це одна з тих речей, які доводиться шукати щоразу. Без нього pandas записує стовпець 0, 1, 2, ... як перший стовпець вашого CSV. Нікому це не потрібно.

Вирівнювання вкладеного JSON з json_normalize

Реальні відповіді API рідко бувають плоскими. Замовлення містять адреси доставки, користувачі мають вкладені налаштування, телеметричні події містять вкладені метадані. pd.json_normalize() обходить вкладені словники і вирівнює їх у стовпці з назвами, розділеними крапкою.

Python 3.8+ — вирівнювання вкладеного JSON за допомогою json_normalize
import json
import pandas as pd

api_response = """
[
  {
    "order_id": "ord_91a3",
    "placed_at": "2026-03-15T09:30:00Z",
    "customer": {
      "name": "Sarah Chen",
      "email": "s.chen@example.com",
      "tier": "premium"
    },
    "shipping": {
      "method": "express",
      "address": {
        "city": "Portland",
        "state": "OR",
        "zip": "97201"
      }
    },
    "total": 299.95
  },
  {
    "order_id": "ord_b7f2",
    "placed_at": "2026-03-15T14:12:00Z",
    "customer": {
      "name": "James Park",
      "email": "j.park@example.com",
      "tier": "standard"
    },
    "shipping": {
      "method": "standard",
      "address": {
        "city": "Austin",
        "state": "TX",
        "zip": "73301"
      }
    },
    "total": 87.50
  }
]
"""

orders = json.loads(api_response)

# json_normalize вирівнює вкладені словники — sep контролює роздільник
df = pd.json_normalize(orders, sep="_")
df.to_csv("flat_orders.csv", index=False)

# Отримані стовпці:
# order_id, placed_at, customer_name, customer_email, customer_tier,
# shipping_method, shipping_address_city, shipping_address_state,
# shipping_address_zip, total

Параметр sep="_" контролює, як об'єднуються назви вкладених ключів. За замовчуванням ".", що дає стовпці на кшталт customer.name. Я надаю перевагу підкресленням, оскільки крапки в назвах стовпців викликають проблеми з SQL-імпортом та деякими формулами електронних таблиць.

Для відповідей API, де масив записів знаходиться під вкладеним ключем, використовуйте параметр record_path. Якщо відповідь виглядає як {"data": {"orders": [...]}}, передайте record_path=["data", "orders"] щоб перейти до потрібного списку. Необов'язковий параметр meta дозволяє витягувати поля батьківського рівня разом із вкладеними записами — корисно, коли відповідь містить інформацію про пагінацію верхнього рівня (номер сторінки, загальна кількість), яку ви хочете бачити як стовпець у кожному рядку. Разом, record_path і meta обробляють більшість реальних форм відповідей вкладених API без спеціального попереднього оброблення.

Довідник параметрів DataFrame.to_csv()

DataFrame.to_csv() має понад 20 параметрів. Ось ті, що мають значення для робочих процесів JSON-to-CSV.

Параметр
Тип
За замовч.
Опис
path_or_buf
str / Path / None
None
Шлях до файлу або буфер — None повертає CSV як рядок
sep
str
","
Роздільник полів — використовуйте "\t" для TSV
index
bool
True
Записати індекс рядка як перший стовпець — майже завжди встановлюйте False
columns
list
None
Вибрати підмножину стовпців та змінити їх порядок у виводі
header
bool / list
True
Записати назви стовпців — встановіть False при дозаписі до наявного файлу
encoding
str
"utf-8"
Кодування виводу — використовуйте "utf-8-sig" для сумісності з Excel на Windows
na_rep
str
""
Рядкове представлення для відсутніх значень (NaN, None)
quoting
int
csv.QUOTE_MINIMAL
Контролює, коли поля беруться в лапки
Python 3.8+ — to_csv із типовими перевизначеннями параметрів
import pandas as pd

df = pd.read_json("telemetry_events.json")

# TSV-вивід із явним кодуванням та обробкою відсутніх значень
df.to_csv(
    "telemetry_events.tsv",
    sep="\t",
    index=False,
    encoding="utf-8",
    na_rep="NULL",
    columns=["event_id", "timestamp", "source", "severity", "message"],
)

# Запис у stdout для передачі в shell-скриптах
print(df.to_csv(index=False))

# Повернути як рядок (без запису файлу)
csv_string = df.to_csv(index=False)
print(len(csv_string), "characters")

Конвертація JSON у CSV з файлу та відповіді API

Два найпоширеніших реальних сценарії: зчитування JSON з файлу на диску та його конвертація, або отримання JSON з HTTP API та збереження результату як CSV. Під час розробки можна обійтися без обробки помилок. У виробництві цей вибір обернеться нічним сповіщенням о 2-й годині. Файли можуть не існувати, API можуть повертати коди статусу 4xx або 5xx замість JSON, тіло відповіді може бути об'єктом помилки, а не масивом, або JSON може бути обрізаний через таймаут мережі. Наведені нижче шаблони явно обробляють всі ці випадки, записують помилки у stderr і повертають кількість рядків, щоб виклики могли виявляти порожні результати та надсилати відповідні сповіщення.

Файл на диску — зчитати, конвертувати, зберегти

Python 3.8+ — конвертація JSON-файлу у CSV з обробкою помилок
import json
import csv
import sys

def json_file_to_csv(input_path: str, output_path: str) -> int:
    """Конвертувати JSON-файл, що містить масив об'єктів, у CSV.
    Повертає кількість записаних рядків.
    """
    try:
        with open(input_path, encoding="utf-8") as jf:
            data = json.load(jf)
    except FileNotFoundError:
        print(f"Error: {input_path} not found", file=sys.stderr)
        return 0
    except json.JSONDecodeError as exc:
        print(f"Error: invalid JSON in {input_path}: {exc.msg} at line {exc.lineno}", file=sys.stderr)
        return 0

    if not isinstance(data, list) or not data:
        print(f"Error: expected a non-empty JSON array in {input_path}", file=sys.stderr)
        return 0

    # Зібрати всі унікальні ключі з усіх записів — обробляє непослідовні схеми
    all_keys: list[str] = []
    seen: set[str] = set()
    for record in data:
        for key in record:
            if key not in seen:
                all_keys.append(key)
                seen.add(key)

    with open(output_path, "w", newline="", encoding="utf-8") as cf:
        writer = csv.DictWriter(cf, fieldnames=all_keys, restval="", extrasaction="ignore")
        writer.writeheader()
        writer.writerows(data)

    return len(data)

rows = json_file_to_csv("deploy_logs.json", "deploy_logs.csv")
print(f"Wrote {rows} rows to deploy_logs.csv")

Відповідь HTTP API — отримати та конвертувати

Python 3.8+ — отримати JSON з API та зберегти як CSV
import json
import csv
import urllib.request
import urllib.error

def api_response_to_csv(url: str, output_path: str) -> int:
    """Отримати JSON з кінцевої точки REST API та записати його як CSV."""
    try:
        req = urllib.request.Request(url, headers={"Accept": "application/json"})
        with urllib.request.urlopen(req, timeout=30) as resp:
            if resp.status != 200:
                print(f"Error: API returned status {resp.status}")
                return 0
            body = resp.read().decode("utf-8")
    except urllib.error.URLError as exc:
        print(f"Error: could not reach {url}: {exc.reason}")
        return 0

    try:
        records = json.loads(body)
    except json.JSONDecodeError as exc:
        print(f"Error: API returned invalid JSON: {exc.msg}")
        return 0

    if not isinstance(records, list) or not records:
        print("Error: expected a non-empty JSON array from the API")
        return 0

    with open(output_path, "w", newline="", encoding="utf-8") as cf:
        writer = csv.DictWriter(cf, fieldnames=records[0].keys())
        writer.writeheader()
        writer.writerows(records)

    return len(records)

rows = api_response_to_csv(
    "https://api.internal.example.com/v2/deployments?status=completed",
    "completed_deployments.csv",
)
print(f"Exported {rows} deployments to CSV")
Примітка:Наведений вище приклад використовує urllib зі стандартної бібліотеки, щоб скрипт не мав залежностей. Якщо у вас встановлено requests, замініть розділ з urllib на resp = requests.get(url, timeout=30); records = resp.json() — решта коду запису CSV залишається незмінною.

Конвертація JSON у CSV через командний рядок

Іноді вам просто потрібен однорядковий рядок у терміналі. Прапор -c Python дозволяє виконати швидку конвертацію без створення файлу скрипту. Для складніших перетворень спочатку передайте через jq для перетворення даних, а потім конвертуйте.

bash — однорядкова конвертація json у csv
# Однорядковий Python: зчитує JSON зі stdin, записує CSV у stdout
cat orders.json | python3 -c "
import json, csv, sys
data = json.load(sys.stdin)
w = csv.DictWriter(sys.stdout, fieldnames=data[0].keys())
w.writeheader()
w.writerows(data)
"

# Зберегти вивід у файл
cat orders.json | python3 -c "
import json, csv, sys
data = json.load(sys.stdin)
w = csv.DictWriter(sys.stdout, fieldnames=data[0].keys())
w.writeheader()
w.writerows(data)
" > orders.csv
bash — самодостатній CLI-скрипт з argparse
# Зберегти як json2csv.py і запустити: python3 json2csv.py input.json -o output.csv
python3 -c "
import json, csv, argparse, sys

parser = argparse.ArgumentParser(description='Convert JSON array to CSV')
parser.add_argument('input', help='Path to JSON file')
parser.add_argument('-o', '--output', default=None, help='Output CSV path (default: stdout)')
parser.add_argument('-d', '--delimiter', default=',', help='CSV delimiter')
args = parser.parse_args()

with open(args.input) as f:
    data = json.load(f)

out = open(args.output, 'w', newline='') if args.output else sys.stdout
writer = csv.DictWriter(out, fieldnames=data[0].keys(), delimiter=args.delimiter)
writer.writeheader()
writer.writerows(data)
if args.output:
    out.close()
    print(f'Wrote {len(data)} rows to {args.output}', file=sys.stderr)
" "$@"
bash — використання jq + csvkit для складних перетворень
# Install csvkit: pip install csvkit

# jq вибирає та вирівнює поля, in2csv виконує CSV-форматування
cat api_response.json | jq '[.[] | {id: .order_id, customer: .customer.name, total}]' | in2csv -f json > orders.csv

# Miller (mlr) — ще один варіант для JSON-to-CSV
mlr --json2csv cat orders.json > orders.csv

Miller (mlr) — це окремий бінарний файл, що обробляє JSON, CSV і TSV як форматами першого класу без необхідності середовища Python. Прапор --json2csv конвертує JSON-вхід у CSV за один прохід, і ви можете об'єднувати команди Miller для фільтрації, сортування або перейменування стовпців у тій самій команді перед записом виводу. Встановлюється через Homebrew на macOS (brew install miller) або через пакетний менеджер вашого дистрибутиву Linux. Особливо корисний у CI-конвеєрах, де потрібна швидка конвертація JSON-to-CSV без розгортання Python-середовища.

Високопродуктивна альтернатива — pandas з pyarrow

Для наборів даних у десятки мільйонів рядків pandas з бекендом pyarrow читає та записує значно швидше, ніж за замовчуванням. C-backed рушій Arrow обробляє стовпчасті дані ефективніше, ніж порядково-орієнтований модуль csv Python. API залишається тим самим — ви просто встановлюєте параметр engine.

bash — встановлення pyarrow
pip install pyarrow
Python 3.8+ — pandas з pyarrow для швидшого запису CSV
import pandas as pd

# Зчитати JSON з рушієм pyarrow (швидший парсинг великих файлів)
df = pd.read_json("sensor_readings.json", engine="pyarrow")

# to_csv не має параметра engine, але операції з DataFrame
# між читанням і записом виграють від стовпчастого компонування pyarrow
df.to_csv("sensor_readings.csv", index=False)

# Для справді великих експортів розгляньте запис у Parquet замість CSV
# — бінарний формат, у 5-10 разів менший, зберігає типи
df.to_parquet("sensor_readings.parquet", engine="pyarrow")

Якщо ви обробляєте більше кількох сотень МБ JSON і кінцевий споживач підтримує Parquet, пропустіть CSV повністю. Parquet менший, зберігає типи стовпців, і як Redshift, так і BigQuery завантажують його нативно. CSV є форматом із втратою інформації — кожне значення перетворюється на рядок.

Вивід у терміналі з підсвічуванням синтаксису

Бібліотека rich відображає таблиці з межами, вирівнюванням та кольором у терміналі — корисно для попереднього перегляду конвертації під час розробки без відкриття вихідного файлу.

bash — встановлення rich
pip install rich
Python 3.8+ — попередній перегляд CSV-виводу в терміналі за допомогою rich
import json
from rich.console import Console
from rich.table import Table

json_string = """
[
  {"hostname": "web-prod-1", "cpu_percent": 72.3, "memory_mb": 3840, "uptime_hours": 720},
  {"hostname": "web-prod-2", "cpu_percent": 45.1, "memory_mb": 2560, "uptime_hours": 168},
  {"hostname": "db-replica-1", "cpu_percent": 91.7, "memory_mb": 7680, "uptime_hours": 2160}
]
"""

records = json.loads(json_string)
console = Console()

table = Table(title="Server Metrics Preview", show_lines=True)
for key in records[0]:
    table.add_column(key, style="cyan" if key == "hostname" else "white")

for row in records:
    table.add_row(*[str(v) for v in row.values()])

console.print(table)
# Відображає кольорову таблицю з межами в терміналі
Попередження:Rich призначений лише для відображення в терміналі. Не використовуйте його для генерації CSV-файлів — він додає ANSI-коди керування, які пошкодять вивід. Записуйте у файли за допомогою csv.DictWriter або DataFrame.to_csv(), а rich використовуйте лише для попереднього перегляду.

Робота з великими JSON-файлами

json.load() зчитує весь файл у пам'ять. Для JSON-файлу розміром 200 МБ це означає ~200 МБ сирого тексту плюс накладні витрати на об'єкти Python — легко 500 МБ+ у купі. Для файлів понад 100 МБ читайте вхід потоково за допомогою ijson і записуйте рядки CSV у міру надходження.

bash — встановлення ijson
pip install ijson

Потокова передача JSON-масиву у CSV за допомогою ijson

Python 3.8+ — потокова конвертація великого JSON-масиву у CSV з постійним використанням пам'яті
import ijson
import csv

def stream_json_to_csv(json_path: str, csv_path: str) -> int:
    """Конвертувати великий JSON-масив у CSV без завантаження всього в пам'ять."""
    with open(json_path, "rb") as jf, open(csv_path, "w", newline="", encoding="utf-8") as cf:
        # ijson.items повертає кожен елемент масиву верхнього рівня по одному
        records = ijson.items(jf, "item")

        first_record = next(records)
        fieldnames = list(first_record.keys())

        writer = csv.DictWriter(cf, fieldnames=fieldnames)
        writer.writeheader()
        writer.writerow(first_record)

        count = 1
        for record in records:
            writer.writerow(record)
            count += 1

    return count

rows = stream_json_to_csv("clickstream_2026_03.json", "clickstream_2026_03.csv")
print(f"Streamed {rows} records to CSV")

NDJSON / JSON Lines — по одному об'єкту на рядок

NDJSON (Newline-Delimited JSON), також відомий як JSON Lines або .jsonl, зберігає один валідний JSON-об'єкт на рядок без обгортального масиву. Цей формат поширений у конвеєрах логів, потоках подій (Kafka, Kinesis) та масових експортах з таких сервісів, як Elasticsearch та BigQuery. Оскільки кожен рядок є самодостатнім JSON-об'єктом, ви можете обробляти NDJSON-файл звичайним циклом Python for по файловому дескриптору — бібліотека ijson не потрібна. Використання пам'яті залишається постійним незалежно від розміру файлу, що робить цей підхід найпростішим для потокової обробки, коли вихідні дані вже у форматі JSON Lines.

Python 3.8+ — конвертація NDJSON у CSV рядок за рядком
import json
import csv

def ndjson_to_csv(ndjson_path: str, csv_path: str) -> int:
    """Конвертувати файл у форматі newline-delimited JSON у CSV, рядок за рядком."""
    with open(ndjson_path, encoding="utf-8") as nf:
        first_line = nf.readline()
        first_record = json.loads(first_line)
        fieldnames = list(first_record.keys())

        with open(csv_path, "w", newline="", encoding="utf-8") as cf:
            writer = csv.DictWriter(cf, fieldnames=fieldnames)
            writer.writeheader()
            writer.writerow(first_record)

            count = 1
            for line in nf:
                line = line.strip()
                if not line:
                    continue
                try:
                    record = json.loads(line)
                    writer.writerow(record)
                    count += 1
                except json.JSONDecodeError:
                    continue  # пропустити пошкоджені рядки

    return count

rows = ndjson_to_csv("access_log.ndjson", "access_log.csv")
print(f"Converted {rows} log entries to CSV")
Примітка:Переходьте до потокової обробки, коли JSON-файл перевищує 100 МБ. 1 ГБ JSON-масив, завантажений за допомогою json.load(), може займати 3–5 ГБ ОЗП через накладні витрати на об'єкти Python. З ijson використання пам'яті залишається постійним незалежно від розміру файлу. Якщо вам просто потрібно швидко конвертувати невеликий файл, вставте його у конвертер JSON у CSV замість цього.

Типові помилки

Відсутнє newline='' у open() — порожні рядки на Windows

Проблема: Модуль csv записує закінчення рядків . Без newline='', текстовий режим Python додає ще один на Windows, створюючи подвоєний вивід.

Вирішення: Завжди передавайте newline='' при відкритті файлу для запису CSV. Це нешкідливо на macOS/Linux.

Before · Python
After · Python
with open("output.csv", "w") as f:
    writer = csv.DictWriter(f, fieldnames=columns)
    writer.writeheader()
    writer.writerows(data)
# Порожні рядки між кожним рядком даних на Windows
with open("output.csv", "w", newline="", encoding="utf-8") as f:
    writer = csv.DictWriter(f, fieldnames=columns)
    writer.writeheader()
    writer.writerows(data)
# Чистий вивід на всіх платформах
Забутий index=False у pandas to_csv()

Проблема: Без index=False pandas додає стовпець з автоінкрементним номером рядка (0, 1, 2, ...), що забруднює CSV даними, яких ніколи не було в оригінальному JSON.

Вирішення: Передайте index=False у to_csv(). Якщо вам справді потрібен стовпець індексу, назвіть його явно через df.index.name = 'row_num'.

Before · Python
After · Python
df = pd.read_json("events.json")
df.to_csv("events.csv")
# CSV отримує зайвий безіменний стовпець: ,event_id,timestamp,...
# Початкова кома ламає багато CSV-парсерів
df = pd.read_json("events.json")
df.to_csv("events.csv", index=False)
# Чистий CSV: event_id,timestamp,...
Використання records[0].keys() при непослідовних ключах

Проблема: Якщо JSON-об'єкти мають різні ключі (деякі записи мають необов'язкові поля), використання ключів першого запису як fieldnames мовчки відкидає стовпці, що з'являються лише в пізніших записах.

Вирішення: Зберіть усі унікальні ключі з усіх записів перед створенням DictWriter.

Before · Python
After · Python
records = json.load(f)
writer = csv.DictWriter(out, fieldnames=records[0].keys())
# Пропускає поле "discount", що з'являється лише в records[2]
records = json.load(f)
all_keys = list(dict.fromkeys(k for r in records for k in r))
writer = csv.DictWriter(out, fieldnames=all_keys, restval="")
# Кожен ключ з кожного запису включено як стовпець
Запис вкладених словників у CSV без вирівнювання

Проблема: csv.DictWriter викликає str() для вкладених словників, створюючи стовпці зі значеннями на кшталт "{'city': 'Portland'}"— сирий Python repr, а не реальні дані.

Вирішення: Спочатку вирівняйте вкладені об'єкти за допомогою pd.json_normalize() або власної функції вирівнювання.

Before · Python
After · Python
records = [{"id": "evt_1", "meta": {"source": "web", "region": "us-west"}}]
writer = csv.DictWriter(f, fieldnames=["id", "meta"])
writer.writerows(records)
# стовпець meta містить: {'source': 'web', 'region': 'us-west'}
import pandas as pd
records = [{"id": "evt_1", "meta": {"source": "web", "region": "us-west"}}]
df = pd.json_normalize(records, sep="_")
df.to_csv("events.csv", index=False)
# Стовпці: id, meta_source, meta_region

csv.DictWriter проти pandas — швидке порівняння

Метод
Вкладений JSON
Власні типи
Потокова обробка
Залежності
Потрібна установка
csv.DictWriter
✗ (вручну)
✓ (рядок за рядком)
Немає
Ні (stdlib)
csv.writer
✓ (рядок за рядком)
Немає
Ні (stdlib)
pd.DataFrame.to_csv()
✗ (лише плоский)
✓ (через dtypes)
pandas + numpy
pip install
pd.json_normalize() + to_csv()
✓ (через dtypes)
pandas + numpy
pip install
csv.writer + json_flatten
flatten_json
pip install
jq + csvkit (CLI)
✓ (через jq)
N/A
jq, csvkit
Системна установка

Використовуйте csv.DictWriter коли вам потрібні нульові залежності, ваш JSON є плоским, і скрипт виконується в обмеженому середовищі (CI-контейнери, Lambda-функції, вбудований Python). Використовуйте pd.json_normalize() + to_csv() коли JSON є вкладеним, вам потрібно перетворити або відфільтрувати дані перед експортом, або ви вже працюєте в pandas-робочому процесі. Для файлів, що не поміщаються в пам'ять, поєднуйте ijson з csv.DictWriter для потокової обробки з постійним використанням пам'яті.

Для швидких конвертацій без коду, конвертер JSON у CSV на ToolDeck впорається без будь-якого налаштування Python.

Часті запитання

Як конвертувати JSON у CSV на Python без pandas?

Використовуйте вбудовані модулі json та csv. Викличте json.load() для парсингу JSON-файлу в список словників, витягніть fieldnames з ключів першого словника, створіть csv.DictWriter, викличте writeheader(), потім writerows(). Цей підхід не потребує зовнішніх залежностей і працює в будь-якому середовищі Python 3.x. Він також працює швидше за pandas для малих файлів, оскільки відсутні витрати на виділення пам'яті для DataFrame. Якщо у JSON-об'єктів різні ключі в різних записах, спочатку зберіть усі унікальні ключі за допомогою dict.fromkeys(k for r in records for k in r), перш ніж передавати їх як fieldnames, щоб уникнути відсутніх стовпців.

Python
import json
import csv

with open("orders.json") as f:
    records = json.load(f)

with open("orders.csv", "w", newline="", encoding="utf-8") as f:
    writer = csv.DictWriter(f, fieldnames=records[0].keys())
    writer.writeheader()
    writer.writerows(records)

Як обробляти вкладений JSON при конвертації у CSV?

Плоскі JSON-масиви безпосередньо відповідають рядкам CSV, але вкладені об'єкти спочатку потрібно вирівняти. З pandas pd.json_normalize() робить це автоматично — він об'єднує вкладені ключі через роздільник-крапку (наприклад, "address.city"). Без pandas напишіть рекурсивну функцію, що обходить словник і конкатенує ключі з роздільником. Для глибоко вкладених структур з кількома рівнями json_normalize обробляє їх за один прохід. Параметр sep контролює символ об'єднання між сегментами ключів — підкреслення зазвичай безпечніше за крапку за замовчуванням для SQL-імпорту та формул електронних таблиць.

Python
import pandas as pd

nested_data = [
    {"id": "ord_91a3", "customer": {"name": "Анна Іваненко", "email": "a.ivanenko@pryklad.ua"}},
]
df = pd.json_normalize(nested_data, sep="_")
# Columns: id, customer_name, customer_email
df.to_csv("flat_orders.csv", index=False)

Чому в моєму CSV-файлі порожні рядки між рядками даних на Windows?

Модуль csv записує закінчення рядків \r\n за замовчуванням. На Windows відкриття файлу в текстовому режимі додає ще один \r, що утворює \r\r\n — що виглядає як порожній рядок. Рішення — завжди передавати newline="" у open(). Це говорить Python не перетворювати закінчення рядків, дозволяючи модулю csv самому їх обробляти. Цей шаблон потрібен незалежно від операційної системи — він нешкідливий на macOS та Linux і критично важливий на Windows. Документація Python явно зазначає це в розділі про модуль csv як правильний спосіб відкривати файли для запису CSV.

Python
# Неправильно — порожні рядки на Windows
with open("output.csv", "w") as f:
    writer = csv.writer(f)

# Правильно — newline="" запобігає подвійному \r
with open("output.csv", "w", newline="") as f:
    writer = csv.writer(f)

Як дозаписати JSON-записи до наявного CSV-файлу?

Відкрийте файл у режимі додавання ("a") і створіть DictWriter з тими самими fieldnames. Пропустіть writeheader(), оскільки рядок заголовку вже існує. З pandas використовуйте to_csv(mode="a", header=False). Переконайтеся, що порядок стовпців відповідає наявному файлу, інакше дані потраплять не в ті стовпці. Якщо ви не впевнені в порядку стовпців наявного файлу, спочатку відкрийте його за допомогою csv.DictReader і зчитайте fieldnames з його атрибута fieldnames, перш ніж створювати writer для дозапису.

Python
import csv

new_records = [
    {"order_id": "ord_f4c1", "total": 89.50, "status": "shipped"},
]

with open("orders.csv", "a", newline="", encoding="utf-8") as f:
    writer = csv.DictWriter(f, fieldnames=["order_id", "total", "status"])
    writer.writerows(new_records)

Який найшвидший спосіб конвертувати великий JSON-файл у CSV на Python?

Для файлів розміром до 500 МБ pd.read_json() з наступним to_csv() є найшвидшим однорядковим підходом — pandas використовує оптимізований код на C внутрішньо. Для файлів понад 500 МБ використовуйте ijson для потокового читання JSON-записів і записуйте їх у CSV за допомогою csv.DictWriter рядок за рядком. Це підтримує постійне використання пам'яті незалежно від розміру файлу. Для NDJSON-файлів (по одному JSON-об'єкту на рядок) ijson не потрібен взагалі — звичайний цикл Python for по файловому дескриптору обробляє кожен рядок незалежно і досягає постійного використання пам'яті без сторонніх бібліотек.

Python
# Швидко для файлів, що поміщаються в пам'ять
import pandas as pd
df = pd.read_json("large_dataset.json")
df.to_csv("large_dataset.csv", index=False)

# Потокова обробка для файлів, що не поміщаються в пам'ять
import ijson, csv
with open("huge.json", "rb") as jf, open("huge.csv", "w", newline="") as cf:
    records = ijson.items(jf, "item")
    first = next(records)
    writer = csv.DictWriter(cf, fieldnames=first.keys())
    writer.writeheader()
    writer.writerow(first)
    for record in records:
        writer.writerow(record)

Чи можна писати CSV-вивід у stdout замість файлу на Python?

Так. Передайте sys.stdout як файловий об'єкт у csv.writer() або csv.DictWriter(). Це корисно для передачі виводу в shell-скриптах або швидкого налагодження. З pandas викличте to_csv(sys.stdout, index=False) або to_csv(None), щоб отримати рядок, який можна надрукувати. Тимчасовий файл не потрібен. При запису у stdout на Windows спочатку викличте sys.stdout.reconfigure(newline=""), щоб уникнути проблеми подвійного символу повернення каретки, оскільки stdout за замовчуванням відкривається в текстовому режимі.

Python
import csv
import sys
import json

data = json.loads('[{"host":"web-1","cpu":72.3},{"host":"web-2","cpu":45.1}]')
writer = csv.DictWriter(sys.stdout, fieldnames=data[0].keys())
writer.writeheader()
writer.writerows(data)
# host,cpu
# web-1,72.3
# web-2,45.1

Пов'язані інструменти

MS
Maria SantosBackend Developer

Maria is a backend developer specialising in Python and API integration. She has broad experience with data pipelines, serialisation formats, and building reliable server-side services. She is an active member of the Python community and enjoys writing practical, example-driven guides that help developers solve real problems without unnecessary theory.

PS
Priya SharmaТехнічний рецензент

Priya is a data scientist and machine learning engineer who has worked across the full Python data stack — from raw data ingestion and cleaning to model deployment and monitoring. She is passionate about reproducible research, Jupyter-based workflows, and the practical engineering side of ML. She writes about NumPy, Pandas, data serialisation, and the Python patterns that make data pipelines reliable at scale.