Python JSON เป็น CSV — คู่มือ
ใช้ แปลง JSON เป็น CSV ฟรีโดยตรงในเบราว์เซอร์ของคุณ — ไม่ต้องติดตั้ง
ลอง แปลง JSON เป็น CSV ออนไลน์ →เกือบทุก data pipeline มักเจอขั้นตอนเดิม: API ส่งข้อมูลมาเป็น JSON แต่ ผู้ใช้ถัดไป — ไม่ว่าจะเป็น spreadsheet, import script, หรือคำสั่ง Redshift COPY — ต้องการ CSV การแปลง JSON เป็น CSV ใน Python ฟังดูง่าย จนกว่าคุณจะเจอ nested object, คีย์ที่ไม่สม่ำเสมอ หรือค่า datetime ที่ต้องจัดการพิเศษ Python มีสองเส้นทางหลัก: โมดูล json + csv แบบ built-in สำหรับ script ที่ไม่ต้องการ dependency ภายนอก และ pandas สำหรับการ flatten ข้อมูลที่ซ้อนกันและชุดข้อมูลขนาดใหญ่ — หรือใช้ เครื่องมือแปลง JSON เป็น CSV ออนไลน์ สำหรับการแปลงครั้งเดียวโดยไม่ต้องเขียนโค้ด คู่มือนี้ครอบคลุมทั้งสองแนวทางตั้งแต่ต้นจนจบ พร้อมตัวอย่าง Python 3.8+ ที่รันได้จริง
- ✓csv.DictWriter แปลง list of dicts เป็น CSV โดยไม่มี dependency — ใช้ json.load() เพื่อ parse แล้วตามด้วย writeheader() + writerows()
- ✓เปิดไฟล์ CSV ด้วย newline="" บน Windows เสมอเพื่อป้องกันแถวว่างระหว่างแถวข้อมูล
- ✓pd.json_normalize() ทำให้ JSON ที่ซ้อนกัน flat ลงใน DataFrame ก่อนเรียก to_csv() — จัดการ nesting หลายชั้นโดยอัตโนมัติ
- ✓ส่ง index=False ไปยัง DataFrame.to_csv() — หากไม่มี pandas จะเขียนคอลัมน์หมายเลขแถวที่ไม่ต้องการ
- ✓สำหรับไฟล์ที่ใหญ่กว่า 500 MB ใช้ ijson สำหรับ streaming JSON parsing ร่วมกับ csv.DictWriter เพื่อการใช้หน่วยความจำคงที่
การแปลง JSON เป็น CSV คืออะไร?
การแปลง JSON เป็น CSV จะเปลี่ยน array ของออบเจกต์ JSON ให้อยู่ในรูปแบบตาราง โดยแต่ละออบเจกต์กลายเป็นแถวและแต่ละคีย์กลายเป็น column header JSON มีโครงสร้างเป็น hierarchy — ออบเจกต์สามารถซ้อนกันได้ลึกไม่จำกัด CSV เป็น flat — ทุกค่าอยู่ในตารางแถว-คอลัมน์ การแปลงทำงานได้ดีเมื่อทุกออบเจกต์ใช้ชุดคีย์ระดับบนสุดเดียวกัน Nested object, array และคีย์ที่ไม่สม่ำเสมอคือส่วนที่ต้องระวัง ข้อมูลดิบยังคงเหมือนเดิม เพียงแต่เปลี่ยนโครงสร้าง
[{"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 ไม่ต้องจัดการ virtual environment csv.DictWriter รับ list of dictionaries และเขียนแต่ละรายการเป็นแถว CSV โดย map คีย์ dict ไปยัง column header พารามิเตอร์ fieldnames ควบคุมทั้งลำดับคอลัมน์และคีย์ที่จะรวมไว้
import json
import csv
# ข้อมูล JSON ตัวอย่าง — array ของออบเจกต์ order
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 หากไม่มี คุณจะได้ double carriage return ซึ่งปรากฏเป็น แถวว่างระหว่างแถวข้อมูลใน Excel บน macOS และ Linux ไม่มีผลเสีย ดังนั้นควรใส่เสมอ
โค้ดด้านบนใช้ json.loads() สำหรับสตริง ใช้ json.load() (ไม่มี s ท้าย) เมื่ออ่านจาก file handle สิ่งนี้ทำให้หลายคนสับสน — ตัวหนึ่งอ่านสตริง อีกตัวอ่าน file object
import json
import csv
with open("server_metrics.json", encoding="utf-8") as jf:
metrics = json.load(jf) # json.load() สำหรับ file object
# 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" จะละทิ้งคีย์ใน dict ที่ไม่อยู่ใน fieldnames แบบเงียบ ค่าเริ่มต้นคือ "raise" ซึ่งโยน ValueError หาก dict ใดมีคีย์ที่ไม่คาดคิด เลือกตามความต้องการของคุณ
csv.DictWriter กับ csv.writer: DictWriter map คีย์ dict ไปยังตำแหน่งคอลัมน์โดยอัตโนมัติ csv.writer เขียน raw list เป็นแถว — คุณจัดการลำดับคอลัมน์เอง DictWriter เป็นตัวเลือกที่ถูกต้องเกือบเสมอ สำหรับ JSON-to-CSV เนื่องจากระเบียน JSON เป็น dictionary อยู่แล้วโมดูล csv ของ Python มาพร้อมกับ dialect ที่ตั้งชื่อไว้สามแบบ: excel (comma delimiter, CRLF line endings — ค่าเริ่มต้น), excel-tab (tab delimiter, CRLF endings) และ unix (LF line endings, ครอบฟิลด์ที่ไม่ใช่ตัวเลขทั้งหมด) ส่งชื่อ dialect เป็นอาร์กิวเมนต์ dialect ให้กับ csv.DictWriterคุณยังสามารถกำหนด custom dialect ด้วย csv.register_dialect() เมื่อระบบปลายทางมีกฎการ quote หรือ delimiter ที่ไม่ปกติ สำหรับ workflow JSON-to-CSV ส่วนใหญ่ dialect excel เหมาะสม แต่เปลี่ยนเป็น unix เมื่อเขียนไฟล์ที่จะถูกประมวลผลด้วยเครื่องมือ POSIX เช่น awk หรือ sort
การจัดการประเภทที่ไม่ใช่มาตรฐาน: datetime, UUID และ Decimal
JSON จาก API มักมีวันที่เป็น ISO string, UUID เป็น hyphenated string และ ค่าเงินเป็น float เมื่อ parse เป็น Python object เพื่อประมวลผลก่อนเขียน CSV คุณต้องแปลงกลับเป็นสตริง โมดูล csv เรียก str() กับทุกค่า ดังนั้นประเภทส่วนใหญ่ทำงานได้เลย แต่ datetime object ให้ string representation เริ่มต้นที่ไม่เป็นระเบียบ และ Decimal ต้องการการจัดรูปแบบที่ชัดเจนเพื่อหลีกเลี่ยง scientific notation
import json
import csv
from datetime import datetime, timezone
from decimal import Decimal
from uuid import UUID
# จำลอง API response ที่ parse แล้วด้วย Python types
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 เกี่ยวกับ custom type คุณทำให้แต่ละระเบียนเป็นสตริงก่อนเขียน แนะนำให้เรียก .isoformat() อย่างชัดเจนกับ datetime object แทนที่จะพึ่งพา str() — รูปแบบ output ที่ได้คาดเดาได้มากกว่า และ parser ปลายทางจัดการ ISO 8601 ได้อย่างน่าเชื่อถือ
Decimal ผ่านไปโดยไม่จัดรูปแบบ ตัวเลขที่เล็กมากหรือใหญ่มากอาจแสดงใน scientific notation (เช่น 1.5E+7) จัดรูปแบบ Decimal ด้วย f-string ที่ชัดเจนเช่น f"{value:.2f}" เสมอเมื่อเขียนข้อมูลทางการเงินลงใน CSVรูปแบบทางเลือกสำหรับ pipeline ที่มี custom type จำนวนมากคือการ extend json.JSONEncoderสร้าง subclass, override เมธอด default() เพื่อคืนค่าที่ JSON serialize ได้สำหรับแต่ละ custom type จากนั้นส่ง subclass เป็นอาร์กิวเมนต์ cls ให้กับ json.dumps()การ re-encode ผ่าน custom encoder ก่อนเขียนลงใน CSV จะทำให้ประเภททั้งหมดเป็นมาตรฐาน ในขั้นตอนเดียวโดยไม่ต้องเรียก prepare_row() ต่อแถว รูปแบบ prepare_row() ที่แสดงด้านบนเหมาะกับ script ใช้ครั้งเดียว แนวทาง JSONEncoder subclass ขยายขนาดได้ดีกว่าเมื่อ domain model เดียวกันที่มี custom type ถูกใช้ร่วมกัน ในหลาย pipeline stage หรือ microservice
อ้างอิงพารามิเตอร์ csv.DictWriter
signature ของ constructor เต็มรูปแบบคือ csv.DictWriter(f, fieldnames, restval="", extrasaction="raise", dialect="excel", **fmtparams)ส่วนใหญ่มีค่าเริ่มต้นที่เหมาะสม ตัวที่คุณจะเปลี่ยนจริงๆ คือ fieldnames, delimiter และ extrasaction
pandas — แปลง JSON เป็น CSV ด้วย DataFrame
หากคุณทำงานใน codebase ที่ใช้ pandas อยู่แล้ว หรือ JSON ของคุณมี nested object ที่ต้องการ flatten แนวทาง pandas ใช้โค้ดน้อยกว่า stdlib มาก ข้อแลกเปลี่ยน: pandas เป็น dependency ขนาด ~30 MB สำหรับ script ใช้ครั้งเดียวไม่เป็นปัญหา แต่สำหรับ Docker image ที่ deploy ไปยัง production แนวทาง stdlib ทำให้เบากว่า
import pandas as pd
# อ่าน JSON array โดยตรงเป็น DataFrame
df = pd.read_json("warehouse_inventory.json")
# เขียนเป็น CSV — index=False ป้องกันหมายเลขแถวที่สร้างอัตโนมัติ
df.to_csv("warehouse_inventory.csv", index=False)
# แค่นั้นเอง สองบรรทัด pandas อนุมานประเภทคอลัมน์โดยอัตโนมัติflag index=False เป็นหนึ่งในสิ่งที่คุณต้องค้นหาทุกครั้ง หากไม่มี pandas จะเขียน คอลัมน์ 0, 1, 2, ... เป็นคอลัมน์แรกของ CSV ไม่มีใครต้องการสิ่งนั้น
การ Flatten JSON ที่ซ้อนกันด้วย json_normalize
API response จริงๆ แทบไม่เคย flat เลย Order มีที่อยู่จัดส่ง ผู้ใช้มี preference ที่ซ้อนกัน เหตุการณ์ telemetry มี metadata ที่ซ้อนกัน pd.json_normalize() เดินผ่าน nested dictionary และทำให้ flat เป็นคอลัมน์ที่มีชื่อคั่นด้วยจุด
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 ทำให้ nested dict flat — sep ควบคุม delimiter
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แนะนำให้ใช้ขีดล่างเพราะจุดในชื่อคอลัมน์ทำให้เกิดปัญหากับการ import SQL และสูตร spreadsheet บางตัว
สำหรับ API response ที่ครอบ records array ไว้ใต้คีย์ที่ซ้อนกัน ใช้พารามิเตอร์ record_path หาก response มีลักษณะเป็น {"data": {"orders": [...]}}ส่ง record_path=["data", "orders"] เพื่อนำทางไปยัง list ที่ถูกต้อง พารามิเตอร์ meta ที่เป็น optional ช่วยให้คุณดึงฟิลด์ระดับ parent พร้อมกับ nested records — มีประโยชน์เมื่อ response มี pagination info ระดับบนสุด (หมายเลขหน้า, จำนวนทั้งหมด) ที่คุณ ต้องการเป็นคอลัมน์ในทุกแถว ด้วยกัน record_path และ meta จัดการรูปร่าง API response ซ้อนกันส่วนใหญ่ในโลกแห่งความเป็นจริงโดยไม่ต้องประมวลผลล่วงหน้าเอง
อ้างอิงพารามิเตอร์ DataFrame.to_csv()
DataFrame.to_csv() มีพารามิเตอร์มากกว่า 20 ตัว นี่คือตัวที่สำคัญสำหรับ workflow JSON-to-CSV
import pandas as pd
df = pd.read_json("telemetry_events.json")
# TSV output พร้อม encoding ที่ระบุชัดเจนและการจัดการค่าที่หายไป
df.to_csv(
"telemetry_events.tsv",
sep="\t",
index=False,
encoding="utf-8",
na_rep="NULL",
columns=["event_id", "timestamp", "source", "severity", "message"],
)
# เขียนไปยัง stdout สำหรับการ pipe ใน shell script
print(df.to_csv(index=False))
# คืนค่าเป็นสตริง (ไม่มีการเขียนไฟล์)
csv_string = df.to_csv(index=False)
print(len(csv_string), "characters")แปลง JSON เป็น CSV จากไฟล์และ API Response
สองสถานการณ์ที่พบบ่อยที่สุดในโลกแห่งความเป็นจริง: การอ่าน JSON จากไฟล์บนดิสก์และแปลง หรือดึง JSON จาก HTTP API และบันทึกผลลัพธ์เป็น CSV ในการพัฒนาคุณสามารถ ไม่จัดการ error ได้ แต่ใน production การเลือกนั้นกลายเป็นการแจ้งเตือนตีสองตอนเช้า ไฟล์อาจไม่มีอยู่ API อาจส่งคืน status code 4xx หรือ 5xx แทน JSON body ของ response อาจเป็น error object แทนที่จะเป็น array หรือ JSON อาจ truncated เนื่องจาก network timeout รูปแบบด้านล่างจัดการกรณีเหล่านี้ทั้งหมด อย่างชัดเจน บันทึก error ไปยัง stderr และส่งคืนจำนวนแถวเพื่อให้ caller ตรวจจับ output ที่มีศูนย์แถวและแจ้งเตือนได้
ไฟล์บนดิสก์ — อ่าน แปลง บันทึก
import json
import csv
import sys
def json_file_to_csv(input_path: str, output_path: str) -> int:
"""แปลงไฟล์ JSON ที่มี array ของออบเจกต์เป็น 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
# รวบรวมคีย์ที่ไม่ซ้ำกันทั้งหมดจากทุกระเบียน — จัดการ schema ที่ไม่สม่ำเสมอ
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 Response — ดึงข้อมูลและแปลง
import json
import csv
import urllib.request
import urllib.error
def api_response_to_csv(url: str, output_path: str) -> int:
"""ดึง JSON จาก REST API endpoint และเขียนเป็น 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 จาก standard library เพื่อ ให้ script ไม่ต้องพึ่งพา dependency หากคุณติดตั้ง requests ไว้แล้ว แทนที่ส่วน urllib ด้วย resp = requests.get(url, timeout=30); records = resp.json() — โค้ดการเขียน CSV ที่เหลือยังคงเหมือนเดิมการแปลง JSON เป็น CSV ผ่าน Command Line
บางครั้งคุณต้องการแค่ one-liner ใน terminal flag -c ของ Python ช่วยให้รันการแปลงอย่างรวดเร็วโดยไม่ต้องสร้างไฟล์ script สำหรับ transformation ที่ซับซ้อนกว่านี้ ให้ pipe ผ่าน jq ก่อนเพื่อ reshape ข้อมูล แล้วค่อยแปลง
# Python one-liner: อ่าน 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) " # บันทึก output ไปยังไฟล์ 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)
" "$@"# ติดตั้ง csvkit: pip install csvkit
# jq ทำการ flatten และเลือกฟิลด์ 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) เป็น binary แบบ standalone ที่ถือว่า JSON, CSV และ TSV เป็นรูปแบบระดับ first-class โดยไม่ต้องการ Python runtime flag --json2csv แปลง JSON input เป็น CSV ในการผ่านเดียว และคุณสามารถเชื่อม Miller verbs เพื่อ filter, sort หรือเปลี่ยนชื่อคอลัมน์ในคำสั่งเดียวกันก่อนเขียน output ติดตั้งผ่าน Homebrew บน macOS (brew install miller) หรือ package manager ของ Linux มีประโยชน์อย่างยิ่งใน CI pipeline ที่คุณต้องการ การแปลง JSON-to-CSV ที่รวดเร็วโดยไม่ต้องเริ่ม Python environment
ทางเลือกประสิทธิภาพสูง — pandas พร้อม pyarrow
สำหรับชุดข้อมูลในช่วงสิบล้านแถว pandas พร้อม backend pyarrow อ่านและเขียนเร็วกว่าค่าเริ่มต้นอย่างมาก C-backed Arrow engine ประมวลผลข้อมูลแบบ columnar ได้มีประสิทธิภาพกว่าโมดูล csv ของ Python ที่ทำงานแบบ row-by-row API ยังคงเหมือนเดิม — คุณแค่ตั้งพารามิเตอร์ engine
pip install pyarrow
import pandas as pd
# อ่าน JSON ด้วย pyarrow engine (การ parse ที่เร็วกว่าสำหรับไฟล์ขนาดใหญ่)
df = pd.read_json("sensor_readings.json", engine="pyarrow")
# to_csv ไม่มีพารามิเตอร์ engine แต่การดำเนินการ DataFrame
# ระหว่างการอ่านและเขียนได้ประโยชน์จาก columnar layout ของ pyarrow
df.to_csv("sensor_readings.csv", index=False)
# สำหรับการ export ขนาดใหญ่จริงๆ ลองเขียนเป็น Parquet แทน CSV
# — รูปแบบ binary ขนาดเล็กกว่า 5-10 เท่า รักษาประเภทไว้
df.to_parquet("sensor_readings.parquet", engine="pyarrow")หากคุณประมวลผล JSON มากกว่าสองสามร้อย MB และ consumer ปลายทาง ยอมรับ Parquet ให้ข้าม CSV ทั้งหมด Parquet มีขนาดเล็กกว่า รักษาประเภทคอลัมน์ไว้ และ ทั้ง Redshift และ BigQuery โหลดมันได้แบบ native CSV เป็นรูปแบบที่สูญเสียข้อมูล — ทุกค่ากลายเป็นสตริง
Output ใน Terminal พร้อม Syntax Highlighting
library rich แสดงตารางพร้อม border, alignment และสีใน terminal — มีประโยชน์สำหรับ preview การแปลงระหว่างการพัฒนาโดยไม่ต้องเปิดไฟล์ output
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)
# แสดงตารางที่เน้นสีพร้อม border ใน terminalcsv.DictWriter หรือ DataFrame.to_csv() และใช้ rich สำหรับการ preview เท่านั้นการทำงานกับไฟล์ JSON ขนาดใหญ่
json.load() อ่านไฟล์ทั้งหมดเข้าหน่วยความจำ สำหรับไฟล์ JSON ขนาด 200 MB หมายความว่า ~200 MB ของ raw text บวกกับ Python object overhead — การใช้ heap ง่ายๆ 500 MB+ สำหรับไฟล์ที่ใหญ่กว่า 100 MB ให้ stream input ด้วย ijson และเขียนแถว CSV ไปเรื่อยๆ
pip install ijson
Streaming JSON Array ไปยัง CSV ด้วย ijson
import ijson
import csv
def stream_json_to_csv(json_path: str, csv_path: str) -> int:
"""แปลง JSON array ขนาดใหญ่เป็น CSV โดยไม่โหลดทั้งหมดเข้าหน่วยความจำ"""
with open(json_path, "rb") as jf, open(csv_path, "w", newline="", encoding="utf-8") as cf:
# ijson.items yield แต่ละ element ของ top-level array ทีละตัว
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 ที่ valid หนึ่งตัวต่อบรรทัดโดยไม่มี wrapping array รูปแบบนี้พบบ่อยใน log pipeline, event stream (Kafka, Kinesis) และ bulk export จากบริการอย่าง Elasticsearch และ BigQuery เนื่องจากแต่ละบรรทัดเป็นออบเจกต์ JSON แบบ self-contained คุณสามารถ ประมวลผลไฟล์ NDJSON ด้วย Python for loop ธรรมดาที่วนซ้ำ file handle — ไม่จำเป็นต้องใช้ ijson library หน่วยความจำคงที่ โดยไม่คำนึงถึงขนาดไฟล์ ทำให้นี่เป็นแนวทาง streaming ที่ง่ายที่สุดเมื่อข้อมูล source ของคุณอยู่ในรูปแบบ 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() อาจใช้ RAM 3–5 GB เนื่องจาก Python object overhead ด้วย ijson หน่วยความจำคงที่โดยไม่คำนึงถึงขนาดไฟล์ หากคุณต้องการแปลงไฟล์เล็กๆ อย่างรวดเร็ว วางลงใน เครื่องมือแปลง JSON เป็น CSV แทนข้อผิดพลาดที่พบบ่อย
ปัญหา: โมดูล csv เขียน เป็นการสิ้นสุดบรรทัด หากไม่มี newline='' โหมด text ของ Python จะเพิ่ม อีกตัวบน Windows ทำให้ได้ output แบบ double-spaced
วิธีแก้: ส่ง 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)
# Output สะอาดบนทุกแพลตฟอร์มปัญหา: หากไม่มี index=False pandas จะเพิ่มคอลัมน์หมายเลขแถวที่เพิ่มขึ้นอัตโนมัติ (0, 1, 2, ...) ที่ทำให้ CSV มีข้อมูลที่ไม่ได้อยู่ใน JSON เดิม
วิธีแก้: ส่ง index=False ให้กับ to_csv() หากคุณต้องการคอลัมน์ index จริงๆ ให้ตั้งชื่ออย่างชัดเจนด้วย df.index.name = 'row_num'
df = pd.read_json("events.json")
df.to_csv("events.csv")
# CSV ได้คอลัมน์ที่ไม่มีชื่อเพิ่มมา: ,event_id,timestamp,...
# comma นำหน้าทำให้ CSV parser หลายตัวพังdf = pd.read_json("events.json")
df.to_csv("events.csv", index=False)
# CSV สะอาด: event_id,timestamp,...ปัญหา: หากออบเจกต์ JSON มีคีย์ต่างกัน (บางระเบียนมีฟิลด์ optional) การใช้คีย์ของระเบียนแรกเป็น 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() กับ nested dict ทำให้ได้คอลัมน์ที่มีค่าเช่น "{'city': 'Portland'}"— Python repr ดิบๆ ไม่ใช่ข้อมูลจริง
วิธีแก้: ทำการ flatten nested object ก่อนโดยใช้ pd.json_normalize() หรือฟังก์ชัน flatten เอง
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 เมื่อคุณต้องการ zero dependency, JSON ของคุณ flat และ script ทำงานใน สภาพแวดล้อมที่จำกัด (CI container, Lambda function, embedded Python) ใช้ pd.json_normalize() + to_csv() เมื่อ JSON ซ้อนกัน คุณต้องการ transform หรือ filter ข้อมูลก่อน export หรือคุณ อยู่ใน pandas workflow อยู่แล้ว สำหรับไฟล์ที่ไม่พอดีกับหน่วยความจำ รวม ijson กับ csv.DictWriter สำหรับ constant-memory streaming
สำหรับการแปลงอย่างรวดเร็วโดยไม่ต้องเขียนโค้ด เครื่องมือแปลง JSON เป็น CSV บน ToolDeck จัดการได้โดยไม่ต้องตั้งค่า Python ใดๆ
คำถามที่พบบ่อย
จะแปลง JSON เป็น CSV ใน Python โดยไม่ใช้ pandas ได้อย่างไร?
ใช้โมดูล json และ csv ที่มาพร้อมกับ Python เรียก json.load() เพื่อแปลงไฟล์ JSON เป็น list of dicts จากนั้นดึง fieldnames จากคีย์ของ dict แรก สร้าง csv.DictWriter เรียก writeheader() แล้วตามด้วย writerows() วิธีนี้ไม่มี external dependencies และใช้งานได้ในทุกสภาพแวดล้อม 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 array ที่เรียบง่ายจะแมปกับแถว CSV ได้โดยตรง แต่อ็อบเจกต์ที่ซ้อนกันต้องทำการ flatten ก่อน ด้วย pandas นั้น pd.json_normalize() จัดการเรื่องนี้โดยอัตโนมัติ — โดยรวมคีย์ที่ซ้อนกันด้วยตัวคั่นจุด (เช่น "address.city") หากไม่มี pandas ให้เขียนฟังก์ชัน recursive ที่เดินผ่าน dict และต่อคีย์ด้วยตัวคั่น สำหรับโครงสร้างที่ซ้อนกันลึกหลายชั้น json_normalize จัดการได้ทั้งหมดในการเรียกครั้งเดียว พารามิเตอร์ sep ควบคุมอักขระที่ใช้เชื่อมระหว่างส่วนของคีย์ — ขีดล่างมักปลอดภัยกว่าจุดเริ่มต้นสำหรับการ import SQL และความเข้ากันได้กับสูตร spreadsheet
import pandas as pd
nested_data = [
{"id": "ord_91a3", "customer": {"name": "สมหญิง ใจดี", "email": "somying.jaidee@example.com"}},
]
df = pd.json_normalize(nested_data, sep="_")
# คอลัมน์: id, customer_name, customer_email
df.to_csv("flat_orders.csv", index=False)ทำไม CSV ของฉันถึงมีแถวว่างระหว่างแถวข้อมูลบน Windows?
โมดูล csv เขียน \r\n เป็นค่าสิ้นสุดบรรทัดตามค่าเริ่มต้น บน Windows การเปิดไฟล์ในโหมด text จะเพิ่ม \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)จะ append ระเบียน JSON ต่อท้ายไฟล์ CSV ที่มีอยู่แล้วได้อย่างไร?
เปิดไฟล์ในโหมด append ("a") และสร้าง DictWriter ด้วย fieldnames เดิม ข้าม writeheader() เนื่องจากแถว header มีอยู่แล้ว ด้วย pandas ใช้ to_csv(mode="a", header=False) ตรวจสอบให้แน่ใจว่าลำดับคอลัมน์ตรงกับไฟล์ที่มีอยู่ มิฉะนั้นข้อมูลจะลงในคอลัมน์ผิด หากไม่แน่ใจเกี่ยวกับลำดับคอลัมน์ในไฟล์ที่มีอยู่ ให้เปิดด้วย csv.DictReader ก่อนและอ่าน fieldnames จาก attribute fieldnames ของมัน ก่อนที่จะสร้าง writer สำหรับการ append
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 MB pd.read_json() ตามด้วย to_csv() เป็นวิธีที่เร็วที่สุดในการเรียกครั้งเดียว — pandas ใช้โค้ด C ที่ปรับปรุงแล้วภายใน สำหรับไฟล์ที่ใหญ่กว่า 500 MB ใช้ ijson เพื่อ stream ระเบียน JSON และเขียนลงใน CSV ด้วย csv.DictWriter ทีละแถว วิธีนี้ทำให้การใช้หน่วยความจำคงที่โดยไม่คำนึงถึงขนาดไฟล์ สำหรับไฟล์ NDJSON (หนึ่งออบเจกต์ JSON ต่อบรรทัด) ไม่จำเป็นต้องใช้ ijson เลย — for loop Python ธรรมดาที่วนซ้ำ file handle จะประมวลผลแต่ละบรรทัดแยกกันและให้หน่วยความจำคงที่โดยไม่ต้องพึ่งพา library ของ third party
# เร็วสำหรับไฟล์ที่พอดีกับหน่วยความจำ
import pandas as pd
df = pd.read_json("large_dataset.json")
df.to_csv("large_dataset.csv", index=False)
# Streaming สำหรับไฟล์ที่ไม่พอดีกับหน่วยความจำ
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 output ไปยัง stdout แทนไฟล์ใน Python ได้ไหม?
ได้ ส่ง sys.stdout เป็น file object ให้กับ csv.writer() หรือ csv.DictWriter() สิ่งนี้มีประโยชน์สำหรับการ pipe output ใน shell scripts หรือการ debug อย่างรวดเร็ว ด้วย pandas เรียก to_csv(sys.stdout, index=False) หรือ to_csv(None) เพื่อรับสตริงที่พิมพ์ได้ ไม่จำเป็นต้องมีไฟล์ชั่วคราว เมื่อเขียนไปยัง stdout บน Windows ให้เรียก sys.stdout.reconfigure(newline="") ก่อนเพื่อหลีกเลี่ยงปัญหา carriage-return ซ้ำ เนื่องจาก stdout เปิดในโหมด text ตามค่าเริ่มต้น
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.