怎麼用 Python fetch 中文 JSON 資料?
Python 初心者遇到辣個 CP950 錯誤的故事
🕒 published on ー 2022. 1. 31.
🔁 last updated ー 2022. 5. 25.
Photo by Raphael Schaller on Unsplash
Free Talk
最近才剛初學 Python,面對 Python 問題還是常先以 JS 的角度去切入, 看到關鍵字 URL(網址)、讀 JSON,直覺反應:簡單,就是要用 Python 去 fetch JSON data 嘛! 直覺 Python 必有內建模組可用來解決此事,不用幾分鐘就能解決吧 w
估狗後發現,原來 Python 星球似乎無 fetch 這個說詞, stackOverflow 多數提問者都老老實實的:get JSON data from URL、get JSON from webpage、parse JSON API …。 JS 星人感受到了文化衝擊。
不過更衝擊的是,當我照著網路上的教學 & 再三確認官方文件,打好自己的程式碼後, 執行下去看到的竟是 UnicodeEncodeError: 'cp950' codec can't encode character '\u83d3' in position 76346: illegal multibyte sequence
!
CP950 錯誤?
Why…!儘管 Python 跟 JS 再怎麼不同,剛才如此小心謹慎的翻文件、查資料,API 網址也經多人確認一切正常的情況下, 不至於會寫出有 Bug 的 Code 呀?
Debug 開始
from urllib.request import urlopen
import json
def print_json_data (api_url):
with urlopen(api_url) as res:
json_data = json.loads(res.read())
print(json_data)
以上是我的 Code。根據錯誤訊息,很明顯跟編碼有關,估狗之後做了這些事:
res.read()
改為res.read().decode(encoding = 'utf-8')
,一樣 CP950 錯誤。- 承上,再改為
req.read().decode(encoding = 'utf-8', errors='ignore')
,一樣 CP950 錯誤,說好的 ignore 呢? - 查
json.load()
、json.loads()
,有何不同,我的寫法用 loads 並沒不對。 - 查 CP950 的歷史、產生錯誤的成因,可是上面第 1 點就是解法了呀!
- 忘記改了什麼,只記得有印出一堆中文亂碼,字全變成黑色菱形,有的中間還有個白色問號,小時候逛完日文網頁忘記把編碼切回中文就常看到這種中文亂碼。
- 查錯誤訊息中
\u83d3
到底是啥字?原來是和菓子的菓,不過這只是瞭解了為何網路上很多都打和果子,不打和菓子,大概就是因為會出錯才不用草字頭吧。 - 問人!
真相大白
沒錯,走投無路的時候就該問人,但得到的回答試了都還是不行,
到這步田地我開始懷疑,該不會又是因為我電腦是 windows 系統那類的吧?
靈機一動決定把對方回答我的最後一版 Code 原封不動直接複製貼上,
乖乖的在終端機輸入 python app.py
去執行…
竟然可以了?為何!明明我的 Code 也是同樣邏輯只是寫法稍有不同而已呀!我不甘心!
JS 星人激動著把 Code 換回一開始自己寫的(上面貼的那樣),再次於終端機輸入 python app.py
去執行…
完好的印出了 JSON 資料,沒任何問題,也不需寫 encoding。
WTF…JS 星人突然領悟了一切問題的根源,根源就是… 因為方便,所以我一直用 Code Runner 幫我執行程式,原來是它在搞事啊! 雲推測是 Code Runner 有東西 import 不完全或有什麼地方跟 Python 打架了之類的。 Code Runner 虧我這麼愛用你 Q
學到了:單純練語法再用 Code Runner 吧,不然還是乖乖自己用 Commad Line 執行程式為佳。 感謝被我問的大大;;
Ending
from urllib.request import urlopen
import json
def print_json_data (api_url):
with urlopen(api_url) as res:
- json_data = json.loads(res.read())
+ json_data = json.loads(res.read().decode(encoding = 'utf-8'))
print(json_data)
最後我的 code 整理如上,覺得 encoding 還是寫著較好,避免又遇到不在 CP950 裡的字。 那麼就這樣,真的是每日犯蠢 (1/n) 捏。