Contents

[Python]文件儲存unicode碼的問題

用 Python 爬蟲抓取資料後,通常會將結果存成 JSON 格式。然而,Python 的 json.dumps() 預設行為會將非 ASCII 字元(包含中文、日文等)轉換成 \uXXXX 的 Unicode 跳脫序列,讓儲存的檔案難以直接閱讀。這篇文章說明問題原因與正確的解決方式。

問題重現

1
2
3
4
5
6
import json

data = {"artist": "じん"}  # 日文字
result = json.dumps(data)
print(result)
# 輸出:{"artist": "\u3058\u3093"}

雖然程式讀取時不會有問題(JSON 規範允許 \uXXXX 表示法),但存到檔案後用文字編輯器開啟,會看到一堆跳脫序列,可讀性很差。

根本原因:ensure_ascii=True

json.dumps() 有一個參數 ensure_ascii預設值為 True,這會讓所有非 ASCII 字元都被轉成 \uXXXX 格式,以確保輸出的 JSON 只包含 ASCII 字元(相容性最高)。

解決方式:ensure_ascii=False

1
2
3
4
5
6
import json

data = {"artist": "じん", "song": "人造エネミー"}
result = json.dumps(data, ensure_ascii=False)
print(result)
# 輸出:{"artist": "じん", "song": "人造エネミー"}

正確的 UTF-8 JSON 檔案讀寫

寫入 JSON 檔案

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
import json

data = [
    {"name": "王小明", "age": 25},
    {"name": "田中さん", "age": 30}
]

# 正確做法:同時設定 ensure_ascii=False 和 encoding='utf-8'
with open("output.json", "w", encoding="utf-8") as f:
    json.dump(data, f, ensure_ascii=False, indent=2)

json.dump()(不加 s)直接寫入檔案物件,json.dumps()(加 s)返回字串。

讀取 JSON 檔案

1
2
3
4
5
6
import json

with open("output.json", "r", encoding="utf-8") as f:
    data = json.load(f)

print(data[0]["name"])  # 王小明

Python 2 vs Python 3 的差異

面向 Python 2 Python 3
預設字串 bytes(str Unicode(str
Unicode 字串 需加 u 前綴:u"中文" 直接使用 "中文"
開啟檔案 需用 io.open() 指定 encoding open() 直接支援 encoding 參數
json.dumps() 同樣預設 ensure_ascii=True 同樣預設 ensure_ascii=True

Python 2 的正確寫法(已不建議使用 Python 2):

1
2
3
4
5
6
7
8
# Python 2
import json, io

data = {u"name": u"王小明"}
result = json.dumps(data, ensure_ascii=False)

with io.open("output.json", "w", encoding="utf-8") as f:
    f.write(result)

Python 3 的寫法更簡潔:

1
2
3
4
5
6
7
# Python 3(建議)
import json

data = {"name": "王小明"}

with open("output.json", "w", encoding="utf-8") as f:
    json.dump(data, f, ensure_ascii=False, indent=2)

其他格式化選項

1
2
3
4
5
6
json.dumps(data,
    ensure_ascii=False,   # 保留非 ASCII 字元
    indent=2,             # 縮排 2 格(美化輸出)
    sort_keys=True,       # 按鍵名排序
    separators=(',', ':') # 壓縮輸出(去除空格)
)

處理換行符號

爬蟲抓到的文字常含有 \n\r\t 等控制字元,存入 JSON 時會被轉義,讀出時再還原,通常不需要特別處理。若確實需要保留字面上的反斜線,可用:

1
2
text = "第一行\n第二行"
# json.dumps 後:{"text": "第一行\n第二行"}  ← \n 是跳脫序列,讀取時自動還原為換行

參考資料