關於爬蟲亂碼有不少羣友的各式各樣的問題,下邊簡單總結下關於網絡爬蟲的亂碼處理。注意,這裏不只是中文亂碼,還包括一些如日文、韓文 、俄文、藏文之類的亂碼處理,由於他們的解決方式 是一致的,故在此統一說明。java
網絡爬蟲,有兩種選擇,一是選擇nutch、hetriex,二是自寫爬蟲,二者在處理亂碼時,原理是一致的,但前者處理亂碼時,要看懂源碼後進行修改才能夠,因此要廢勁一些;然後者更自由方便,能夠在編碼處理時進行處理。這也是不少人在用框架寫爬蟲會出現各類各樣的亂碼時,無從下手的緣由了,像比較成熟的nutch在處理亂碼時也是比較簡單的,因此依然會出現亂碼,因此須要二次開發才能真正解決亂碼問題。web
一、網絡爬蟲出現亂碼的緣由api
源網頁編碼和爬取下來後的編碼轉換不一致。如源網頁爲gbk編碼的字節流,而咱們抓取下後程序直接使用utf-8進行編碼並輸出到存儲文件中,這必然會引發亂碼,即當源網頁編碼和抓取下來後程序直接使用處理編碼一致時,則不會出現亂碼,此時再進行統一的字符編碼也就不會出現亂碼了。注意區分源網編碼A、程序直接使用的編碼B、統一轉換字符的編碼C。數組
A、就是web page的服務器端編碼服務器
B、抓取到的數據,原始狀況爲字節數組,它是由A來編碼的,只有B=A時,才能夠保證不出現亂碼,不然當字符集不兼容時,老是會出現亂碼,此步驟每每用於測試。網絡
C、統一轉碼是指獲得網頁的原始編碼A後,再進行的統一編碼,主要是爲了將各個網頁的數據統一成一類編碼,每每選擇字符集較大的utf-8爲宜。框架
每一個網頁都有本身的編碼,像gbk、utf-八、iso8859-1,以及日文的jp系統編碼、西歐、俄文等編碼各不相同,當進行漫爬時老是會擴展出各類編碼,有的爬蟲是對web網頁進行簡單的編碼識別再進行統一編碼,有的是不作源網頁的判斷直接統一按utf-8來處理,這顯然是會形成亂碼狀況。工具
二、亂碼的解決方法測試
根據緣由來找解決方法,就很是簡單了。網站
(1) 肯定源網頁的編碼A
編碼A每每在網頁中的三個位置,http header的content、網頁的meta charset中、網頁頭中Document定義中。在獲取源網頁編碼時,依次判斷下這三部分數據便可,從前日後,優先級亦是如此。
理論上這樣作是對的,但國內一些網站確是很不符合規範,好比寫的gbk,實際是utf-8,有的是寫的utf-8,但實際是gbk,固然這是不多的一批網站,但確實存在。因此在肯定網頁編碼時,應該對該特殊狀況作特別處理,如中文檢查、默認編碼等策略。
還有一種狀況,是以上三者中均沒有編碼信息,則通常採用cpdetector等第三方網頁編碼智能識別工具來作,其原理即爲統計字節數組的特徵來機率計算得出實際編碼,有必定的準確率,但我實際的時候發現,其準確率仍是頗有限的。
但綜合上述的三種編碼確認方式後,幾乎能夠徹底解決中文亂碼問題,在我基於nutch1.6二次開發的網絡爬蟲系統中,編碼正確經統計能夠達到99.99%,也證實了上述方法策略的可行性。
(2)程序經過編碼B對源網頁數據還原
顯然,這裏的B是要和A相等的,在java中,如獲得的源網頁的字節數組爲source_byte_array,那麼通過轉換爲String str=new String(source_byte_array,B);即在內存上這些字節數組對應的字符是正確編碼和可顯示的,此時的打印輸出結果是正常的,此步驟每每用於debug或是控制檯輸出作測試。
(3) 統一轉碼
網絡爬蟲系統數據來源不少,不可能使用數據時,再轉化爲其原始的數據,假使這樣作是很廢事的。因此通常的爬蟲系統都要對抓取下來的結果進行統一編碼,從而在使用時作到一致對外,方便使用。此時便是在(2)的基礎上,作一個統一的編碼轉換便可,在java中的實現以下
源網頁的字節數組爲source_byte_array
轉換爲正常的字符串: String normal_source_str=new String(source_byte_array,C),此時能夠用java api直接存儲,但每每不直接寫入字符串,由於通常的爬蟲存儲都是多個源網頁存儲到一個文件中,因此要記錄字節偏移量,故下一步。
再將獲得的str轉換爲統一的編碼C格式的字節數組,則byte[] new_byte_array=normal_source_str.getBytes(C)便可,此時便可用java io api將數組寫入文件,並記錄相應的字節數組偏移量等,待真正使用時,直接io讀取便可。