爬蟲利器:Requests庫使用
Requests:讓HTTP服務人類。
本文中的有些內容來自官方網站,也有一部分是我的理解,算是個筆記版本吧。
1、requests是什麼
寫了一些爬蟲,從urllib庫轉到requests庫,到目前為止,個人感覺requests庫是最簡單易用的HTTP庫,以下這段話來自requests官網:
Requests 唯一的一個非轉基因的 Python HTTP 庫,人類可以安全享用。
警告:非專業使用其他 HTTP 庫會導致危險的副作用,包括:安全缺陷症、冗餘程式碼症、重新發明輪子症、啃文件症、抑鬱、頭疼、甚至死亡。
字裡行間透露著requests庫的自信,它確實做到了。
以下為Requests庫的功能特性,完全滿足今日web的需求:
- Keep-Alive & 連線池
- 國際化域名和 URL
- 帶持久 Cookie 的會話
- 瀏覽器式的 SSL 認證
- 自動內容解碼
- 基本/摘要式的身份認證
- 優雅的 key/value Cookie
- 自動解壓
- Unicode 響應體
- HTTP(S) 代理支援
- 檔案分塊上傳
- 流下載
- 連線超時
- 分塊請求
- 支援
.netrc
2、安裝及更新
2.1 安裝
最簡單的安裝方式是pip安裝,只需執行以下一條指令:
pip install requests
也可以通過git使用原始碼安裝,需要執行以下兩條指令:
git clone git://github.com /kennethreitz/requests.git
python setup.py install
2.2 更新
使用pip進行更新:
pip install --upgrade requests
3、使用
3.1 傳送請求
我們以http://httpbin.org/
網站作為測試目標,該網站專門為HTTP客戶端提高測試服務。
使用該庫要在檔案開始部分匯入Requests模組:
import requests
HTTP的請求型別有POST,GET,PUT,DELETE,HEAD 以及 OPTIONS,其中POST和GET是最常使用的,用requests實現這幾種請求程式碼如下:
r = requests.get('https://httpbin.org/get')
r = requests.put("http://httpbin.org/put")
r = requests.delete("http://httpbin.org/delete")
r = requests.head("http://httpbin.org/get")
r = requests.options("http://httpbin.org/get")
我們得到了一個名為r
的Response物件,我們可以從這個物件中獲取想要的資訊,例如狀態碼(r.status_code)、文字內容(r.text)等。
3.2 傳遞URL引數
經常可以看到一些網址中有一個?
, 後面還跟著幾個引數,這種URL其實傳遞了某種資料,例如http://httpbin.org/get?key=val
。Requests允許使用params 關鍵字引數,以一個字串字典來提供這些引數。如果想傳遞key1=val1
和key2=val2
到httpbin.org/get
,那麼可以使用如下程式碼:
payload = {'key1': 'val1', 'key2': 'val2', 'key3': None}
r = requests.get("http://httpbin.org/get", params=payload)
print(r.url)
執行結果為:http://httpbin.org/get?key1=val1&key2=val2
注:字典中值為None的鍵不會被新增到URL的查詢字串中。
還可以將一個列表作為值傳入:
payload = {'key1': 'val1', 'key2': ['val2', 'val3']}
r = requests.get("http://httpbin.org/get", params=payload)
print(r.url)
執行結果為:http://httpbin.org/get?key1=val1&key2=val2&key2=val3
3.3 響應內容
3.3.1 文字響應內容
在3.1中已經提到Response物件包含很多資訊,其中r.text
為伺服器響應內容:
r = requests.get("http://httpbin.org/get")
print(r.text)
執行結果為:
{
"args": {},
"headers": {
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate",
"Connection": "close",
"Host": "httpbin.org",
"User-Agent": "python-requests/2.18.4"
},
"origin": "114.244.178.208",
"url": "http://httpbin.org/get"
}
Requests可以自動對大多數unicode字符集無縫解碼。
請求發出後,Requests會基於HTTP頭部對響應的編碼做出有根據的推測。我們可以通過r.encoding
得到編碼,也可以使用r.encoding
屬性改變編碼。
3.3.2 二進位制響應內容
上面r.text
獲得的是響應內容的文字,我們也可以以位元組的方式訪問請求響應體,對於非文字請求r.content
,Requests會自動解碼gzip
和deflate
傳輸編碼的響應內容。
3.3.3 JSON響應內容
Requests內建一個JSON解碼器,使用方法如下:
r = requests.get("http://httpbin.org/get")
print(r.json())
如果JSON解碼失敗,r.json()
會丟擲一個異常。需要注意的是,成功呼叫r.json()
並不意味著響應成功,因為某些伺服器會在失敗的響應中包含一個JSON物件,這種JSON會被解碼返回。如果要判斷請求是否成功,我們可以使用r.raise_for_status()
或者檢查r.status_code
是否和預期相同。
3.3.4 原始響應內容
有時候我們可能需要獲取伺服器的原始套接字響應,那麼我們應該使用r.raw
,使用時要確保在初始請求中設定了stream=True
:
r = requests.get("http://httpbin.org/get", stream=True)
print(r.raw)
print(r.raw.read(10))
執行結果如下:
<urllib3.response.HTTPResponse object at 0x0000021D55814320>
b'{\n "args"'
4、定製請求頭
請求某些伺服器時需要加上請求頭,Requests的請求介面有一個名為headers
的引數,只需傳給它一個字典即可:
headers = {'user-agent': 'my-app/0.0.1'}
r = requests.get("http://httpbin.org/get", headers=headers)
注意: 定製 header 的優先順序低於某些特定的資訊源,例如:
- 如果在
.netrc
中設定了使用者認證資訊,使用 headers= 設定的授權就不會生效。而如果設定了auth=
引數,.netrc
的設定就無效了。 - 如果被重定向到別的主機,授權 header 就會被刪除。
- 代理授權 header 會被 URL 中提供的代理身份覆蓋掉。
- 在我們能判斷內容長度的情況下,header 的 Content-Length 會被改寫。
更進一步講,Requests 不會基於定製 header 的具體情況改變自己的行為。只不過在最後的請求中,所有的 header 資訊都會被傳遞進去。
注意: 所有的 header 值必須是 string
、bytestring 或者 unicode。儘管傳遞 unicode header 也是允許的,但不建議這樣做。
5、響應狀態碼
我們可以響應狀態碼得知此次請求的結果,一般200
為請求成功, Requests還附帶了一個內建的狀態碼查詢物件requests.codes
:
r = requests.get('http://httpbin.org/get')
print(r.status_code)
print(r.status_code == requests.codes.ok)
執行結果為:
200
True
如果傳送了一個錯誤請求(一個 4XX 客戶端錯誤,或者 5XX 伺服器錯誤響應),我們可以通過 Response.raise_for_status()
來丟擲異常:
r = requests.get('http://httpbin.org/status/404')
print(r.status_code)
r.raise_for_status()
執行結果為:
404
---------------------------------------------------------------------------
HTTPError Traceback (most recent call last)
<ipython-input-19-351ffd673854> in <module>()
1 r = requests.get('http://httpbin.org/status/404')
2 print(r.status_code)
----> 3 r.raise_for_status()
E:\Anaconda3\lib\site-packages\requests\models.py in raise_for_status(self)
933
934 if http_error_msg:
--> 935 raise HTTPError(http_error_msg, response=self)
936
937 def close(self):
HTTPError: 404 Client Error: NOT FOUND for url: http://httpbin.org/status/404
6、響應頭
不只請求會有請求頭,響應也有響應頭:
r = requests.get('http://httpbin.org/get')
print(r.headers)
print(r.headers['Connection'])
print(r.headers['connection'])
print(r.headers['conNecTion'])
執行結果:
{
"Connection": "keep-alive",
"Server": "meinheld/0.6.1",
"Date": "Thu, 25 Jan 2018 13:47:59 GMT",
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Credentials": "true",
"X-Powered-By": "Flask",
"X-Processed-Time": "0.00102591514587",
"Content-Length": "268",
"Via": "1.1 vegur"
}
keep-alive
keep-alive
keep-alive
可以看出該伺服器響應頭為Python字典形式,但是這個字典比較特殊:它是僅為HTTP頭部而生的,是大小寫不敏感的。我們可以以任意大小寫形式來訪問響應頭欄位,由上面的例子也可以看出。
7、超時
requests在傳送請求時可以附帶一個timeout引數,如果伺服器在timeout秒內沒有應答,將會引發一個異常,更精確地說,是在timeout秒內沒有從基礎套接字上接收到任何位元組的資料時。如果我們不使用這個引數,我們的程式可能會永遠失去響應。
r = requests.get('http://httpbin.org/get', timeout=0.01)
這樣就可以得到一個超時異常:
timeout Traceback (most recent call last)
ConnectTimeout: HTTPConnectionPool(host='httpbin.org', port=80): Max retries exceeded with url: /get (Caused by ConnectTimeoutError(<urllib3.connection.HTTPConnection object at 0x000002BADB2A40F0>, 'Connection to httpbin.org timed out. (connect timeout=0.01)'))
8、錯誤與異常
遇到網路問題(如:DNS 查詢失敗、拒絕連線等)時,Requests 會丟擲一個ConnectionError
異常。
若請求超時,則丟擲一個 Timeout
異常。
若請求超過了設定的最大重定向次數,則會丟擲一個 TooManyRedirects
異常。
所有Requests顯式丟擲的異常都繼承自 requests.exceptions.RequestException
。
9、 代理
某些網站對同一IP的訪問頻率和次數做了限制,如果想要突破這些限制,頻繁替換代理是一種最簡單的解決辦法。Requests庫也為我們提供了代理的使用,只要在傳送請求時指定proxies引數即可:
proxies = {
"http": "http://10.111.1.14:1212",
"https": "http://10.110.1.10:1213",
}
r = requests.get("http://httpbin.org/get", proxies=proxies)
如果使用的代理需要使用HTTP Basic Auth,可以使用http://user:[email protected]/
語法:
proxies = {
"http": "http://user:[email protected]:3128/",
}
如果要為某個特定主機設定代理,使用scheme://hostname
作為key,它會為指定的主機進行匹配代理:
proxies = {'http://10.20.1.128': 'http://10.10.1.10:5323'}
至此,Requests庫的常用功能介紹完畢,如果想要進階功能的使用教程,請移步官方網站: