對python3 而言,亂碼不叫亂碼,叫做編碼錯誤
沒錯,python3 內所有的文字都是 unicode
類型的str,對於原本是utf-8 編碼的文字,再另外編成big5 後當然會出現亂碼
一般而言透過requests 訪問網頁的程式碼如下:
1 2 3 4 5 6
| import lxml, requests
result = requests.get('http://disp.cc/'); print("encoding: %s" % result.encoding) print("content: \n%s" % result.text)
|
request
取得的網頁會自動判別網頁編碼,但為了保險起見我會自行設定
下方是自動判斷編碼時的輸出:
1 2 3 4 5 6 7 8 9 10
| encoding: utf-8 content: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>Disp BBS</title> <meta property="fb:app_id" content="111318672241067"/> <meta property="og:title" content="網頁型電子佈告欄系統 - Disp BBS"/> 下略 ....
|
另外我們來看 big5的網站會怎麼編碼,這邊用銘傳大學的課程查詢當範例
1 2 3 4 5 6
| import lxml, requests
result = requests.get('http://www.mcu.edu.tw/student/new-query/sel-query/qslist_1.asp'); print("encoding: %s" % result.encoding) print("content: \n%s" % result.text)
|
輸出:
1 2 3 4 5 6 7 8 9 10
| encoding: ISO-8859-1 content:
<html> <head> <title>¯S®í±ø¥ó¬d¸ßµ²ªG</title> <meta http-equiv="Content-Type" content="text/html; charset=big5"> <link href="cls.css" rel="stylesheet" type="text/css"> </head> 下略...
|
從輸出可以猜測 requests 的預設編碼可能是:ISO-8859-1,但是在 <meta charset>
這邊我們發現網站是用big5 編碼的,所以我們需要手動指定 requests 的編碼方式:
1 2 3 4
| result = requests.get('http://www.mcu.edu.tw/student/new-query/sel-query/qslist_1.asp'); result.encoding = 'big5' print("encoding: %s" % result.encoding) print("content: \n%s" % result.text)
|
這樣我們的輸出就會正常了:
1 2 3 4 5 6 7 8 9 10
| encoding: big5 content:
<html> <head> <title>特殊條件查詢結果</title> <meta http-equiv="Content-Type" content="text/html; charset=big5"> <link href="cls.css" rel="stylesheet" type="text/css"> </head> 下略 ...
|
但是把encoding 設成big5 仍然不是一個好的做法,你會遇到某些網站雖然已經轉成big5,但他的輸出仍是亂碼
1 2 3 4 5 6 7 8
| import lxml, requests
result = requests.post('http://www.mcu.edu.tw/student/new-query/sel-query/qslist_1.asp', data={'dept1': '02'}); result.encoding = 'big5' print("encoding: %s" % result.encoding) print("content: \n%s" % result.text)
|
輸出篇幅太長,我直接擷取有問題的輸出
1 2 3 4 5
| <td align="center"> <a href="https://tch.mcu.edu.tw/sylwebqry/pro10_22.aspx?tcls=02252&tcour=00221&tyear=&tsem=&teac=&type=1" target="_bank"> <font size="-1" color="#0080FF">正課: 李�X煌</font> </a> </td>
|
原字碼為:正課: 李鞇煌
這是因為 鞇
並非big5 的字碼,而是基於big5 而擴展的香港增補字,雖然都是big5,但是big5 有不同的種類,例如微軟cmd 的編碼為: cp950
,而基於香港增補字擴充的編碼則為: big5hkscs
可以在這網頁內查到鞇
其他相關的說明,在網頁內的 Encodings that can encode this properly
欄位內可以查到該字可支援的編碼,僅支援: utf_8 utf_16 gbk gb18030 big5hkscs
這幾種。
既然我們知道不能用big5 編碼了,那我們就要來修改一下程式:
1 2 3 4 5 6 7 8
| import lxml, requests
result = requests.post('http://www.mcu.edu.tw/student/new-query/sel-query/qslist_1.asp', data={'dept1': '02'}); result.encoding = 'big5-hkscs' print("encoding: %s" % result.encoding) print("content: \n%s" % result.text)
|
輸出就正常了:
1 2 3 4 5
| <td align="center"> <a href="https://tch.mcu.edu.tw/sylwebqry/pro10_22.aspx?tcls=02252&tcour=00221&tyear=&tsem=&teac=&type=1" target="_bank"> <font size="-1" color="#0080FF">正課: 李鞇煌</font> </a> </td>
|
結論:
網頁編碼有utf8 就用utf8
若為big5 則轉換為 big5-hkscs