JSON to CSV Python — DictWriter + pandas Beispiele
Nutze das kostenlose JSON to CSV direkt im Browser – keine Installation erforderlich.
JSON to CSV online testen →Nahezu jede Datenpipeline stößt irgendwann auf denselben Schritt: Eine API gibt JSON zurück, aber der nächste Verbraucher — ein Tabellenkalkulationsprogramm, ein Import-Skript, ein Redshift-COPY-Befehl — benötigt CSV. Die Konvertierung von JSON zu CSV in Python klingt trivial, bis man auf verschachtelte Objekte, inkonsistente Schlüssel oder Datetime-Werte trifft, die eine spezielle Behandlung erfordern. Python bietet zwei solide Wege: die eingebauten json + csv Module für Skripte ohne externe Abhängigkeiten, und pandas für das Abflachen verschachtelter Strukturen und größere Datensätze — oder den Online-JSON-zu-CSV-Konverter für schnelle Einzel-Konvertierungen ohne Code. Dieser Leitfaden behandelt beide Ansätze von Anfang bis Ende, mit ausführbaren Python-3.8+-Beispielen.
- ✓csv.DictWriter konvertiert eine Liste von Dicts ohne Abhängigkeiten in CSV — json.load() zum Parsen verwenden, dann writeheader() + writerows().
- ✓CSV-Dateien unter Windows immer mit newline="" öffnen, um leere Zeilen zwischen Datenzeilen zu verhindern.
- ✓pd.json_normalize() flacht verschachteltes JSON in ein flaches DataFrame ab, bevor to_csv() aufgerufen wird — behandelt mehrstufige Verschachtelungen automatisch.
- ✓index=False an DataFrame.to_csv() übergeben — ohne diese Option schreibt pandas eine unerwünschte Zeilennummern-Spalte.
- ✓Für Dateien über 500 MB ijson für das Streaming-JSON-Parsing in Kombination mit csv.DictWriter für konstante Speichernutzung verwenden.
Was ist JSON-zu-CSV-Konvertierung?
Die JSON-zu-CSV-Konvertierung transformiert ein Array von JSON-Objekten in ein tabellarisches Format, bei dem jedes Objekt zu einer Zeile und jeder Schlüssel zu einer Spaltenüberschrift wird. JSON ist hierarchisch — Objekte können beliebig tief verschachtelt sein. CSV ist flach — jeder Wert sitzt in einem Zeilen-Spalten-Raster. Die Konvertierung funktioniert reibungslos, wenn jedes Objekt denselben Satz von Schlüsseln auf oberster Ebene teilt. Verschachtelte Objekte, Arrays und inkonsistente Schlüssel machen die Sache komplizierter. Die Rohdaten bleiben identisch; nur die Struktur ändert sich.
[{"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 ohne pandas in CSV konvertieren
Das csv-Modul ist in jeder Python-Installation enthalten. Kein pip install, keine Virtual-Environment-Verrenkungen. csv.DictWriter nimmt eine Liste von Dictionaries entgegen und schreibt jedes als CSV-Zeile, wobei Dict-Schlüssel auf Spaltenüberschriften abgebildet werden. Der fieldnames-Parameter steuert sowohl die Spaltenreihenfolge als auch, welche Schlüssel eingeschlossen werden.
import json
import csv
# Beispiel-JSON-Daten — ein Array von Bestellobjekten
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.95Das Argument newline="" bei open() ist unter Windows nicht optional. Ohne es entstehen doppelte Wagenrückläufe — die in Excel als Leerzeilen zwischen jeder Datenzeile erscheinen. Unter macOS und Linux ist es harmlos, also immer angeben.
Der obige Code verwendet json.loads() für einen String. Verwende json.load() (ohne abschließendes s), wenn aus einem Datei-Handle gelesen wird. Das verwirrt ständig — die eine Funktion liest einen String, die andere ein Datei-Objekt.
import json
import csv
with open("server_metrics.json", encoding="utf-8") as jf:
metrics = json.load(jf) # json.load() für Datei-Objekte
# Explizite Feldnamen steuern die Spaltenreihenfolge
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)
# Es erscheinen nur die fünf angegebenen Spalten in genau dieser ReihenfolgeDas Setzen von extrasaction="ignore" verwirft stillschweigend alle Schlüssel in den Dicts, die nicht in der fieldnames-Liste stehen. Der Standard ist "raise", der einen ValueError auslöst, wenn ein Dict einen unerwarteten Schlüssel hat. Wähle das, was zu deiner Fehlertoleranz passt.
csv.DictWriter vs. csv.writer: DictWriter ordnet Dict-Schlüssel automatisch Spaltenpositionen zu. csv.writer schreibt rohe Listen als Zeilen — die Spaltenreihenfolge muss selbst verwaltet werden. DictWriter ist für JSON-zu-CSV fast immer die richtige Wahl, da JSON-Datensätze bereits Dictionaries sind.Das csv-Modul wird mit drei benannten Dialekten geliefert: excel (Komma als Trennzeichen, CRLF-Zeilenenden — der Standard), excel-tab (Tabulator als Trennzeichen, CRLF-Enden) und unix (LF-Zeilenenden, alle nicht-numerischen Felder werden in Anführungszeichen gesetzt). Den Dialektnamen als dialect-Argument an csv.DictWriter übergeben. Mit csv.register_dialect() kann auch ein benutzerdefinierter Dialekt definiert werden, wenn das Zielsystem ungewöhnliche Anführungszeichen- oder Trennzeichenregeln hat. Für die meisten JSON-zu-CSV-Workflows ist der excel-Dialekt korrekt, aber auf unix wechseln, wenn Dateien von POSIX-Tools wie awk oder sort verarbeitet werden.
Umgang mit nicht-standardmäßigen Typen: datetime, UUID und Decimal
JSON von APIs enthält Datumsangaben häufig als ISO-Strings, UUIDs als Bindestriche-Strings und Geldbeträge als Floats. Wenn diese vor dem Schreiben der CSV in Python-Objekte umgewandelt werden, müssen sie wieder in Strings zurückkonvertiert werden. Das csv-Modul ruft str() für jeden Wert auf, sodass die meisten Typen einfach funktionieren. Aber datetime-Objekte erzeugen unübersichtliche Standard-String-Darstellungen, und Decimal-Werte müssen explizit formatiert werden, um wissenschaftliche Notation zu vermeiden.
import json
import csv
from datetime import datetime, timezone
from decimal import Decimal
from uuid import UUID
# Simulation einer geparsten API-Antwort mit Python-Typen
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:
"""Nicht-String-Typen in CSV-freundliche Strings konvertieren."""
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 GmbHDie Funktion prepare_row() ist hier der richtige Ansatz. Anstatt zu versuchen, csv.DictWriter benutzerdefinierte Typen beibringen zu wollen, normalisiert man jeden Datensatz vor dem Schreiben in Strings. Es empfiehlt sich, .isoformat() bei datetime-Objekten explizit aufzurufen, anstatt sich auf str() zu verlassen — das Ausgabeformat ist vorhersehbarer, und nachgelagerte Parser verarbeiten ISO 8601 zuverlässig.
Decimal-Werte ohne Formatierung durchgelassen werden, können sehr kleine oder sehr große Zahlen in wissenschaftlicher Notation erscheinen (z. B. 1.5E+7). Decimal beim Schreiben von Finanzdaten in CSV immer mit einem expliziten f-String wie f"{value:.2f}" formatieren.Ein alternatives Muster für Pipelines mit vielen benutzerdefinierten Typen ist die Erweiterung von json.JSONEncoder. Davon ableiten, die default()-Methode überschreiben, um für jeden benutzerdefinierten Typ einen JSON-serialisierbaren Wert zurückzugeben, und dann die Unterklasse als cls-Argument an json.dumps() übergeben. Das erneute Kodieren über den benutzerdefinierten Encoder vor dem CSV-Schreiben normalisiert alle Typen in einem Schritt, ohne einen zeilenweisen prepare_row()-Aufruf. Das oben gezeigte prepare_row()-Muster ist einfacher für Einzel-Skripte; der JSONEncoder-Unterklasse-Ansatz skaliert besser, wenn dasselbe Domänenmodell mit benutzerdefinierten Typen über viele Pipeline-Stufen oder Microservices hinweg geteilt wird.
csv.DictWriter — Parameterreferenz
Die vollständige Konstruktorsignatur lautet csv.DictWriter(f, fieldnames, restval="", extrasaction="raise", dialect="excel", **fmtparams). Die meisten davon haben sinnvolle Standardwerte. Die, die tatsächlich geändert werden, sind fieldnames, delimiter und extrasaction.
pandas — JSON mit DataFrames in CSV konvertieren
Wenn bereits in einer pandas-lastigen Codebasis gearbeitet wird oder das JSON verschachtelte Objekte enthält, die abgeflacht werden müssen, ist der pandas-Ansatz deutlich weniger Code als die stdlib-Version. Der Kompromiss: pandas ist eine ~30-MB-Abhängigkeit. Für ein Wegwerf-Skript ist das in Ordnung. Für ein Docker-Image, das in die Produktion geht, hält der stdlib-Ansatz die Dinge schlanker.
import pandas as pd
# JSON-Array direkt in einen DataFrame einlesen
df = pd.read_json("warehouse_inventory.json")
# In CSV schreiben — index=False verhindert die automatisch generierten Zeilennummern
df.to_csv("warehouse_inventory.csv", index=False)
# Das war's. Zwei Zeilen. pandas erkennt Spaltentypen automatisch.Das Flag index=False ist eines dieser Dinge, die man jedes Mal nachschlagen muss. Ohne es schreibt pandas eine 0, 1, 2, ...-Spalte als erste Spalte der CSV. Das will niemand.
Verschachteltes JSON mit json_normalize abflachen
Echte API-Antworten sind selten flach. Bestellungen enthalten Lieferadressen, Benutzer enthalten verschachtelte Einstellungen, Telemetrieereignisse enthalten verschachtelte Metadaten. pd.json_normalize() durchläuft verschachtelte Dictionaries und flacht sie in Spalten mit punktgetrennten Namen ab.
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 flacht verschachtelte Dicts ab — sep steuert das Trennzeichen
df = pd.json_normalize(orders, sep="_")
df.to_csv("flat_orders.csv", index=False)
# Resultierende Spalten:
# order_id, placed_at, customer_name, customer_email, customer_tier,
# shipping_method, shipping_address_city, shipping_address_state,
# shipping_address_zip, totalDer Parameter sep="_" steuert, wie verschachtelte Schlüsselnamen verbunden werden. Der Standard ist ".", was Spalten wie customer.name erzeugt. Unterstriche sind vorzuziehen, da Punkte in Spaltennamen bei SQL-Importen und manchen Tabellenkalkulationsformeln Probleme bereiten.
Für API-Antworten, die das Datensatz-Array unter einem verschachtelten Schlüssel verpacken, den Parameter record_path verwenden. Wenn die Antwort wie {"data": {"orders": [...]}} aussieht, record_path=["data", "orders"] übergeben, um zur richtigen Liste zu navigieren. Der optionale meta-Parameter ermöglicht es, übergeordnete Felder neben den verschachtelten Datensätzen zu extrahieren — nützlich, wenn die Antwort Paginierungsinformationen auf oberster Ebene (Seitennummer, Gesamtanzahl) enthält, die als Spalte in jeder Zeile erscheinen sollen. Zusammen behandeln record_path und meta die meisten realen verschachtelten API-Antwortstrukturen ohne benutzerdefinierte Vorverarbeitung.
DataFrame.to_csv() — Parameterreferenz
DataFrame.to_csv() hat über 20 Parameter. Dies sind die relevanten für JSON-zu-CSV-Workflows.
import pandas as pd
df = pd.read_json("telemetry_events.json")
# TSV-Ausgabe mit expliziter Kodierung und Behandlung fehlender Werte
df.to_csv(
"telemetry_events.tsv",
sep="\t",
index=False,
encoding="utf-8",
na_rep="NULL",
columns=["event_id", "timestamp", "source", "severity", "message"],
)
# Auf stdout schreiben für das Weiterleiten in Shell-Skripten
print(df.to_csv(index=False))
# Als String zurückgeben (keine Datei geschrieben)
csv_string = df.to_csv(index=False)
print(len(csv_string), "Zeichen")JSON aus einer Datei und API-Antwort in CSV konvertieren
Die zwei häufigsten realen Szenarien: JSON aus einer Datei auf dem Datenträger lesen und konvertieren, oder JSON von einer HTTP-API abrufen und das Ergebnis als CSV speichern. In der Entwicklung kann man auf Fehlerbehandlung verzichten. In der Produktion wird diese Entscheidung zu einem Alarm um 2 Uhr morgens. Dateien könnten nicht existieren, APIs könnten 4xx- oder 5xx-Statuscodes statt JSON zurückgeben, der Antwortinhalt könnte ein Fehlerobjekt statt eines Arrays sein, oder das JSON könnte durch ein Netzwerk-Timeout abgeschnitten sein. Die folgenden Muster behandeln all diese Fälle explizit, protokollieren Fehler auf stderr und geben eine Zeilenanzahl zurück, damit Aufrufer Null-Zeilen-Ausgaben erkennen und entsprechend alarmieren können.
Datei auf dem Datenträger — Lesen, Konvertieren, Speichern
import json
import csv
import sys
def json_file_to_csv(input_path: str, output_path: str) -> int:
"""Eine JSON-Datei mit einem Array von Objekten in CSV konvertieren.
Gibt die Anzahl der geschriebenen Zeilen zurück.
"""
try:
with open(input_path, encoding="utf-8") as jf:
data = json.load(jf)
except FileNotFoundError:
print(f"Fehler: {input_path} nicht gefunden", file=sys.stderr)
return 0
except json.JSONDecodeError as exc:
print(f"Fehler: ungültiges JSON in {input_path}: {exc.msg} in Zeile {exc.lineno}", file=sys.stderr)
return 0
if not isinstance(data, list) or not data:
print(f"Fehler: erwartet ein nicht-leeres JSON-Array in {input_path}", file=sys.stderr)
return 0
# Alle eindeutigen Schlüssel über alle Datensätze sammeln — behandelt inkonsistente Schemata
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"{rows} Zeilen in deploy_logs.csv geschrieben")HTTP-API-Antwort — Abrufen und Konvertieren
import json
import csv
import urllib.request
import urllib.error
def api_response_to_csv(url: str, output_path: str) -> int:
"""JSON von einem REST-API-Endpunkt abrufen und als CSV schreiben."""
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"Fehler: API hat Status {resp.status} zurückgegeben")
return 0
body = resp.read().decode("utf-8")
except urllib.error.URLError as exc:
print(f"Fehler: {url} konnte nicht erreicht werden: {exc.reason}")
return 0
try:
records = json.loads(body)
except json.JSONDecodeError as exc:
print(f"Fehler: API hat ungültiges JSON zurückgegeben: {exc.msg}")
return 0
if not isinstance(records, list) or not records:
print("Fehler: erwartet ein nicht-leeres JSON-Array von der 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"{rows} Deployments in CSV exportiert")urllib aus der Standardbibliothek, um das Skript abhängigkeitsfrei zu halten. Wenn requests installiert ist, den urllib-Abschnitt durch resp = requests.get(url, timeout=30); records = resp.json() ersetzen — der restliche CSV-Schreibcode bleibt identisch.JSON-zu-CSV-Konvertierung über die Kommandozeile
Manchmal benötigt man nur einen Einzeiler im Terminal. Pythons -c-Flag ermöglicht eine schnelle Konvertierung ohne eine Skript-Datei zu erstellen. Für komplexere Transformationen zuerst durch jq leiten, um die Daten umzustrukturieren, und dann konvertieren.
# Python-Einzeiler: liest JSON von stdin, schreibt CSV auf 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) " # Ausgabe in eine Datei speichern 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
# Als json2csv.py speichern und ausführen: python3 json2csv.py input.json -o output.csv
python3 -c "
import json, csv, argparse, sys
parser = argparse.ArgumentParser(description='JSON-Array in CSV konvertieren')
parser.add_argument('input', help='Pfad zur JSON-Datei')
parser.add_argument('-o', '--output', default=None, help='Ausgabe-CSV-Pfad (Standard: stdout)')
parser.add_argument('-d', '--delimiter', default=',', help='CSV-Trennzeichen')
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'{len(data)} Zeilen in {args.output} geschrieben', file=sys.stderr)
" "$@"# csvkit installieren: pip install csvkit
# jq wählt Felder aus, in2csv übernimmt die CSV-Formatierung
cat api_response.json | jq '[.[] | {id: .order_id, customer: .customer.name, total}]' | in2csv -f json > orders.csv
# Miller (mlr) ist eine weitere Option für JSON-zu-CSV
mlr --json2csv cat orders.json > orders.csvMiller (mlr) ist eine eigenständige Binärdatei, die JSON, CSV und TSV als erstklassige Formate behandelt, ohne Python-Laufzeitumgebung. Das Flag --json2csv konvertiert JSON-Eingaben in einem einzigen Durchgang in CSV, und Miller-Verben können verkettet werden, um Spalten im selben Befehl vor der Ausgabe zu filtern, zu sortieren oder umzubenennen. Installation über Homebrew unter macOS ( brew install miller) oder den Linux-Paketmanager. Besonders nützlich in CI-Pipelines, wo schnelle JSON-zu-CSV-Konvertierung ohne Python-Umgebung gewünscht wird.
Hochleistungs-Alternative — pandas mit pyarrow
Für Datensätze im Bereich von Zehnmillionen von Zeilen liest und schreibt pandas mit dem pyarrow-Backend deutlich schneller als mit dem Standard. Die C-basierte Arrow-Engine verarbeitet spaltenweise Daten effizienter als das zeilenweise csv-Modul von Python. Die API bleibt gleich — nur der engine-Parameter wird gesetzt.
pip install pyarrow
import pandas as pd
# JSON mit pyarrow-Engine einlesen (schnelleres Parsen für große Dateien)
df = pd.read_json("sensor_readings.json", engine="pyarrow")
# to_csv hat keinen engine-Parameter, aber die DataFrame-Operationen
# zwischen Lesen und Schreiben profitieren von pyarrows Spaltenlayout
df.to_csv("sensor_readings.csv", index=False)
# Für wirklich große Exporte Parquet statt CSV in Betracht ziehen
# — binäres Format, 5–10x kleiner, erhält Typen
df.to_parquet("sensor_readings.parquet", engine="pyarrow")Wenn mehr als einige hundert MB JSON verarbeitet werden und der finale Empfänger Parquet akzeptiert, CSV komplett überspringen. Parquet ist kleiner, erhält Spaltentypen, und sowohl Redshift als auch BigQuery laden es nativ. CSV ist ein verlustbehaftetes Format — jeder Wert wird zu einem String.
Terminal-Ausgabe mit Syntax-Hervorhebung
Die rich-Bibliothek rendert Tabellen mit Rahmen, Ausrichtung und Farbe im Terminal — nützlich, um eine Konvertierung während der Entwicklung in der Vorschau zu sehen, ohne die Ausgabedatei zu öffnen.
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-Metriken Vorschau", 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)
# Rendert eine farblich hervorgehobene Tabelle mit Rahmen im Terminalcsv.DictWriter oder DataFrame.to_csv() schreiben und rich nur für die Vorschau verwenden.Arbeiten mit großen JSON-Dateien
json.load() liest die gesamte Datei in den Arbeitsspeicher. Bei einer 200-MB-JSON-Datei bedeutet das ~200 MB Rohtext plus Python-Objekt-Overhead — leicht 500 MB+ Heap-Nutzung. Für Dateien über 100 MB die Eingabe mit ijson streamen und CSV-Zeilen während des Lesens schreiben.
pip install ijson
JSON-Array mit ijson in CSV streamen
import ijson
import csv
def stream_json_to_csv(json_path: str, csv_path: str) -> int:
"""Ein großes JSON-Array in CSV konvertieren, ohne alles in den Arbeitsspeicher zu laden."""
with open(json_path, "rb") as jf, open(csv_path, "w", newline="", encoding="utf-8") as cf:
# ijson.items liefert jedes Element des obersten Arrays einzeln
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"{rows} Datensätze in CSV gestreamt")NDJSON / JSON Lines — Ein Objekt pro Zeile
NDJSON (Newline-Delimited JSON), auch JSON Lines oder .jsonl genannt, speichert ein gültiges JSON-Objekt pro Zeile ohne umschließendes Array. Dieses Format ist verbreitet in Log-Pipelines, Event-Streams (Kafka, Kinesis) und Massen-Exporten von Diensten wie Elasticsearch und BigQuery. Da jede Zeile ein eigenständiges JSON-Objekt ist, kann eine NDJSON-Datei mit einer einfachen Python for-Schleife über das Datei-Handle verarbeitet werden — keine ijson-Bibliothek nötig. Der Speicher bleibt unabhängig von der Dateigröße konstant, was dies zum einfachsten Streaming-Ansatz macht, wenn die Quelldaten bereits im JSON-Lines-Format vorliegen.
import json
import csv
def ndjson_to_csv(ndjson_path: str, csv_path: str) -> int:
"""Eine newline-delimited JSON-Datei zeilenweise in CSV konvertieren."""
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 # fehlerhafte Zeilen überspringen
return count
rows = ndjson_to_csv("access_log.ndjson", "access_log.csv")
print(f"{rows} Log-Einträge in CSV konvertiert")json.load() geladen wird, kann 3–5 GB RAM verbrauchen, bedingt durch Python-Objekt-Overhead. Mit ijson bleibt der Speicher unabhängig von der Dateigröße konstant. Für eine schnelle Konvertierung einer kleinen Datei diese einfach in den JSON-zu-CSV-Konverter einfügen.Häufige Fehler
Problem: Das csv-Modul schreibt \r\n-Zeilenenden. Ohne newline='' fügt Pythons Textmodus unter Windows ein weiteres \r hinzu, was doppelzeilige Ausgabe erzeugt.
Lösung: Immer newline='' beim Öffnen einer Datei zum CSV-Schreiben übergeben. Unter macOS/Linux ist es harmlos.
with open("output.csv", "w") as f:
writer = csv.DictWriter(f, fieldnames=columns)
writer.writeheader()
writer.writerows(data)
# Leere Zeilen zwischen jeder Datenzeile unter Windowswith open("output.csv", "w", newline="", encoding="utf-8") as f:
writer = csv.DictWriter(f, fieldnames=columns)
writer.writeheader()
writer.writerows(data)
# Saubere Ausgabe auf allen PlattformenProblem: Ohne index=False fügt pandas eine automatisch hochzählende Zeilennummer-Spalte (0, 1, 2, ...) hinzu, die die CSV mit Daten verschmutzt, die nie im ursprünglichen JSON waren.
Lösung: index=False an to_csv() übergeben. Wenn tatsächlich eine Index-Spalte benötigt wird, diese explizit mit df.index.name = 'row_num' benennen.
df = pd.read_json("events.json")
df.to_csv("events.csv")
# CSV erhält eine extra namenlose Spalte: ,event_id,timestamp,...
# Das führende Komma bricht viele CSV-Parserdf = pd.read_json("events.json")
df.to_csv("events.csv", index=False)
# Saubere CSV: event_id,timestamp,...Problem: Wenn JSON-Objekte unterschiedliche Schlüssel haben (manche Datensätze haben optionale Felder), werden durch die Verwendung der Schlüssel des ersten Datensatzes als fieldnames Spalten, die nur in späteren Datensätzen erscheinen, still verworfen.
Lösung: Alle eindeutigen Schlüssel über alle Datensätze sammeln, bevor der DictWriter erstellt wird.
records = json.load(f) writer = csv.DictWriter(out, fieldnames=records[0].keys()) # Verpasst das Feld "discount", das nur in records[2] erscheint
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="") # Jeder Schlüssel aus jedem Datensatz wird als Spalte eingeschlossen
Problem: csv.DictWriter ruft str() für verschachtelte Dicts auf, was Spalten mit Werten wie "{'city': 'Portland'}"erzeugt — rohe Python-Darstellung, keine echten Daten.
Lösung: Verschachtelte Objekte zuerst mit pd.json_normalize() oder einer benutzerdefinierten Abflach-Funktion abflachen.
records = [{"id": "evt_1", "meta": {"source": "web", "region": "us-west"}}]
writer = csv.DictWriter(f, fieldnames=["id", "meta"])
writer.writerows(records)
# meta-Spalte enthält: {'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)
# Spalten: id, meta_source, meta_regioncsv.DictWriter vs. pandas — Kurzvergleich
csv.DictWriter verwenden, wenn null Abhängigkeiten benötigt werden, das JSON flach ist und das Skript in einer eingeschränkten Umgebung läuft (CI-Container, Lambda-Funktionen, eingebettetes Python).pd.json_normalize() + to_csv() verwenden, wenn das JSON verschachtelt ist, Daten vor dem Export transformiert oder gefiltert werden müssen oder bereits in einem pandas-Workflow gearbeitet wird. Für Dateien, die nicht in den Arbeitsspeicher passen, ijson mit csv.DictWriter für konstantes Speicher-Streaming kombinieren.
Für schnelle, codefreie Konvertierungen erledigt der JSON-zu-CSV-Konverter auf ToolDeck es ohne Python-Setup.
Häufig gestellte Fragen
Wie konvertiere ich JSON ohne pandas in Python zu CSV?
Verwende die eingebauten Module json und csv. Rufe json.load() auf, um die JSON-Datei als Liste von Dicts zu parsen, extrahiere die Feldnamen aus den Schlüsseln des ersten Dicts, erstelle einen csv.DictWriter, rufe writeheader() und dann writerows() auf. Dieser Ansatz hat null externe Abhängigkeiten und funktioniert in jeder Python-3.x-Umgebung. Er läuft außerdem schneller als pandas bei kleinen Dateien, da kein DataFrame-Overhead anfällt. Wenn deine JSON-Objekte über verschiedene Datensätze hinweg unterschiedliche Schlüssel haben, sammle alle einzigartigen Schlüssel zuerst mit dict.fromkeys(k for r in records for k in r), bevor du sie als fieldnames übergibst, um fehlende Spalten zu vermeiden.
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)Wie gehe ich mit verschachteltem JSON beim Konvertieren in CSV um?
Flache JSON-Arrays lassen sich direkt auf CSV-Zeilen abbilden, aber verschachtelte Objekte müssen zuerst abgeflacht werden. Mit pandas erledigt pd.json_normalize() das automatisch — es verbindet verschachtelte Schlüssel mit einem Punkttrennzeichen (z. B. "address.city"). Ohne pandas schreibe eine rekursive Funktion, die das Dict durchläuft und Schlüssel mit einem Trennzeichen verkettet. Für tief verschachtelte Strukturen mit mehreren Ebenen verarbeitet json_normalize alles in einem Durchgang. Der sep-Parameter steuert das Verbindungszeichen zwischen Schlüsselsegmenten — ein Unterstrich ist in der Regel sicherer als der Standard-Punkt für SQL-Importe und Tabellenkalkulationsformeln.
import pandas as pd
nested_data = [
{"id": "ord_91a3", "customer": {"name": "Anna Müller", "email": "a.mueller@beispiel.de"}},
]
df = pd.json_normalize(nested_data, sep="_")
# Spalten: id, customer_name, customer_email
df.to_csv("flat_orders.csv", index=False)Warum hat meine CSV unter Windows leere Zeilen zwischen den Datenzeilen?
Das csv-Modul schreibt standardmäßig \r\n-Zeilenenden. Unter Windows fügt das Öffnen der Datei im Textmodus ein weiteres \r hinzu, was \r\r\n erzeugt — das erscheint als Leerzeile. Die Lösung ist, immer newline="" an open() zu übergeben. Damit weist man Python an, keine Zeilenenden zu übersetzen und überlässt das dem csv-Modul. Dieses Muster ist unabhängig vom Betriebssystem erforderlich — es ist harmlos unter macOS und Linux, aber auf Windows unverzichtbar. Die Python-Dokumentation weist im Abschnitt zum csv-Modul ausdrücklich darauf hin, dass dies die korrekte Art ist, Dateien für CSV-Schreibvorgänge zu öffnen.
# Falsch — leere Zeilen unter Windows
with open("output.csv", "w") as f:
writer = csv.writer(f)
# Richtig — newline="" verhindert doppeltes \r
with open("output.csv", "w", newline="") as f:
writer = csv.writer(f)Wie hänge ich JSON-Datensätze an eine bestehende CSV-Datei an?
Öffne die Datei im Anhänge-Modus ("a") und erstelle einen DictWriter mit denselben Feldnamen. Überspringe writeheader(), da die Kopfzeile bereits vorhanden ist. Mit pandas verwende to_csv(mode="a", header=False). Stelle sicher, dass die Spaltenreihenfolge mit der bestehenden Datei übereinstimmt, sonst landen die Daten in den falschen Spalten. Wenn du die Spaltenreihenfolge in der bestehenden Datei nicht kennst, öffne sie zuerst mit csv.DictReader und lese die Feldnamen aus dem fieldnames-Attribut, bevor du den Writer zum Anhängen erstellst.
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)Was ist der schnellste Weg, eine große JSON-Datei in Python in CSV zu konvertieren?
Für Dateien unter 500 MB ist pd.read_json() gefolgt von to_csv() der schnellste Einzelaufruf — pandas verwendet intern optimierten C-Code. Für Dateien über 500 MB verwende ijson, um JSON-Datensätze zu streamen und sie mit csv.DictWriter Zeile für Zeile in CSV zu schreiben. Dies hält die Speichernutzung unabhängig von der Dateigröße konstant. Für NDJSON-Dateien (ein JSON-Objekt pro Zeile) benötigst du ijson überhaupt nicht — eine einfache Python-for-Schleife über das Datei-Handle verarbeitet jede Zeile unabhängig und erreicht konstanten Speicherverbrauch ohne externe Bibliotheken.
# Schnell für Dateien, die in den Arbeitsspeicher passen
import pandas as pd
df = pd.read_json("large_dataset.json")
df.to_csv("large_dataset.csv", index=False)
# Streaming für Dateien, die nicht in den Arbeitsspeicher passen
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)Kann ich die CSV-Ausgabe in Python auf stdout schreiben statt in eine Datei?
Ja. Übergib sys.stdout als Datei-Objekt an csv.writer() oder csv.DictWriter(). Das ist nützlich für das Weiterleiten von Ausgaben in Shell-Skripten oder zum schnellen Debuggen. Mit pandas rufe to_csv(sys.stdout, index=False) auf oder to_csv(None), um einen String zu erhalten, den du ausgeben kannst. Keine temporäre Datei nötig. Beim Schreiben auf stdout unter Windows rufe zuerst sys.stdout.reconfigure(newline="") auf, um das Problem mit doppelten Wagenrückläufen zu vermeiden, da stdout standardmäßig im Textmodus geöffnet wird.
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.1Verwandte Tools
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.