日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > python >内容正文

python

[Python爬虫] 中文编码问题:raw_input输入、文件读取、变量比较等str、unicode、utf-8转换问题

發(fā)布時(shí)間:2024/5/28 python 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [Python爬虫] 中文编码问题:raw_input输入、文件读取、变量比较等str、unicode、utf-8转换问题 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
? ? ? ? 最近研究搜索引擎、知識(shí)圖譜和Python爬蟲比較多,中文亂碼問(wèn)題再次浮現(xiàn)于眼前。雖然市面上講述中文編碼問(wèn)題的文章數(shù)不勝數(shù),同時(shí)以前我也講述過(guò)PHP處理數(shù)據(jù)庫(kù)服務(wù)器中文亂碼問(wèn)題,但是此處還是準(zhǔn)備簡(jiǎn)單做下筆記。方便以后查閱和大家學(xué)習(xí)。
? ? ? ? 中文編碼問(wèn)題的處理核心都是——保證所有的編碼方式一致即可,包括編譯器、數(shù)據(jù)庫(kù)、瀏覽器編碼方式等,而Python通常的處理流程是將unicode作為中間轉(zhuǎn)換碼進(jìn)行過(guò)渡。先將待處理字符串用unicode函數(shù)以正確的編碼轉(zhuǎn)換為Unicode碼,在程序中統(tǒng)一用Unicode字符串進(jìn)行操作;最后輸出時(shí),使用encode方法,將Unicode再轉(zhuǎn)換為所需的編碼即可,同時(shí)保證編輯器服務(wù)器編碼方式一致。
? ? ? ?
PS:當(dāng)然Python3除外!這篇文章比較啰嗦,畢竟是在線筆記和體會(huì)嘛,望理解~
? ? ? ? 在詳細(xì)講解概念之前,先講述我最近遇到的字符編碼的兩個(gè)問(wèn)題及解決。下圖是最常見(jiàn)到幾個(gè)問(wèn)題編碼問(wèn)題:

參考資料:
? ? ? ??詳解 python 中文編碼與處理
? ? ? ??python字符編碼與解碼unicode、str和中文 'ascii' codec can't decode
? ? ? ??Python的中文編碼問(wèn)題-segmentfault
? ? ? ? 書籍《Python核心編程(第二版)》和《Python基礎(chǔ)教程(第二版)》

一. raw_input輸入str轉(zhuǎn)換unicode處理

? ? ? ? 背景:在做Python定向圖片爬蟲時(shí),會(huì)通過(guò)raw_input輸入關(guān)鍵詞如“主播”,會(huì)爬取標(biāo)題title中包含"主播"的URL,再去到具體的頁(yè)面爬取圖集。
? ? ? ? 問(wèn)題:如果是自定義字符串直接通過(guò): s=u'主播'?定義為Unicode編碼,再與同樣為Unicode編碼的title.text(下一篇文章詳細(xì)介紹該爬蟲)比較即可。但是如果需要raw_input輸入呢?而且在通過(guò)unicodedecode轉(zhuǎn)換過(guò)程中總是報(bào)錯(cuò),為什么呢?
? ? ? ? 主要問(wèn)題是如何將str轉(zhuǎn)換為unicode編碼(How to convert str to unicode),默認(rèn)python編碼方式ascii碼。
? ? ? ? unicode(string[, encoding[, errors]])

>>> help(unicode) Help on class unicode in module __builtin__:class unicode(basestring)| unicode(object='') -> unicode object| unicode(string[, encoding[, errors]]) -> unicode object| | Create a new Unicode object from the given encoded string.| encoding defaults to the current default string encoding.| errors can be 'strict', 'replace' or 'ignore' and defaults to 'strict'. ? ? ? ? 舉個(gè)簡(jiǎn)單的例子:需要判斷搜索詞key是否在title標(biāo)題中。
# coding=utf-8 import sysdef getTitle(key,url):#title = driver.find_element_by_xpath()title = u'著名女主播Miss與杰倫直播LOL'print key,type(key)print title,type(title)if key in title:print 'YES'else:print 'NO'key = raw_input("Please input a key: ") print key,type(key) url = 'http://www.baidu.com/' getTitle(key,url)

