JSON у CSV на Python — Приклади DictWriter і pandas
Використовуйте безкоштовний 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 є плоским — кожне значення розміщується в сітці рядків і стовпців. Конвертація працює чисто, коли кожен об'єкт має однаковий набір ключів верхнього рівня. Вкладені об'єкти, масиви та непослідовні ключі — ось де все стає цікавішим. Самі дані залишаються ідентичними; змінюється лише структура.
[{"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 контролює як порядок стовпців, так і те, які ключі включаються.
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) при читанні з файлового дескриптора. Це постійно плутає людей — один читає рядок, інший читає файловий об'єкт.
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 потребують явного форматування, щоб уникнути наукової нотації.
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.
pandas — конвертація JSON у CSV з DataFrames
Якщо ви вже працюєте в кодовій базі, де активно використовується pandas, або ваш JSON має вкладені об'єкти, які потрібно вирівняти, підхід pandas вимагає значно менше коду, ніж версія із stdlib. Компроміс: pandas — це залежність ~30 МБ. Для одноразового скрипту це нормально. Для Docker-образу, який ви відправляєте у виробництво, підхід із stdlib тримає все легшим.
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() обходить вкладені словники і вирівнює їх у стовпці з назвами, розділеними крапкою.
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.
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 і повертають кількість рядків, щоб виклики могли виявляти порожні результати та надсилати відповідні сповіщення.
Файл на диску — зчитати, конвертувати, зберегти
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 — отримати та конвертувати
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 для перетворення даних, а потім конвертуйте.
# Однорядковий 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
# Зберегти як 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)
" "$@"# 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.csvMiller (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.
pip install pyarrow
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 відображає таблиці з межами, вирівнюванням та кольором у терміналі — корисно для попереднього перегляду конвертації під час розробки без відкриття вихідного файлу.
pip install 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)
# Відображає кольорову таблицю з межами в терміналіcsv.DictWriter або DataFrame.to_csv(), а rich використовуйте лише для попереднього перегляду.Робота з великими JSON-файлами
json.load() зчитує весь файл у пам'ять. Для JSON-файлу розміром 200 МБ це означає ~200 МБ сирого тексту плюс накладні витрати на об'єкти Python — легко 500 МБ+ у купі. Для файлів понад 100 МБ читайте вхід потоково за допомогою ijson і записуйте рядки CSV у міру надходження.
pip install ijson
Потокова передача JSON-масиву у CSV за допомогою ijson
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.
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.load(), може займати 3–5 ГБ ОЗП через накладні витрати на об'єкти Python. З ijson використання пам'яті залишається постійним незалежно від розміру файлу. Якщо вам просто потрібно швидко конвертувати невеликий файл, вставте його у конвертер JSON у CSV замість цього.Типові помилки
Проблема: Модуль csv записує закінчення рядків . Без newline='', текстовий режим Python додає ще один на Windows, створюючи подвоєний вивід.
Вирішення: Завжди передавайте newline='' при відкритті файлу для запису CSV. Це нешкідливо на macOS/Linux.
with open("output.csv", "w") as f:
writer = csv.DictWriter(f, fieldnames=columns)
writer.writeheader()
writer.writerows(data)
# Порожні рядки між кожним рядком даних на Windowswith open("output.csv", "w", newline="", encoding="utf-8") as f:
writer = csv.DictWriter(f, fieldnames=columns)
writer.writeheader()
writer.writerows(data)
# Чистий вивід на всіх платформахПроблема: Без index=False pandas додає стовпець з автоінкрементним номером рядка (0, 1, 2, ...), що забруднює CSV даними, яких ніколи не було в оригінальному JSON.
Вирішення: Передайте index=False у to_csv(). Якщо вам справді потрібен стовпець індексу, назвіть його явно через df.index.name = 'row_num'.
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,...Проблема: Якщо JSON-об'єкти мають різні ключі (деякі записи мають необов'язкові поля), використання ключів першого запису як fieldnames мовчки відкидає стовпці, що з'являються лише в пізніших записах.
Вирішення: Зберіть усі унікальні ключі з усіх записів перед створенням DictWriter.
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.DictWriter викликає str() для вкладених словників, створюючи стовпці зі значеннями на кшталт "{'city': 'Portland'}"— сирий Python repr, а не реальні дані.
Вирішення: Спочатку вирівняйте вкладені об'єкти за допомогою pd.json_normalize() або власної функції вирівнювання.
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_regioncsv.DictWriter проти pandas — швидке порівняння
Використовуйте 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, щоб уникнути відсутніх стовпців.
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-імпорту та формул електронних таблиць.
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.
# Неправильно — порожні рядки на 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 для дозапису.
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 по файловому дескриптору обробляє кожен рядок незалежно і досягає постійного використання пам'яті без сторонніх бібліотек.
# Швидко для файлів, що поміщаються в пам'ять
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 за замовчуванням відкривається в текстовому режимі.
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Пов'язані інструменти
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.
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.