在上一篇日志中對Requests做了一個整體的介紹,接來下再介紹一些高級的用法,主要資料還是翻譯自官網的文檔,如有錯漏,歡迎指正。
參考資料:http://docs.python-requests.org/en/latest/user/advanced/
會話對象(Session Objects)
一個請求傳遞的參數,在另一個請求是無效的,不過會話對象允許跨請求的保存參數,還可以從會話實例中保存所有請求的cookies數據。
下面介紹一下在Requests中會話對象主要的API。
跨請求的保存cookies數據:
s = requests.Session() s.get('http://httpbin.org/cookies/set/sessioncookie/123456789') r = s.get("http://httpbin.org/cookies") print r.text # '{"cookies": {"sessioncookie": "123456789"}}'
傳遞到請求方法中任何字典類型的數據都會設置成會話級別的值,方法級別的參數會覆蓋會話級別的參數。
刪除一個字典類型的參數:
有時,想從會話中刪除一個字典的鍵,要做到這一點,只要設置方法參數中鍵的值為None
,它就會自動的被刪除掉。
請求和響應對象(Request and Response Objects)
每當調用requests.*()的請求方法時,主要做兩個事情,第一個是構造一個請求對象對服務器發起請求或者查詢一些資源。第二個是在請求從服務器獲得一個響應時生成一個響應對象。響應對象包含從服務器返回的所有信息也包含最初構造的請求對象。以下這個例子是一個簡單的請求從Wikipedia的服務器返回一些重要的信息:
>>> r = requests.get('http://en.wikipedia.org/wiki/Monty_Python')
如果想訪問從服務器返回給我們的標頭信息,可以這樣做:
>>> r.headers {'content-length': '56170', 'x-content-type-options': 'nosniff', 'x-cache': 'HIT from cp1006.eqiad.wmnet, MISS from cp1010.eqiad.wmnet', 'content-encoding': 'gzip', 'age': '3080', 'content-language': 'en', 'vary': 'Accept-Encoding,Cookie', 'server': 'Apache', 'last-modified': 'Wed, 13 Jun 2012 01:33:50 GMT', 'connection': 'close', 'cache-control': 'private, s-maxage=0, max-age=0, must-revalidate', 'date': 'Thu, 14 Jun 2012 12:59:39 GMT', 'content-type': 'text/html; charset=UTF-8', 'x-cache-lookup': 'HIT from cp1006.eqiad.wmnet:3128, MISS from cp1010.eqiad.wmnet:80'}
然而,如果想訪問請求發送給服務器的標頭信息:
>>> r.request.headers {'Accept-Encoding': 'identity, deflate, compress, gzip', 'Accept': '*/*', 'User-Agent': 'python-requests/0.13.1'}
SSL證書驗證(SSL Cert Verification)
Requests就像一個web瀏覽器一樣,可以驗證SSL證書和HTTPS請求,檢查主機的SSL證書,可以使用verify
參數:
>>> requests.get('https://kennethreitz.com', verify=True) requests.exceptions.SSLError: hostname 'kennethreitz.com' doesn't match either of '*.herokuapp.com', 'herokuapp.com'
https://kennethreitz.com
這個域名沒有設置SSL證書,所以它驗證失敗了,Github就能通過驗證:
>>> requests.get('https://github.com', verify=True) <Response [200]>
默認情況下verify
的值為True,verify
選項只適用於驗證主機的證書。
還可以指定本地的證書文件作為一個路徑或鍵值對:
>>> requests.get('https://kennethreitz.com', cert=('/path/server.crt', '/path/key')) <Response [200]>
如果指定一個錯誤的路徑或無效的證書:
>>> requests.get('https://kennethreitz.com', cert='/wrong_path/server.pem') SSLError: [Errno 336265225] _ssl.c:347: error:140B0009:SSL routines:SSL_CTX_use_PrivateKey_file:PEM lib
正文內容的工作流程(Body Content Workflow)
默認情況下,當發出一個請求,響應正文會立即被下載,你可以覆蓋這個行為來推遲下載響應正文直到你通過stream
這個參數來訪問Response.content屬性:
tarball_url = 'https://github.com/kennethreitz/requests/tarball/master' r = requests.get(tarball_url, stream=True)
這時候,只有響應的標頭被下載和連接仍然保持打開,因此,我們可以有條件的檢索內容:
if int(r.headers['content-length']) < TOO_LONG: content = r.content ...
通過使用Response.iter_content
和Response.iter_lines
方法你可以進一步的控制工作流程,或者通過Response.raw
閱讀底層urllib3的urllib3.HTTPResponse.
Keep-Alive
由於使用urllib3,在會話中keep-Alive是100%自動的,在一個會話中創建的任何請求都會自動使用適當的連接。
注意,當所有的正文數據已被讀取,連接會被釋放回池中以便重用;一定要設置stream
為False或者讀取響應對象的content
屬性。
流上傳(Streaming Uploads)
Requests支持流上傳,它允許你發送大量的流或文件而不讀取到內存中,流上傳,只需要為正文提供一個類似文件的對象:
with open('massive-body') as f: request.post('http://some.url/streamed', data=f)
數據塊編碼請求(Chunk-Encoded Requests)
Requets還為傳入和傳出的請求提供塊傳輸編碼的支持,發送一個塊編碼的請求,為你的正文簡單的提供一個生成器(或者任何沒有長度的迭代器):
def gen(): yield 'hi' yield 'there' request.post('http://some.url/chunked', data=gen())
事件鈎子(Event Hooks)
Requests有一個hook系統,你可以用它來操縱部分請求過程,或者進行信號事件的處理。
可用的hooks:response
:
響應從一個請求產生。
根據每條請求可以指定一個hook函數通過一個{hook_name: callback_function}
字典類型的hook請求參數:
hooks=dict(response=print_url)
回調函數會收到一個塊數據作為第一個參數。
def print_url(r): print(r.url)
當執行回調的時候如果出現了錯誤,會給出一個警告。
如果回調函數返回一個值,就認為它是在傳遞時替換數據的,如果函數沒有返回任何值,那它就沒有什么其他的影響。
在運行時輸出一些請求方法的參數:
>>> requests.get('http://httpbin.org', hooks=dict(response=print_url)) http://httpbin.org <Response [200]>
自定義的身份驗證(Custom Authentication)
Requests允許你使用指定的自定義的身份驗證機制。
任何可調用的請求方法通過auth
參數,在派發之前可以修改請求。
身份驗證很容易定義,都是繼承於requests.auth.AuthBase
的子類。Requests提供兩種常見的身份驗證方案實現在requests.auth: HTTPBasicAuth
和HTTPDigestAuth
。
我們假裝我們有一個web服務,它只會在標頭的X-Pizza
被設置為一個密碼值時返回響應,雖然不太可能,但只是用它就好:
from requests.auth import AuthBase class PizzaAuth(AuthBase): """Attaches HTTP Pizza Authentication to the given Request object.""" def __init__(self, username): # setup any auth-related data here self.username = username def __call__(self, r): # modify and return the request r.headers['X-Pizza'] = self.username return r
然后,我們可以創建一個請求使用Pizza驗證:
>>> requests.get('http://pizzabin.org/admin', auth=PizzaAuth('kenneth')) <Response [200]>
流請求(Streaming Requests)
利用requests.Response.iter_lines()
方法,你可以輕松的遍歷流API如Twitter Streaming API.
使用Twitter Streaming API去跟蹤“requests”關鍵字:
import requests import json r = requests.post('https://stream.twitter.com/1/statuses/filter.json', data={'track': 'requests'}, auth=('username', 'password'), stream=True) for line in r.iter_lines(): if line: # filter out keep-alive new lines print json.loads(line)
代理(Streaming Requests)
如果你需要使用一個代理,你可以在任何請求方法中使用proxies
參數配置單個請求:
import requests proxies = { "http": "10.10.1.10:3128", "https": "10.10.1.10:1080", } requests.get("http://example.org", proxies=proxies)
你也可以通過環境變量HTTP_PROXY
和HTTPS_PROXY
來配置代理:
$ export HTTP_PROXY="10.10.1.10:3128" $ export HTTPS_PROXY="10.10.1.10:1080" $ python >>> import requests >>> requests.get("http://example.org")
為你的代理使用HTTP的基本認證,可以使用這樣http://user:password@host/
的格式:
proxies = { "http": "http://user:pass@10.10.1.10:3128/", }