? ? ? ? 輸出如下圖所示:


? ? ? ? 嘗試修改的方法包括:通過(guò)unicode(key,'utf-8')轉(zhuǎn)碼、key.decode('utf-8')轉(zhuǎn)碼、重置sys.defaultencoding都不行。而通過(guò)key.decode('raw_unicode_escape')轉(zhuǎn)換得到的亂碼"?÷2¥"(主播)。而同學(xué)的Python2.7能將str轉(zhuǎn)換成unicode編碼。
? ? ? ? "UnicodeDecodeError: 'ascii' codec can't decode byte"?需先將str轉(zhuǎn)換為unicode編碼,但是我s.decode('utf-8')就報(bào)錯(cuò) "UnicodeDecodeError: 'utf8' codec can't decode byte"。
s = '主播' s.decode('utf-8').encode('gb18030') ? ? ? ? 最后解決方法從stackoverflow得到,一方面說(shuō)明自己確實(shí)研究得不是很深,另一方面那個(gè)論壇確實(shí)更強(qiáng)大。參考:
? ? ? ??python raw-input odd behavior with accents containing strings
? ? ? ? 它是將終端的輸入編碼通過(guò)decode轉(zhuǎn)換成unicode編碼
? ? ? ??
key = raw_input("Please input a key: ").decode(sys.stdin.encoding)



二. 讀取中文文件亂碼處理

? ? ? ? 此時(shí)你的爬蟲僅僅是能從raw_input中輸入進(jìn)行處理或者定義unicode的字符串進(jìn)行定向爬取,但是如果關(guān)鍵詞很多就需要通過(guò)讀取文件來(lái)實(shí)現(xiàn)。如下圖所示,是我"Python爬取百度InfoBox"這篇文章。同樣,你會(huì)遇到各種中文亂碼問(wèn)題需要處理。

? ? ? ? 舉個(gè)簡(jiǎn)單例子:通過(guò)Selenium爬取百度百科Summary第一段。

# coding=utf-8 import sys import os import urllib import time from selenium import webdriver from selenium.webdriver.common.keys import Keys import selenium.webdriver.support.ui as ui from selenium.webdriver.common.action_chains import ActionChains #driver = webdriver.PhantomJS(executable_path="G:\phantomjs-1.9.1-windows\phantomjs.exe") driver = webdriver.Firefox() wait = ui.WebDriverWait(driver,10)def getTitle(line,info):print 'Fun: ' + line,type(line)driver.get("http://baike.baidu.com/")elem_inp = driver.find_element_by_xpath("//form[@id='searchForm']/input") elem_inp.send_keys(line) elem_inp.send_keys(Keys.RETURN)elem_value = driver.find_element_by_xpath("//div[@class='lemma-summary']/div[1]").textprint 'Summary ',type(elem_value)print elem_value,'\n'info.write(line.encode('utf-8')+'\n'+elem_value.encode('utf-8')+'\n')time.sleep(5) def main():source = open("E:\\Baidu.txt",'r')info = open("E:\\BaiduSpider.txt",'w')for line in source:line = line.rstrip('\n')print 'Main: ' + line,type(line)line = unicode(line,"utf-8")getTitle(line,info)else:info.close()main() ? ? ? ? 其中TXT通常默認(rèn)為ANSI編碼,代碼步驟:
? ? ? ? 1.我先把Baidu.txt修改為utf-8編碼,同時(shí)讀入通過(guò)unicode(line,'utf-8')將str轉(zhuǎn)換為unicode編碼;
? ? ? ? 2.Selenium先通過(guò)打開(kāi)百度百科,在輸入關(guān)鍵詞"北京故宮"進(jìn)行搜索,通過(guò)find_element_by_xpath爬取"故宮"的summary第一段內(nèi)容,而且編碼方式為unicode;
? ? ? ? 3.最后文件寫操作,通過(guò)line.encode('utf-8')將unicode轉(zhuǎn)換成utf-8,否則會(huì)報(bào)錯(cuò)UnicodeDecodeError: 'ascii'。
? ? ? ? 總之過(guò)程滿足:編碼=》Unicode=》處理=》utf-8或gbk
?
? ? ? ? 由于創(chuàng)建txt文件時(shí)默認(rèn)是ascii格式,而文字為'utf-8'格式時(shí)會(huì)報(bào)錯(cuò)。當(dāng)然你也可以通過(guò)CODECS方法創(chuàng)建制定格式文件。
? ? ? ? codes是COder/DECoder的首字母組合。它定義了文本跟二進(jìn)制值的轉(zhuǎn)換方式,跟ASCII那種用一個(gè)字節(jié)把字符轉(zhuǎn)換成數(shù)字的方式不同,Unicode用的是多字節(jié)。這也導(dǎo)致了Unicode支持多種不同的編碼方式。codes支持的四種編碼方式包括:ASCII、ISO 8859-1/Latin-1、UTF-8和UTF-16。
import codecs #用codecs提供的open方法來(lái)指定打開(kāi)的文件的語(yǔ)言編碼,它會(huì)在讀取的時(shí)候自動(dòng)轉(zhuǎn)換為內(nèi)部unicode info = codecs.open(baiduFile,'w','utf-8') #該方法不是io故換行是'\r\n' info.writelines(key.text+":"+elem_dic[key].text+'\r\n')


