爬蟲(Py2和Py3區別)
什麼是字元編碼?
計算機裡的所有資料,本質都是二進位制
二進位制 0b01100001 十進位制 97 通過 ASCII編碼表 對應字元 ‘a’
簡體中文: gb2312、gbk、gb18030, cp936 ,code page 936,一個漢字2個位元組
繁體中文: Big5
日文:Shift-jis
誕生了 Unicode編碼,包含了世界上所有國家的字元,對編碼進行了大一統。 每個字元佔用 3~6 個位元組,浪費空間。
誕生了 utf-8 可變長的Unicode,一個漢字佔3個位元組,一個字母佔1個位元組,大大了減少了空間佔用。
爬蟲程式處理編碼的場景:
- 傳送請求獲取網頁內容(不同的網頁編碼可能不一樣)
- 程式處理時產生的字串(可能會有不同編碼)
- 儲存結果需要統一編碼(寫入儲存時候的編碼)
二、Python2和Python3的 字元編碼 和 字元型別
Python3:
Unicode字串 str 型別
非Unicode字串 bytes 型別
Python2:
Unicode字串 unicode 型別
非Unicode字串 str 型別
三、編碼的轉換
任何語言、任何平臺、任何編碼的字串,都可以和Unicode互相轉換。
例 : utf8_str -> gbk_str
非Unicode字串,可以通過decode解碼為Unicode字串
unicode_str = utf8_str.decode(“utf-8”)
# Unicode字串, 可以通過 encode 編碼為其他編碼
gbk_str = unicode_str.encode(“gbk”)
反之: gbk_str -> utf8_str
unicode_str = gbk_str.decode(“gbk”)
utf8_str = unicode_str.encode(“utf-8”)
UnicodeDecodeError、UnicodeEncodeError
四、終端建立字串的編碼
在直譯器終端建立的字串
Python2:根據作業系統決定
Linux為utf-8、簡體簡體中文Windows 為 gbk。注意,如果是iPython建立的,都是 utf-8
Python3:Unicode 編碼
五、檔案編碼
寫入字串到檔案中,檔案建立成功,則檔案編碼等同於寫入的字串編碼。
如果寫入了其他編碼的字串,則檔案編碼被修改,原來的內容會變成"亂碼"。
六、處理字串寫入檔案時候的編碼。
Python不能直接寫 Unicode字串到檔案中,必須寫入 非Unicode
1. 手動轉碼處理
Python3:
# w 必須寫 Unicode, wb 寫非Unicode(gbk、utf-8、jpg、mp4)
with open("xxx.txt", "wb") as f:
f.write(unicode_str.encode("utf-8"))
Python2:
# w 寫字串, wb 寫非字串
with open("xxx.txt", "w") as f:
f.write(unicode_str.encode("utf-8"))
2. 通過 open()方法的 encoding 引數
Python3:
with open("xxx.txt", "w", encoding="utf-8") as f:
f.write(unicode_str)
Python2:
Python2的 open() 沒有 encoding,但是可以通過 codecs 模組解決
import codecs
with codecs.open("xxx.txt", "w", encoding="utf-8") as f:
f.write(unicode_str)
3. 如果強行寫入Unicode字串,且並沒有通過 1 和 2 處理,則Python直譯器編碼嘗試轉碼再寫入。
with open("xxx.txt", "w") as f:
f.write(unicode_str)
Python2 預設直譯器編碼是 ascii,在處理中文則報錯 UnicodeEncodeError 無法按 ASCII編碼處理中文字串,
解決方案,將Python2 直譯器編碼修改為 utf-8
import sys
reload(sys)
sys.setdefaultencoding("utf-8")
Python3 預設直譯器編碼是 utf-8,不會出現任何錯誤
七、程式碼檔案頭部編碼宣告
Python2 預設程式碼檔案編碼宣告是 ascii,所以程式碼中有中文部分會報錯,
解決方案,在程式碼第一行新增
#coding:utf-8
Python3 預設程式碼檔案編碼宣告是 utf-8,所以不需要修改。
八、urlencode編碼
import urllib
qeryt_str = urllib.urlencode({“wd” : “你好”})
https://www.baidu.com/s?wd=%E4%B8%AD%E5%9B%BD&pn=40
爬蟲三大池:UserAgent池、IP代理池、Cookie池
練習
第一種方法:
#coding:utf-8
import random
import urllib
import urllib2
USER_AGENT_LIST = [
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1",
"Mozilla/5.0 (X11; CrOS i686 2268.111.0) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.57 Safari/536.11",
]
def send():
# 通過random.choice隨機從列表中返回一個新的useragent
useragent = random.choice(USER_AGENT_LIST)
headers = {'User-Agent':useragent}
# 構建一個包含請求報頭的請求物件
request = urllib2.Request("http://www.baidu.com/", headers=headers)
# 傳送指定的url地址請求,返回一個類檔案的響應物件
response = urllib2.urlopen(request)
# 獲取響應的狀態碼
if response.getcode() == 200:
# 讀取響應中內容,獲取網頁原始編碼字串
html = response.read()
return html
return None
if __name__ == '__main__':
html = send_request()
with open("baidu.html", "w") as f:
f.write(html)
第二種方法:
#coding:utf-8
import random
import urllib2
USER_AGENT_LIST = [
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1",
"Mozilla/5.0 (X11; CrOS i686 2268.111.0) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.57 Safari/536.11",
]
def send_request():
# UserAgent池、IP代理池、Cookie池
# 通過random.choice隨機從列表中返回一個新的useragent
useragent = random.choice(USER_AGENT_LIST)
# 構建一個包含請求報頭的請求物件
request = urllib2.Request("http://www.baidu.com/")
# 新增/修改 指定請求報頭值
request.add_header("User-Agent", useragent)
# 獲取指定請求報頭值,注意a必須小寫
print(request.get_header("User-agent"))
# 傳送指定的url地址請求,返回一個類檔案的響應物件
response = urllib2.urlopen(request)
# 獲取響應的狀態碼
if response.getcode() == 200:
# 讀取響應中內容,獲取網頁原始編碼字串
html = response.read()
return html
return None
if __name__ == '__main__':
html = send_request()
with open("baidu.html", "w") as f:
f.write(html)
4、構建字典查詢
#coding:utf-8
import urllib
import urllib2
def send_request():
#輸入自定義查詢的關鍵字
keyword = raw_input("請輸入需要查詢的關鍵字")
# 固定的url地址
base_url = "https://www.baidu.com/s?"
# 構建查詢字典
query_dict = {"wd" : keyword, 'pn':'40'}
# 通過urlencode方法,構建查詢字串
query_str = urllib.urlencode(query_dict)
# 和固定的url地址拼接,構建完整的url地址
full_url = base_url + query_str
headers = {"User-Agent" : "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko"}
reqeust = urllib2.Request(full_url, headers=headers)
response = urllib2.urlopen(reqeust)
return response.read()
if __name__ == '__main__':
html = send_request()
with open("baidu.html", "w") as f:
f.write(html)
Python3程式碼:
#coding:utf-8
# import urllib
# import urllib2
import urllib.request
import urllib.parse
def send_request():
#輸入自定義查詢的關鍵字
keyword = input("請輸入需要查詢的關鍵字")
# 固定的url地址
base_url = "https://www.baidu.com/s?"
# 構建查詢字典
query_dict = {"wd" : keyword}
########1. 通過urlencode方法,構建查詢字串
########query_str = urllib.urlencode(query_dict)
query_str = urllib.parse.urlencode(query_dict)
# 和固定的url地址拼接,構建完整的url地址
full_url = base_url + query_str
headers = {"User-Agent" : "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko"}
######### 2. 構建請求
#reqeust = urllib2.Request(full_url, headers=headers)
reqeust = urllib.request.Request(full_url, headers=headers)
######### 3. 傳送請求,返回響應
#response = urllib2.urlopen(reqeust)
response = urllib.request.urlopen(reqeust)
return response.read()
if __name__ == '__main__':
html = send_request()
with open("baidu.html", "wb") as f:
f.write(html)