爬蟲入門講解(用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 //伺服器當前不能處理客戶端的請求,一段時間後可能恢復正常