三. Unicode詳解

? ? ? ?PS: 該部分主要參考書籍《Python核心編程(第二版)》作者Wesley J.Chun
? ? ? ?什么是Unicode?
? ? ? ?Unicode字符串聲明通過(guò)字母"u",它用來(lái)將標(biāo)準(zhǔn)字符串或者是包含Unicode字符的字符串轉(zhuǎn)換成完全的Unicode字符串對(duì)象。Python1.6起引進(jìn)Unicode字符串支持,是用來(lái)在多種雙字節(jié)字符的格式、編碼進(jìn)行轉(zhuǎn)換的。
? ? ? ? Unicode是計(jì)算機(jī)支持這個(gè)星球上多種語(yǔ)言的秘密武器。在Unicode之前,用的都是ASCII碼,每個(gè)英文字符都是以7位二進(jìn)制數(shù)的方式存儲(chǔ)在計(jì)算機(jī)內(nèi),其范圍是32~126。當(dāng)用戶在文件中鍵入A時(shí),計(jì)算機(jī)會(huì)把A的ASCII碼值65寫入磁盤,然后當(dāng)計(jì)算機(jī)讀取該文件時(shí),它會(huì)首先把65轉(zhuǎn)換成字符A再顯示到屏幕上。
? ? ? ? 但是它的缺點(diǎn)也很明顯:對(duì)于成千上萬(wàn)的字符來(lái)說(shuō),ASCII實(shí)在太少。而Unicode通過(guò)使用一個(gè)或多個(gè)字節(jié)來(lái)表示一個(gè)字符的方法,可以表示超過(guò)90,000個(gè)字符。

>>> s1 = "中文" >>> s1 '\xd6\xd0\xce\xc4' >>> print s1,type(s1) 中文 <type 'str'>>>> s2 = u"中文" >>> s2 u'\xd6\xd0\xce\xc4' >>> print s2,type(s2) ?D?? <type 'unicode'> >>> ? ? ? ?前面添加'u'聲明為Unicode字符串,但它實(shí)際的編碼并沒(méi)有改變。
? ? ? ?編碼轉(zhuǎn)碼
? ? ? ?Unicode支持多種編碼格式,這為程序員帶來(lái)了額外的負(fù)擔(dān),每當(dāng)你向一個(gè)文件寫入字符串的時(shí)候,你必須定義一個(gè)編碼(encoding參數(shù))用于把對(duì)應(yīng)的Unicode內(nèi)容轉(zhuǎn)換成你定義的格式,通過(guò)encode()函數(shù)實(shí)現(xiàn);相應(yīng)地,當(dāng)我們從這個(gè)文件讀取數(shù)據(jù)時(shí),必須"解碼"該文件,使之成為相應(yīng)的Unicode字符串對(duì)象。
? ? ? ? str1.decode('gb2312') 解碼表示將gb2312編碼字符串轉(zhuǎn)換成unicode編碼
? ? ? ? str2.encode('gb2312') 編碼表示將unicode編碼的字符串轉(zhuǎn)換成gb2312編碼

