爬蟲-urllib3模塊的使用
urllib3是一個功能強大,對SAP健全的 HTTP客戶端,許多Python生態系統已經使用了urllib3。
一、安裝
sudo pips install urllib3
二、創建PoolManager對象
通過urllib3訪問網頁,首先需要構造一個PoolManager實例對象用於處理與線程池的連接以及線程安全的所有細節,然後通過request()方法來發送請求
-
import urllib3 #創建PoolManager對象,用於處理與線程池的連接以及線程安全的所有細節 http = urllib3.PoolManager() #對需要爬取的網頁發送請求 resp = http.request(method,url,...)
method和url兩個參數必選,並且method需要大寫
三、基本GET請求(headers參數和fields參數)
-
最基本的GET請求
import urllib3 #創建PoolManager對象,用於處理與線程池的連接以及線程安全的所有細節 http = urllib3.PoolManager() #對需要爬取的網頁發送請求 resp = http.request('GET','//www.baidu.com/') print(resp.data.decode())#響應數據 print(resp.headers)#響應頭信息 print(resp.status)#狀態碼 resp.release_conn()#釋放這個http連接
-
添加headers和查詢參數
可以傳入headers
參數(dict類型)來增加請求頭中的headers信息。可以利用fields參數傳遞查詢參數(dict類型),並且url後面的’?『一定不能帶上
-
import urllib3 http = urllib3.PoolManager() kw = {"wd":"長城"} headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"} resp = proxy.request('GET','//www.baidu.com/s',fields=kw,headers = headers) print(resp.data.decode())
四、基本POST請求(fields參數)
-
最基本的POST請求需要傳入fields參數(dict類型),urllib3會自動將其轉換成表單數據類型
import urllib3 http = urllib3.PoolManager() #需要提交的數據 data = {'word':'hello'} headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"} response = http.request('POST','//httpbin.org/post',fields = data,headers = headers) print(response.data.decode())
-
url中攜帶查詢參數
- 需要先通過urlencode()編碼,然後附加在url後面,這和GET方式有所不同(示例略)
-
傳遞json數據(body參數)
- 利用body參數進行傳遞,但是數據需要先序列化成json字符串,然後headers中需要設置’Content-Type’:’application/json’
-
import urllib3 import json http = urllib3.PoolManager() url = '//openapi.vmall.com/mcp/offlineshop/getShopList' data = { "portal":2,"lang":"zh-CN","country":"CN","brand":1,"province":"山西","city":"太原","pageNo":1,"pageSize":20 } # 將字典類型數據序列化成json字符串 json_data = json.dumps(data) #headers中設置Conten-Type為application/json headers = { 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.163 Safari/537.36', 'Content-Type':'application/json' } resp = http.request('POST',url,body = json_data,headers = headers) print(resp.data.decode())
注意:body參數和fields參數不能同時使用
五、文件上傳
-
普通文件上傳
- 使用multipart/form-data編碼方式上傳文件,可以使用和傳入Form data數據一樣的方法進行,並將文件定義為一個二元元組(文件名,數據)或三元元組(文件名,數據,MIME類型),文件名的定義雖然不是嚴格要求的,但是推薦使用,以使得表現得更像瀏覽器
import urllib3 http = urllib3.PoolManager() #打開文件test.txt with open('test.txt','r') as f: file_data = f.read() headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"} #三元元組的方式傳入 resp = http.request('POST','//httpbin.org/post',fields={'filefield':('test.txt',file_data,'text/plain')},headers=headers) #二元元組的方式傳入 #resp = http.request('POST','//httpbin.org/post',fields={'filefield':('test.txt',file_data)},headers=headers) print(resp.data.decode('unicode_escape'))
-
二進制文件上傳
- 原始二進制數據,只要將其定義為body參數即可。同時,建議對header的Content-Type參數進行設置
import urllib3 http = urllib3.PoolManager() with open('test.jpg','rb') as f: binary_data = f.read() headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36",'Content-Type':'image/jpeg'} resp = http.request('POST','//httpbin.org/post',body = binary_data,headers = headers) print(resp.data.decode())
- 原始二進制數據,只要將其定義為body參數即可。同時,建議對header的Content-Type參數進行設置
六、超時設置
-
使用timeout,可以控制請求的總超時時間(連接超時和讀取超時時間總和),timeout參數為一個浮點數:
resp = http.request('GET','//httpbin.org/delay/3',timeout = 4.0)
-
也可以分別設置總超時、連接超時和讀取超時時間,這時候需要使用Timeout()實例,裏面有3個關鍵字參數total,connect和read:
#設置總超時時間為3.0秒,連接超時不超過1.5秒,讀取超時不超過2.0秒 resp = http.request('GET','//httpbin.org/delay/3',timeout = urllib3.Timeout(total=3.0,connect=1.5,read=2.0))
-
如果想讓所有的request都遵循一個timeout,可以將timeout參數定義在PoolManager中,當在具體的request中再次定義timeout時,會覆蓋PoolManager層面上的timeout。
http = urllib3.PoolManager(timeout = urllib3.Timeout(total=3.0,connect=1.5,read=2.0)) #http = urllib3.PoolManager(timeout = 4.0)
七、重試(retries參數)以及重定向(redirect參數)設置
-
urllib3默認進行3次請求重試,3次重定向
-
通過retries來自定義請求重試次數
#設置請求重試次數10次 resp = http.request('GET','//httpbin.org/ip',retries = 10)
-
將參數retries設為False,請求重試和重定向會同時關閉
#同時關閉請求重試和重定向 resp = http.request('GET','//httpbin.org/redirect/1',retries = False)
-
將參數redirect設為False,僅關閉重定向,保持請求重試
#僅關閉重定向 resp = http.request('GET','//httpbin.org/redirect/1',redirect = False)
-
通過Retry()實例可以精細控制重試和重定向次數,該實例默認總重試次數為10次,比如我們設置3次重試,2次重定向
resp = http.request('GET','//httpbin.org/redirect/3',retries = urllib3.Retry(3,redirect = 2))
-
如果想讓所有的request都遵循一個請求重試和重定向策略,可以在PoolManager中定義retries參數,當在具體的request中再次定義retries時,會覆蓋 PoolManager層面上的retries。
http = urllib3.PoolManager(retries = urllib3.Retry(3,redirect=2)) #http = urllib3.PoolManager(retries = False)
八、ProxyManager(代理IP)
- 如果你需要使用代理來訪問某個網站的話, 那麼你可以使用 ProxyManager 對象來進行設置
- ProxyManager和PoolManager的方法基本完全相同,這裡舉個簡單的小例子
import urllib3 #創建ProxyManager對象 proxy_http = urllib3.ProxyManager('//175.42.122.96:9999') headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"} #利用代理對需要爬取的網頁發送請求 resp = proxy_http.request('GET','//www.baidu.com/',headers=headers) print(resp.data.decode())#響應數據 print(resp.headers)#響應頭信息 print(resp.status)#狀態碼 resp.release_conn()#釋放這個http連接
九、SSL證書驗證
-
urllib3默認不驗證HTTPS請求,如果想開啟驗證,最可靠的方法是使用提供Mozilla根證書包的certifi包
sudo pip3 install certifi
-
獲得證書後,可以在PoolManager中定義cert_reqs參數和ca_certs參數,來自動處理證書驗證
import urllib3 import certici #開啟ssl證書自動驗證 http = urllib3.PoolManager(cert_reqs='CERT_REQUIRED',ca_certs=certifi.where()) headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"} resp = http.request('GET','//www.baidu.com/',headers=headers) print(resp.data.decode())
-
如果需要,可以使用OS提供的證書。只需指定證書包的完整路徑作為ca_certs參數而不是 certifi.where()。例如,大多數Linux系統都存儲證書/etc/ssl/certs/ca-certificates.crt。
import urllib3 import certifi http = urllib3.PoolManager(cert_reqs='CERT_REQUIRED',ca_certs='/etc/ssl/certs/ca-certificates.crt')