1. 程式人生 > >爬蟲入門講解(用urllib庫爬取資料 )

爬蟲入門講解(用urllib庫爬取資料 )

首先介紹說明什麼是爬蟲?

是一種按照一定的規則,自動地抓取網際網路資訊的程式或者指令碼。 
所謂網頁抓取,就是把URL地址中指定的網路資源從網路流中讀取出來,儲存到本地。 在
Python中有很多庫可以用來抓取網頁 

爬蟲分類 

通用爬蟲(General Purpose Web Crawler)、 聚焦爬蟲(Focused Web Crawler)、增量
式爬蟲(Incremental Web Crawler)、深層爬蟲(Deep Web Crawler) 

通用網路爬蟲 
捜索引擎抓取系統(Baidu、Google、Yahoo 等)的重要組成部分。主要目的是將互聯
網上的網頁下載到本地,形成一個網際網路內容的映象備份。 

聚焦爬蟲 
是"面向特定主題需求"的一種網路爬蟲程式,它與通用搜索引擎爬蟲的區別在於: 聚焦
爬蟲在實施網頁抓取時會對內容進行處理篩選,儘量保證只抓取與需求相關的網頁資訊。
 增量式抓取 
是指在具有一定量規模的網路頁面集合的基礎上,採用更新資料的方式選取已有集合中的過時網頁進行抓取,以保證所抓取到的資料與真實網路資料足夠接近。進行增量式抓取的前提是,系統已經抓取了足夠數量的網路頁面,並具有這些頁面被抓取的時間資訊。  

深度爬蟲 
針對起始url地址進行資料採集,在響應資料中進行資料篩選得到需要進行資料採集的下一波url地址,並將url地址新增到資料採集佇列中進行二次爬取..以此類推,一致到所有頁面的資料全部採集完成即可完成深度資料採集,這裡的深度指的就是url地址的檢索深度。

爬蟲步驟 
網頁抓取,資料提取,資料儲存 

HTTP協議 
HTTP,HyperText Transfer Protocol,是網際網路上應用最為廣泛的一種網路協議。 
是一個基於TCP/IP通訊協議來傳遞資料,一個屬於應用層的協議 
瀏覽器作為HTTP客戶端通過URL向HTTP服務端即WEB伺服器傳送所有請求。Web服
務器根據接收到的請求後,向客戶端傳送響應資訊。 
HTTPS(Hypertext Transfer Protocol over Secure Socket Layer)HTTP的安全版,在
HTTP下加入SSL層。 
SSL(Secure Sockets Layer 安全套接層)主要用於Web的安全傳輸協議,在傳輸層對網
絡連線進行加密,保障在Internet上資料傳輸的安全。 

HTTP 的埠號為 80, 
HTTPS 的埠號為 443 。

urlib的使用 

在Python3.x中,我們可以使用urlib這個元件抓取網頁,urllib是一個URL處理包,這個
包中集合了一些處理URL的模組 
1.urllib.request模組是用來開啟和讀取URLs的; 
2.urllib.error模組包含一些有urllib.request產生的錯誤,可以使用try進行捕捉處理; 
3.urllib.parse模組包含了一些解析URLs的方法; 
4.urllib.robotparser模組用來解析robots.txt文字檔案.它提供了一個單獨的RobotFileP
arser類,通過該類提供的can_fetch()方法測試爬蟲是否可以下載一個頁面。 

urllib.request.urlopen() 

這個介面函式就可以很輕鬆的開啟一個網站,讀取並列印資訊。 
from urllib import request 
 
if __name__ == "__main__": 
    response = request.urlopen("http://fanyi.baidu.com") 
    html = response.read() 
print(html) 
說明 
request.urlopen()開啟和讀取URLs資訊,返回物件response 

自動獲取網頁編碼

chardet 
第三方庫,用來判斷編碼的模組 
使用chardet.detect()方法,判斷網頁的編碼方式 
安裝方法: 
pip install chardet 
程式碼: 
from urllib import request 
import chardet 
if __name__ == "__main__": 
    response = request.urlopen("http://fanyi.baidu.com/") 
    html = response.read() 
    charset = chardet.detect(html) 
    print(charset) 

Request物件 

反爬蟲機制: 
1、 封殺爬蟲程式 
2、 封殺指定IP 
3、 封殺非人操作的程式 

如果需要執行更復雜的操作,比如增加 HTTP 報頭,必須建立一個 Request 例項來作為
urlopen()的引數;而需要訪問的 url 地址則作為 Request 例項的引數。 
from urllib import request 
 
if __name__ == "__main__":     req = request.Request("http://fanyi.baidu.com/")    

response = request.urlopen(req) 

 html = response.read()    

html = html.decode("utf-8") print(html) 