>>> s = '中文' >>> s '\xd6\xd0\xce\xc4' >>> print s,type(s) 中文 <type 'str'> >>> s.decode('gb2312') u'\u4e2d\u6587' >>> print s.decode('gb2312'),type(s.decode('gb2312')) 中文 <type 'unicode'>>>> len(s) 4 >>> len(s.decode('gb2312')) 2>>> t = u'中文' >>> t u'\xd6\xd0\xce\xc4' >>> len(t) 4 >>> print t,type(t) ?D?? <type 'unicode'> >>> ? ? ? ? 前綴'u'表示字符串是一個(gè)Unicode串,僅僅是一個(gè)聲明。
? ? ? ? Unicode實(shí)際應(yīng)用
? ? ? ? 1.程序中出現(xiàn)字符串時(shí)一定要加個(gè)前綴u
? ? ? ?
2.不要用str()函數(shù),而是用unicode()代替
? ? ? ? 3.不要用過(guò)時(shí)的string模塊——如果給它的是非ASCII字符,它會(huì)把一切搞砸
? ? ? ? 4.不到必要時(shí)不要再程序里面編解碼Unicode字符。只在你要寫入文件或數(shù)據(jù)庫(kù)或網(wǎng)絡(luò)時(shí),才調(diào)用encode()函數(shù);相應(yīng)地,只在需要把數(shù)據(jù)讀回來(lái)時(shí)才調(diào)用decode()函數(shù)
? ? ? ? 5.由于pickle模塊只支持ASCII字符串,盡量避免基于文本的pickle操作
? ? ? ? 6.假設(shè)構(gòu)建一個(gè)用數(shù)據(jù)庫(kù)來(lái)讀寫Unicode數(shù)據(jù)的Web應(yīng)用,必須保持以下對(duì)Unicode的支持
? ? ? ? ? ?
· 數(shù)據(jù)庫(kù)服務(wù)器(MySQL、PostgreSQL、SQL Server等)
? ? ? ? ? ?· 數(shù)據(jù)庫(kù)適配器(MySQLLdb等)
? ? ? ? ? ?· Web開(kāi)發(fā)框架(mod_python、cgi、Zope、Django等)

? ? ? ? 數(shù)據(jù)庫(kù)方面確保每張表都用UTF-8編碼,適配器如果不支持Unicode如MySQLdb,則必須在connect()方法里面用一個(gè)特殊的關(guān)鍵字use_unicode來(lái)確保得到的查詢結(jié)果是Unicode字符串。mod_python開(kāi)啟對(duì)Unicode的支持即可,只要在request對(duì)象里面把text-encoding設(shè)為“utf-8”就OK了。同時(shí)瀏覽器也注意下。
? ? ? ? 總結(jié):使用應(yīng)用程序完全支持Unicode,兼容其他的語(yǔ)言本身就是一個(gè)工程。它需要詳細(xì)的考慮、計(jì)劃。所有涉及的軟件、系統(tǒng)都需要檢查,包括Python的標(biāo)準(zhǔn)庫(kù)和其他要用到的第三方擴(kuò)展模塊。你甚至需要組件一個(gè)經(jīng)驗(yàn)豐富的團(tuán)隊(duì)來(lái)專門負(fù)責(zé)國(guó)家化(I18N)問(wèn)題。


四. 常用處理方法總結(jié)

? ? ? ? 源自:http://xianglong.me/article/learn-python-1-chinese-encoding/
? ? ? ? 結(jié)合我遇到的兩個(gè)問(wèn)題,歸納了以下幾點(diǎn)。常見(jiàn)中文編碼問(wèn)題解決方法包括:

