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','https://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','https://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','http://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 = 'https://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','http://httpbin.org/post',fields={'filefield':('test.txt',file_data,'text/plain')},headers=headers) #二元元組的方式傳入 #resp = http.request('POST','http://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','http://httpbin.org/post',body = binary_data,headers = headers) print(resp.data.decode())
- 原始二進位制資料,只要將其定義為body引數即可。同時,建議對header的Content-Type引數進行設定
六、超時設定
-
使用timeout,可以控制請求的總超時時間(連線超時和讀取超時時間總和),timeout引數為一個浮點數:
resp = http.request('GET','http://httpbin.org/delay/3',timeout = 4.0)
-
也可以分別設定總超時、連線超時和讀取超時時間,這時候需要使用Timeout()例項,裡面有3個關鍵字引數total,connect和read:
#設定總超時時間為3.0秒,連線超時不超過1.5秒,讀取超時不超過2.0秒 resp = http.request('GET','http://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','http://httpbin.org/ip',retries = 10)
-
將引數retries設為False,請求重試和重定向會同時關閉
#同時關閉請求重試和重定向 resp = http.request('GET','http://httpbin.org/redirect/1',retries = False)
-
將引數redirect設為False,僅關閉重定向,保持請求重試
#僅關閉重定向 resp = http.request('GET','http://httpbin.org/redirect/1',redirect = False)
-
通過Retry()例項可以精細控制重試和重定向次數,該例項預設總重試次數為10次,比如我們設定3次重試,2次重定向
resp = http.request('GET','http://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('https://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','https://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','https://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')