User Agent 
瀏覽器就是網際網路世界上公認被允許的身份,如果我們希望我們的爬蟲程式更像一個真
實使用者,那我們第一步,就是需要偽裝成一個被公認的瀏覽器。用不同的瀏覽器在傳送
請求的時候,會有不同的 User-Agent 頭。中文名為使用者代理,簡稱UA 
User Agent存放於Headers中 
伺服器就是通過檢視Headers中的User Agent來判斷是誰在訪問。 
urllib中預設的User Agent,會有Python的字樣,如果伺服器檢查User Agent,可以拒
絕Python程式訪問網站。 

設定User Agent 
方法 1:在建立 Request 物件的時候,填入 headers 引數(包含 User Agent 資訊),這個
Headers引數要求為字典; 
方法2:在建立Request物件的時候不新增headers引數,在建立完成之後,使用add_h
eader()的方法,新增headers。 

from urllib import request

if __name__ == "__main__":
    url = 'http://www.csdn.net/'
    head = {}  # 寫入 User Agent 資訊
    head['User-Agent'] = 'Mozilla/5.0 (Linux; Android 4.1.1; Nexus 7 Build/JRO03D) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166  Safari/535.19'
    #建立 Request 物件
    req = request.Request(url, headers=head)
    # 也可以通過呼叫Request.add_header()新增/修改一個特定的 header
    req.add_header("User-Agent", "Mozilla/5.0 (Linux; Android 4.1.1; Nexus 7 Build/JRO03D) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166  Safari/535.19")
    req.add_header("Connection", "keep-alive")
    # 也可以通過呼叫 Request.get_header()來檢視 header 資訊
    print(req.get_header(header_name="Connection"))
    print(req.get_header(header_name="User-Agent"))
    # #傳入建立好的 Request 物件
    response = request.urlopen(req)
    # #讀取響應資訊並解碼
    html = response.read().decode('utf-8')
    # #列印資訊
    print(html)

IP代理 
直接訪問網站 
python

代理分類 
代理可以分為三種,即高度匿名代理、普通匿名代理和透明代理。 
高度匿名代理 隱藏客戶的真實IP,但是不改變客戶機的請求,就像有個真正的客戶瀏覽器
在訪問伺服器。 
普通匿名代理 能隱藏客戶機的真實 IP,會改變客戶的請求資訊,伺服器端不知道你的 ip
地址但有可能認為我們使用了代理。 
透明代理 不但改變了我們的請求資訊,還會傳送真實的IP地址。 
 
爬蟲程式執行速度是很快,在網站爬取資料時,一個固定IP的訪問頻率就會很高,這不符合
人為操作的標準。所以一些網站會設定一個IP訪問頻率的閾值,如果一個IP訪問頻率超過
這個閾值,說明這個不是人在訪問,而是一個爬蟲程式。 
解決辦法一:設定延時 
解決辦法二:使用 IP 代理。可以設定一些代理伺服器,每隔一段時間換一個代理,就算 IP
被禁止,依然可以換個IP繼續爬取。 
免費短期代理網站舉例: 
西刺免費代理IP   http://www.xicidaili.com/ 
快代理免費代理   http://www.kuaidaili.com/free/inha/ 
聚合資料 https://www.juhe.cn/docs/api/id/62 
代理IP選取 
西刺網站為例,選出訊號好的IP 

使用代理的步驟: 
 (1)呼叫urlib.request.ProxyHandler(),構建處理器物件,proxies引數為一個字典。 
 
   (2)建立Opener物件 
 
 (3)安裝Opener 
 
使用 install_opener 方法之後,會將程式預設的 urlopen 方法替換掉。也就是說,如果使
用install_opener之後,在該檔案中,再次呼叫urlopen會使用自己建立好的opener。 

url編碼解碼 
urllib.parse.urlencode()函式幫我們將key:value這樣的鍵值對轉換成"key=value"這樣的
的字串,解碼工作可以使用urllib的unquote()函式。 
from urllib import parse word = {"title" : "天貓商城"} url1 = parse.urlencode(word) print(url1) url2 =parse.unquote(url1) print(url2) 

GET請求 
GET 請求一般用於向伺服器獲取資料 
案例:百度搜索端午節 

在其中可以看到在請求部分裡,http://www.baidu.com/s? 之後出現一個長長的字串,
其中就包含我們要查詢的關鍵詞,於是我們可以嘗試用預設的 Get 方式來發送請求。 

POST請求 
urlopen的data引數,是POST方法進行Request請求時,要傳送給伺服器的資料,字典
型別,裡面要匹配鍵值對。 
如果沒有設定urlopen()函式的data引數,HTTP請求採用GET方式 
使用urllib.parse.urlencode()函式將傳送的表單資料編碼 