? ? ? ??1.遵循PEP0263原則,聲明編碼格式
? ? ? ??在PEP 0263--Defining Python Source Code Encodings中提出了對(duì)Python編碼問(wèn)題的最基本的解決方法:在Python源碼文件中聲明編碼格式,最常見(jiàn)的聲明方式:

#!/usr/bin/python # -*- coding: <encoding name> -*- ? ? ? ? 根據(jù)這個(gè)聲明,Python會(huì)嘗試將文件中的字符編碼轉(zhuǎn)為encoding編碼,它可以是任意一種Python支持的格式,一般都會(huì)使用utf-8\gbk的編碼格式。并且它盡可能的將指定地編碼直接寫成Unicode文本。?
? ? ? ? 注意,coding:encoding只是告訴Python文件使用了encoding格式的編碼,但是編輯器可能會(huì)以自己的方式存儲(chǔ).py文件,因此最后文件保存的時(shí)候還需要編碼中選指定的ecoding才行。?

? ? ? ? 2.字符串變量賦值時(shí)添加前綴u,使用 u'中文' 替代 '中文'
str1 = '中文' str2 = u'中文' ? ? ? ? Python中有以上兩種聲明字符串變量的方式,它們的主要區(qū)別是編碼格式的不同,其中tr1的編碼格式和Python文件聲明的編碼格式一致,而str2的編碼格式則是Unicode。
? ? ? ? 如果你要聲明的字符串變量中存在非ASCII的字符,那么最好使用str2的聲明格式,這樣你就可以
不需要執(zhí)行decode,直接對(duì)字符串進(jìn)行操作,可以避免一些出現(xiàn)異常的情況。

? ? ? ? 3.重置默認(rèn)編碼
? ? ? ? Python中出現(xiàn)這么多編碼問(wèn)題的根本原因是Python 2.x的默認(rèn)編碼格式是ASCII,所以你也可以通過(guò)以下的方式修改默認(rèn)的編碼格式:sys.getdefaultencoding()默認(rèn)是'ascii'編碼。?
#設(shè)置編碼utf-8 import sys reload(sys) sys.setdefaultencoding('utf-8') #顯示當(dāng)前默認(rèn)編碼方式 print sys.getdefaultencoding() ? ? ? ?這種方法是可以解決部分編碼問(wèn)題,但是同時(shí)也會(huì)引入很多其他問(wèn)題,得不償失,不建議使用這種方式。
? ? ? ?其原理: 首先, 這個(gè)就是Python語(yǔ)言本身的問(wèn)題。因?yàn)樵赑ython 2.x的語(yǔ)法中, 默認(rèn)的str并不是真正意義上我們理解的字符串, 而是一個(gè)byte數(shù)組, 或者可以理解成一個(gè)純ascii碼字符組成的字符串, 與Python 3中的bytes類型的變量對(duì)應(yīng); 而真正意義上通用的字符串則是unicode類型的變量, 它則與Python 3中的str變量對(duì)應(yīng)。本來(lái)應(yīng)該用作byte數(shù)組的類型, 卻被用來(lái)做字符串用, 這種看似奇葩的設(shè)定是Python 2一直被人詬病的東西, 不過(guò)也沒(méi)有辦法, 為了與之前的程序保持兼容.。
? ? ? ?在Python 2中作為兩種字符串類型, str與unicode之間就需要各種轉(zhuǎn)換的方式。首先是一種顯式轉(zhuǎn)換的方式, 就是encode和decode兩種方法。在這里這兩貨的意思很容易被搞反, 科學(xué)的調(diào)用方式是:?
? ? ? ?str --- decode方法 ---> unicode?
? ? ? ?unicode --- encode方法 ---> str?

? ? ? ?4.
終極原則:decode early, unicode everywhere, encode late
? ? ? ?Decode early:盡早decode, 將文件中的內(nèi)容轉(zhuǎn)化成unicode再進(jìn)行下一步處理?
? ? ? ?Unicode everywhere:程序內(nèi)部處理都用unicode,比如字符串拼接、替換、比較等操作 ??
? ? ? ?Encode late:最后encode回所需的encoding, 例如把最終結(jié)果寫進(jìn)結(jié)果文件?

? ? ? ?按照這個(gè)原則處理Python的字符串,基本上可以解決所有的編碼問(wèn)題(只要你的代碼和Python環(huán)境沒(méi)有問(wèn)題)。前面講述的兩個(gè)問(wèn)題解決實(shí)質(zhì)也是這樣,只是有些取巧即可。

? ? ? ?5.使用decode().encode()方法
? ? ? ?網(wǎng)頁(yè)采集時(shí),代碼指定#coding:utf-8,如果網(wǎng)頁(yè)的編碼為gbk需要這樣處理:
? ? ? ?html = html.decode('gbk').encode('utf-8')

? ? ? ?6.輸入變量raw_input中文編碼
? ? ? ?將終端的輸入編碼str通過(guò)decode轉(zhuǎn)換成unicode編碼,再使用unicode處理:
? ? ? ?key = raw_input("Please input a key: ").decode(sys.stdin.encoding)

? ? ? ?7.文件讀寫操作
? ? ? ?由于默認(rèn)的txt文件為ANSI編碼,讀取時(shí)通過(guò)unicode轉(zhuǎn)碼,經(jīng)過(guò)“ 編碼=》Unicode=》處理=》utf-8或gbk ?”順序即可。同時(shí)文件輸出時(shí)encode('utf-8')轉(zhuǎn)換txt為UTF-8格式。 終極代碼:
? ? ? ?info = codecs.open(baiduFile,'w','utf-8')


? ? ? ??8.升級(jí)Python 2.x到3.x
? ? ? ? 最后一個(gè)方法:升級(jí)Python 2.x,使用Python 3.x版本。這樣說(shuō)主要是為了吐槽Python 2.x的編碼設(shè)計(jì)問(wèn)題。當(dāng)然,升級(jí)到Python 3.x肯定可以解決大部分因?yàn)榫幋a產(chǎn)生的異常問(wèn)題。畢竟Python 3.x版本對(duì)字符串這部分還是做了相當(dāng)大的改進(jìn)的。
? ? ? ? 在Python 3.0之后的版本中,所有的字符串都是使用Unicode編碼的字符串序列,同時(shí)還有以下幾個(gè)改進(jìn):
? ? ? ? · 默認(rèn)編碼格式改為unicode
? ? ? ? ·?所有的Python內(nèi)置模塊都支持unicode
? ? ? ? · 不再支持u'中文'的語(yǔ)法格式

? ? ? ? 所以,對(duì)于Python 3.x來(lái)說(shuō),編碼問(wèn)題已經(jīng)不再是個(gè)大的問(wèn)題,基本上很少遇到上述的幾個(gè)異常。

總結(jié)

? ? ? ? 最后希望文章對(duì)你有所幫助,尤其是你剛好遇到這個(gè)問(wèn)題的,由于是結(jié)合最近做的東西,所以文章比較雜亂,但如果你剛好需要,確實(shí)能解決你的問(wèn)題的。
? ? ? ??紀(jì)伯倫曾說(shuō)過(guò):“你無(wú)法同時(shí)擁有青春和關(guān)于青春的知識(shí);因?yàn)榍啻好τ谏?jì),沒(méi)有余暇去求知;而知識(shí)忙于尋求自我,無(wú)法享受生活。”
? ? ? ? 同樣現(xiàn)在找工作的我,無(wú)法在擁有扎實(shí)基礎(chǔ)知識(shí)的同時(shí)又兼顧深度的項(xiàng)目理解,但我更傾向于分享知識(shí),因?yàn)樗褪菍で笞晕?#xff0c;就是享受生活,就是編程之樂(lè)~

? ? ? ? (By:Eastmount 2015-10-1 晚上11點(diǎn)?http://blog.csdn.net/eastmount/


總結(jié)

以上是生活随笔為你收集整理的[Python爬虫] 中文编码问题:raw_input输入、文件读取、变量比较等str、unicode、utf-8转换问题的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。