1. 程式人生 > 實用技巧 >requests高階用法

requests高階用法

會話物件

會話物件讓你能夠跨請求保持某些引數。它也會在同一個Session例項發出的所有請求之間保持cookie,期間使用urllib3的connection pooling功能。所以如果你向同一主機發送多個請求,底層的TCP連結將會被重用,從而帶來顯著的效能提升。

我們來跨請求保持一些cookie:

會話也可用來為請求方法提供預設資料。這是通過為會話物件的屬性提供資料來實現的:

任何你傳遞給請求方法的字典都會與已設定會話層資料合併。方法層的引數覆蓋會話的引數。

不過需要注意,就算使用了會話,方法級別的引數也不會被跨請求保持。下面的例子只會和第一個請求傳送cookie,而非第二個;

從字典引數中移除一個值:

有時你會想省略字典引數中一些會話層的鍵。要做到這一點,你只需簡單地在方法層引數中將那個鍵的值設定為None,那個鍵就會被自動省略掉。

請求與響應物件

任何時候進行了類似requests.get()的呼叫,你都在做兩件主要的事情。其一,你在構建一個Request物件,該物件將被髮送到某個伺服器請求或查詢一些資源。其二。一旦requests得到一個從伺服器返回的響應就會產生一個Response物件。該響應物件包含伺服器返回的所有資訊,也包含你原來建立的request物件。

準備的請求

當你從API或者會話呼叫中收到一個Response物件時,request屬性其實是使用了PrepareRequest。有時在傳送請求之前,你需要對body或者header做一些額外處理。

SSL證書驗證

Requests可以為HTTPS請求驗證SSL證書,就像web瀏覽器一樣。SSL驗證預設是開啟的。

客戶端證書

你也可以指定一個本地證書用作客戶端證書,可以是單個檔案(包含金鑰和證書)或一個包含兩個檔案路徑的元組:

CA證書

Requests預設附帶了一套它信任的根證書,來自於Mozilla trust store。

響應體內容工作流

預設情況下,當你進行網路請求後,響應體會立即被下載。你可以通過stream引數覆蓋這個行為,推遲下載響應體直接訪問Response.content屬性。

import requests
#s=requests.get("https://www.baidu.com")
s=requests.get("https://www.baidu.com",stream=True)
print(s.content)  

如果你在請求中把stream設為True,Requests 無法將連線釋放回連線池,除非你 消耗了所有的資料,或者呼叫了Response.close。 這樣會帶來連線效率低下的問題。如果你發現你在使用stream=True的同時還在部分讀取請求的 body(或者完全沒有讀取 body),那麼你就應該考慮使用 with 語句傳送請求,這樣可以保證請求一定會被關閉:

with requests.get('http://httpbin.org/get', stream=True) as r:
    # 在此處理響應。

保持活動狀態(持久連線)

好訊息——歸功於 urllib3,同一會話內的持久連線是完全自動處理的!同一會話內你發出的任何請求都會自動複用恰當的連線!

注意:只有所有的響應體資料被讀取完畢連線才會被釋放為連線池;所以確保將stream設定為False或讀取Response物件的content屬性。

流式上傳

Requests支援流式上傳,這允許你傳送大的資料流或檔案而無需先把它們讀入記憶體。

要使用流式上傳,僅需為你的請求體提供一個類檔案物件即可:

塊編碼請求

對於出去或進來的請求,Requsts也支援分塊傳輸編碼。要傳送一個塊編碼的請求,僅需為你的請求體提供一個生成器(或任意沒有具體長度的迭代器):

POST多個分塊編碼的檔案

你可以在一個請求中傳送多個檔案。

事件掛鉤

Requests有一個鉤子系統,你可以用來操控部分請求過程,或訊號事件處理。

自定義身份驗證

Requests允許你使用自己指定的身份驗證機制。

任何傳遞給請求方法的auth引數的可呼叫物件,在請求發出之前都有機會修改請求。

自定義的身份驗證機制是作為requests.auth.AuthBase的子類來實現的,也非常容易定義。Requests在requests.auth中提供了兩種常見的身份驗證方案:

HTTPBasicAuth和HTTPDigestAuth。

流式請求

使用Response.iter_lines()你可以很方便地對流式API進行迭代。簡單地設定stream為True便可以使用iter_lines對響應進行迭代:

import json
import requests
r = requests.get('http://httpbin.org/stream/20', stream=True)
for line in r.iter_lines():
    # filter out keep-alive new lines
    if line:
        decoded_line = line.decode('utf-8')
        print(json.loads(decoded_line))

代理

如果需要使用代理,你可以通過為任意請求方法提供proxies引數來配置單個請求:

SOCKS

除了基本的HTTP代理,Request還支援SOCKS協議的代理。這是一個可選功能,若要使用,你需要安裝第三方庫。

合規性

Requests符合所有相關的規範和RFC,這樣不會為使用者造成不必要的困難。但這種對規範的考慮導致一些行為對於不熟悉相關規範的人來說看似有點奇怪。

編碼方式

HTTP動詞

Requests提供了幾乎所有HTTP動詞的功能:GET,OPTIONS,HEAD,POST,PUT,PATCH,DELETE。以下內容為使用Requests中的這些動詞以及Github API提供了詳細示例。

定製動詞

有時候你會碰到一些伺服器,處於某些原因,他們允許或者要求使用者使用上述HTTP動詞之外的定製動詞。比如說WEBDAV伺服器會要求你使用MKCOL方法。別擔心,Requests一樣可以搞定他們。你可以使用內建的.requests方法;

響應頭連結欄位

許多HTTP API都有響應頭連結欄位的特性,他們使得API能夠更好地自我描述和自我暴露。

傳輸介面卡

從v1.0.0以後,Requests的內部採用了模組化設計。部分原因是為了實現傳輸介面卡。

阻塞和非阻塞

使用預設的傳輸介面卡,Requests不提供任何形式的非阻塞IO。Response.content屬性會阻塞,直到整個響應下載完成。

Header排序

在某些特殊情況下你也許需要按照次序來提供header,如果你向headers關鍵字引數傳入一個OrderDict,就可以向提供一個帶排序的header。然而,Requests 使用的預設 header 的次序會被優先選擇,這意味著如果你在headers關鍵字引數中覆蓋了預設 header,和鍵字引數中別的 header 相比,它們也許看上去會是次序錯誤的。

如果這個對你來說是個問題,那麼使用者應該考慮在Session物件上面設定預設 header,只要將Session設為一個定製的OrderedDict即可。這樣就會讓它成為優選的次序。

超時(timeout) 

為防止伺服器不能及時響應,大部分發至外部伺服器的請求都應該帶著timeout引數。在預設情況下,除非顯式指定了timeout值,requests是不會自動進行超時處理的。如果沒有timeout,你的程式碼可能會掛起若干分鐘甚至更長時間。

連線超時指的是在你的客戶端實現到遠端機器埠的連線時(對應的是`connect()`_),Request 會等待的秒數。一個很好的實踐方法是把連線超時設為比 3 的倍數略大的一個數值,因為TCP 資料包重傳視窗 (TCP packet retransmission window)的預設大小是 3。

一旦你的客戶端連線到了伺服器並且傳送了 HTTP 請求,讀取超時指的就是客戶端等待伺服器傳送請求的時間。(特定地,它指的是客戶端要等待伺服器傳送位元組之間的時間。在 99.9% 的情況下這指的是伺服器傳送第一個位元組之前的時間)。