Cookie 
HTTP是無狀態的面向連線的協議, 為了保持連線狀態, 引入了Cookie機制, 在瀏覽器中存
儲使用者資訊 
應用:Cookie模擬登陸 
# 獲取一個有登入資訊的 Cookie 模擬登陸 from urllib import request import chardet 
 
# 1. 構建一個已經登入過的使用者的 headers 資訊

headers = {     "User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36",    

"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",    

# 便於終端閱讀,表示不支援壓縮檔案    

# Accept-Encoding: gzip, deflate, sdch,  

"Accept-Language":"zh-CN,zh;q=0.9",     "Cache-Control": "max-age=0",     "Connection":"keep-alive",     # 重點:這個 Cookie 是儲存了密碼無需重複登入的使用者的 Cookie,這個 Cookie 裡記錄 了使用者名稱,密碼(通常經過 RAS 加密)     "Cookie": "__cfduid=d813c9add816556c64a8c087554cfb7af1508468882; BDUSS=kM2UnphaUpJRVphdjFrQ3R0TX5KM1NhY25mLVFmdTUtbTJ2ZndiMkw1TWRYRkJiQUFBQ UFBJCQAAAAAAAAAAAEAAABUN0cMVG9temt5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB3PKFsdzyhba; BAIDUID=675B04E847A8A586ECC76203C511EA12:FG=1; PSTM=1529894757; BD_UPN=12314753; BIDUPSID=269D2DF8A150308A1A953FED45517BA8; BDORZ=B490B5EBF6F3CD402E515D22BCDA1598; BD_CK_SAM=1; PSINO=1; H_PS_PSSID=1428_21106_20927; BD_HOME=1",     "Host":"www.baidu.com",     "Upgrade-Insecure-Requests":"1", } 
 
# 2. 通過 headers 裡的報頭資訊(主要是 Cookie 資訊),構建 Request 物件 req = request.Request("https://www.baidu.com/", headers = headers) 
 
# 3. 直接訪問 renren 主頁,伺服器會根據 headers 報頭資訊(主要是 Cookie 資訊),判斷這 是一個已經登入的使用者,並返回相應的頁面 response = request.urlopen(req) # 4. 列印響應內容 html = response.read() charset = chardet.detect(html)['encoding'] print(charset) print(html.decode(charset)) 
 
cookielib庫 和 HTTPCookieProcessor處理器 
Python 處理 Cookie,一般是通過 cookielib 模組和 urllib 的 request 模組的
HTTPCookieProcessor處理器類一起使用。 
cookielib模組:主要作用是提供用於儲存cookie的物件 
HTTPCookieProcessor處理器:主要處理cookie物件,並構建handler物件。 

cookielib 庫 
主要作用是提供用於儲存cookie的物件 
該模組主要的物件有CookieJar、FileCookieJar、MozillaCookieJar、LWPCookieJar。 
CookieJar:管理HTTP cookie值、儲存HTTP請求生成的cookie、向傳出的HTTP請求新增cookie 的物件。整個 cookie 都儲存在記憶體中。 FileCookieJar (filename,delayload=None,policy=None):CookieJar 派生而來,將 cookie 儲存到 檔案中。filename 是儲存 cookie 的檔名。delayload 為 True 時支援延遲訪問檔案,即只有 在需要時才讀取檔案或在檔案中儲存資料。 MozillaCookieJar (filename,delayload=None,policy=None) :從 FileCookieJar 派 生 而 來 , MozillaCookieJar 例項與 Mozilla 瀏覽器 cookies.txt 相容。 LWPCookieJar (filename,delayload=None,policy=None):從 FileCookieJar 派生而來,例項與 libwww-perl 標準的 Set-Cookie3 檔案格式相容。 
HTTPCookieProcessor處理器:處理cookie物件,並構建handler處理器物件。 
案例:獲取Cookie,生成CookieJar()物件中 
from urllib import request import http.cookiejar 
 
# 構建一個 CookieJar 物件例項來儲存 cookie cookiejar = http.cookiejar.CookieJar() 
 
# 使用 HTTPCookieProcessor()來建立 cookie 處理器物件,引數為 CookieJar()物件 handler=request.HTTPCookieProcessor(cookiejar) 
 
# 通過 build_opener() 來構建 opener opener = request.build_opener(handler) 
 
# 4. 以 get 方法訪問頁面,訪問之後會自動儲存 cookie 到 cookiejar 中 opener.open("https://www.baidu.com") 
 
## 可以按標準格式將儲存的 Cookie 打印出來 cookieStr = "" for item in cookiejar:     cookieStr = cookieStr + item.name + "=" + item.value + ";" 
 
## 捨去最後一位的分號 print(cookieStr[:-1]) 

獲取AJAX載入的內容 
AJAX一般返回的是JSON,直接對AJAX地址進行post或get,就返回JSON資料了。 

from urllib import request from urllib import parse 
 
url = "https://movie.douban.com/j/chart/top_list?type=11&interval_id=100%3A90&action" headers={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36"} # 變動的是這兩個引數,從 start 開始往後顯示 limit 個 formdata = {     'start':'0',     'limit':'10' } data = parse.urlencode(formdata).encode(encoding='UTF8') req = request.Request(url, data = data, headers = headers) response = request.urlopen(req) print(response.read().decode('utf-8')) 
 
HTTPS請求 SSL證書驗證 
現在隨處可見 https 開頭的網站,urllib2 可以為 HTTPS 請求驗證 SSL 證書,就像 web
瀏覽器一樣,如果網站的 SSL 證書是經過 CA 認證的,則能夠正常訪問,如:
https://www.baidu.com/等... 
如果 SSL 證書驗證不通過,或者作業系統不信任伺服器的安全證書,比如瀏覽器在訪問
12306 網站如:https://www.12306.cn/mormhweb/的時候,會警告使用者證書不受信任。
(據說 12306 網站證書是自己做的,沒有通過CA 認證) 

urllib.error 
urllib.error可以接收有urllib.request產生的異常。 
 
URLError 
產生的原因主要有: 
 沒有網路連線 
 伺服器連線失敗 
 找不到指定的伺服器 
案例:訪問了一個不存在的域名,用try except語句來捕獲相應的異常 
from urllib import request from urllib import error 
 
if __name__ == "__main__":    

#一個不存在的連線    

url = "http://www.ajkfhafwjqh.com/"    

req = request.Request(url) 

 try:        

response = request.urlopen(req)        

html = response.read().decode('utf-8')        

print(html)    

except error.URLError as e:        

print(e.reason) 
HTTPError 
HTTPError 是 URLError 的子類,我們發出一個請求時,伺服器上都會對應一個 response
應答物件,其中它包含一個數字"響應狀態碼"。 
如果 urlopen 不能處理的,會產生一個 HTTPError,對應相應的狀態碼,HTTP 狀態碼錶
示HTTP協議所返回的響應的狀態。 
from urllib import request from urllib import error 
 
if __name__ == "__main__":    

#一個不存在的連線    

url = "http://www.zhihu.com/AAA.html"    

#url = "http://blog.csdn.net/cqcre"    

req = request.Request(url)    

try:        

responese = request.urlopen(req)        

html = responese.read()        

print(html)    

except error.HTTPError as e:        

print(e.code) 

混合使用 
如果想用 HTTPError 和 URLError 一起捕獲異常,那麼需要將 HTTPError 放在 URLError
的前面,因為HTTPError是URLError的一個子類。如果URLError放在前面,出現HTTP
異常會先響應URLError,這樣HTTPError就捕獲不到錯誤資訊了。 
from urllib import request from urllib import error 
 
req = request.Request("http://www.douyu.com/tom_kwok.html") try:     request.urlopen(req) except error.HTTPError as err:     print(err.code) except error.URLError as err:     print(err) else:     print("Good Job") 
也可以使用hasattr函式判斷一場物件含有的屬性,如果含有reason屬性表明是URLError,
如果含有code屬性表明是HTTPError。 
if __name__ == "__main__":    

#一個不存在的連線     url = "http://www.douyu.com/tom_kwok.html"    

req = request.Request(url)    

try:        

responese = request.urlopen(req)    

except error.URLError as e:        

if hasattr(e, 'code'):            

print("HTTPError")            

print(e.code)        

elif hasattr(e, 'reason'): 

 print("URLError")            

print(e.reason) 
狀態碼 
狀態程式碼有三位數字組成,第一個數字定義了響應的類別,且有五種可能取值: 
1xx:指示資訊–表示請求已接收,繼續處理

2xx:成功–表示請求已被成功接收、理解、接受

3xx:重定向–要完成請求必須進行更進一步的操作

4xx:客戶端錯誤–請求有語法錯誤或請求無法實現 5xx:伺服器端錯誤–伺服器未能實現合法的請求

常見狀態程式碼、狀態描述、說明: 200 OK     //客戶端請求成功 400 Bad Request  //客戶端請求有語法錯誤,不能被伺服器所理解 401 Unauthorized //請求未經授權,這個狀態程式碼必須和 WWW-Authenticate 報頭域一起使用 403 Forbidden  //伺服器收到請求,但是拒絕提供服務 404 Not Found  //請求資源不存在,eg:輸入了錯誤的 URL 500 Internal Server Error //伺服器發生不可預期的錯誤 503 Server Unavailable  //伺服器當前不能處理客戶端的請求,一段時間後可能恢復正常