Python request 簡單使用

Requests 是用Python語言編寫,基於 urllib,採用 Apache2 Licensed 開源協議的 HTTP 庫。它比 urllib 更加方便,能夠節約咱們大量的工做,徹底知足 HTTP 測試需求。Requests 的哲學是以 PEP 20 的習語爲中心開發的,因此它比 urllib 更加 Pythoner。更重要的一點是它支持 Python3 哦!python

發送請求

使用 Requests 發送網絡請求很是簡單。nginx

一開始要導入 Requests 模塊:git

import requests
 
  

而後,嘗試獲取某個網頁。本例子中,咱們來獲取 Github 的公共時間線:github

 

 r = requests.get('https://api.github.com')

 

如今,咱們有一個名爲 r 的 Response 對象。咱們能夠從這個對象中獲取全部咱們想要的信息。json

Requests 簡便的 API 意味着全部 HTTP 請求類型都是顯而易見的。例如,你能夠這樣發送一個 HTTP POST 請求:api

 
   
>>> r = requests.post('http://httpbin.org/post', data = {'key':'value'})
 
  

漂亮,對吧?那麼其餘 HTTP 請求類型:PUT,DELETE,HEAD 以及 OPTIONS 又是如何的呢?都是同樣的簡單:跨域

 
   
>>> r = requests.put('http://httpbin.org/put', data = {'key':'value'})
>>> r = requests.delete('http://httpbin.org/delete')
>>> r = requests.head('http://httpbin.org/get')
>>> r = requests.options('http://httpbin.org/get')
 
  

都很不錯吧,但這也僅是 Requests 的冰山一角服務器

傳遞 URL 參數

你也許常常想爲 URL 的查詢字符串(query string)傳遞某種數據。若是你是手工構建 URL,那麼數據會以鍵/值對的形式置於 URL 中,跟在一個問號的後面。例如, httpbin.org/get?key=val。 Requests 容許你使用 params 關鍵字參數,以一個字符串字典來提供這些參數。舉例來講,若是你想傳遞 key1=value1 和 key2=value2 到 httpbin.org/get ,那麼你可使用以下代碼:cookie

 
   
>>> payload = {'key1': 'value1', 'key2': 'value2'}
>>> r = requests.get("http://httpbin.org/get", params=payload)
 
  

經過打印輸出該 URL,你能看到 URL 已被正確編碼:網絡

 
   
>>> print(r.url)
http://httpbin.org/get?key2=value2&key1=value1
 
  

注意字典裏值爲 None 的鍵都不會被添加到 URL 的查詢字符串裏。

你還能夠將一個列表做爲值傳入:

 
   
>>> payload = {'key1': 'value1', 'key2': ['value2', 'value3']}

>>> r = requests.get('http://httpbin.org/get', params=payload)
>>> print(r.url)
http://httpbin.org/get?key1=value1&key2=value2&key2=value3

響應內容

咱們能讀取服務器響應的內容。再次以 GitHub 時間線爲例:

 
   
>>> import requests
>>> r = requests.get('https://api.github.com/events')
>>> r.text
u'[{"repository":{"open_issues":0,"url":"https://github.com/...
 
  

Requests 會自動解碼來自服務器的內容。大多數 unicode 字符集都能被無縫地解碼。

請求發出後,Requests 會基於 HTTP 頭部對響應的編碼做出有根據的推測。當你訪問 r.text 之時,Requests 會使用其推測的文本編碼。你能夠找出 Requests 使用了什麼編碼,而且可以使用r.encoding 屬性來改變它:

 
   
>>> r.encoding
'utf-8'
>>> r.encoding = 'ISO-8859-1'

若是你改變了編碼,每當你訪問 r.text ,Request 都將會使用 r.encoding 的新值。你可能但願在使用特殊邏輯計算出文本的編碼的狀況下來修改編碼。好比 HTTP 和 XML 自身能夠指定編碼。這樣的話,你應該使用 r.content 來找到編碼,而後設置 r.encoding 爲相應的編碼。這樣就能使用正確的編碼解析 r.text 了。

在你須要的狀況下,Requests 也可使用定製的編碼。若是你建立了本身的編碼,並使用 codecs模塊進行註冊,你就能夠輕鬆地使用這個解碼器名稱做爲 r.encoding 的值, 而後由 Requests 來爲你處理編碼。

二進制響應內容

你也能以字節的方式訪問請求響應體,對於非文本請求:

 
   
>>> r.content
b'[{"repository":{"open_issues":0,"url":"https://github.com/...

Requests 會自動爲你解碼 gzip 和 deflate 傳輸編碼的響應數據。

例如,以請求返回的二進制數據建立一張圖片,你可使用以下代碼:

 
   
>>> from PIL import Image
>>> from io import BytesIO

>>> i = Image.open(BytesIO(r.content))
 
  

JSON 響應內容

Requests 中也有一個內置的 JSON 解碼器,助你處理 JSON 數據:

 
   
>>> import requests

>>> r = requests.get('https://api.github.com/events')
>>> r.json()
[{u'repository': {u'open_issues': 0, u'url': 'https://github.com/...

若是 JSON 解碼失敗, r.json() 就會拋出一個異常。例如,響應內容是 401 (Unauthorized),嘗試訪問 r.json() 將會拋出 ValueError: No JSON object could be decoded 異常。

須要注意的是,成功調用 r.json() 並**不**意味着響應的成功。有的服務器會在失敗的響應中包含一個 JSON 對象(好比 HTTP 500 的錯誤細節)。這種 JSON 會被解碼返回。要檢查請求是否成功,請使用 r.raise_for_status() 或者檢查 r.status_code 是否和你的指望相同。

原始響應內容

在罕見的狀況下,你可能想獲取來自服務器的原始套接字響應,那麼你能夠訪問 r.raw。 若是你確實想這麼幹,那請你確保在初始請求中設置了 stream=True。具體你能夠這麼作:

 
   
>>> r = requests.get('https://api.github.com/events', stream=True)
>>> r.raw
<requests.packages.urllib3.response.HTTPResponse object at 0x101194810>
>>> r.raw.read(10)
'\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\x03'
 
  

但通常狀況下,你應該如下面的模式將文本流保存到文件:

 
   
with open(filename, 'wb') as fd:
    for chunk in r.iter_content(chunk_size):
        fd.write(chunk)
 
   
 
  

使用 Response.iter_content 將會處理大量你直接使用 Response.raw 不得不處理的。 當流下載時,上面是優先推薦的獲取內容方式。 Note that chunk_size can be freely adjusted to a number that may better fit your use cases.

定製請求頭

若是你想爲請求添加 HTTP 頭部,只要簡單地傳遞一個 dict 給 headers 參數就能夠了。

例如,在前一個示例中咱們沒有指定 content-type:

 
   
>>> url = 'https://api.github.com/some/endpoint'
>>> headers = {'user-agent': 'my-app/0.0.1'}

>>> r = requests.get(url, headers=headers)
 
  

注意: 定製 header 的優先級低於某些特定的信息源,例如:

  • 若是在 .netrc 中設置了用戶認證信息,使用 headers= 設置的受權就不會生效。而若是設置了 auth= 參數,``.netrc`` 的設置就無效了。
  • 若是被重定向到別的主機,受權 header 就會被刪除。
  • 代理受權 header 會被 URL 中提供的代理身份覆蓋掉。
  • 在咱們能判斷內容長度的狀況下,header 的 Content-Length 會被改寫。

更進一步講,Requests 不會基於定製 header 的具體狀況改變本身的行爲。只不過在最後的請求中,全部的 header 信息都會被傳遞進去。

注意: 全部的 header 值必須是 string、bytestring 或者 unicode。儘管傳遞 unicode header 也是容許的,但不建議這樣作。

更加複雜的 POST 請求

一般,你想要發送一些編碼爲表單形式的數據——很是像一個 HTML 表單。要實現這個,只需簡單地傳遞一個字典給 data 參數。你的數據字典在發出請求時會自動編碼爲表單形式:

 
   
>>> payload = {'key1': 'value1', 'key2': 'value2'}

>>> r = requests.post("http://httpbin.org/post", data=payload)
>>> print(r.text)
{
  ...
  "form": {
    "key2": "value2",
    "key1": "value1"
  },
  ...
}
 
  

你還能夠爲 data 參數傳入一個元組列表。在表單中多個元素使用同一 key 的時候,這種方式尤爲有效:

 
   
>>> payload = (('key1', 'value1'), ('key1', 'value2'))
>>> r = requests.post('http://httpbin.org/post', data=payload)
>>> print(r.text)
{
  ...
  "form": {
    "key1": [
      "value1",
      "value2"
    ]
  },
  ...
}
 
   

  

 
  

不少時候你想要發送的數據並不是編碼爲表單形式的。若是你傳遞一個 string 而不是一個 dict,那麼數據會被直接發佈出去。

例如,Github API v3 接受編碼爲 JSON 的 POST/PATCH 數據:

 
   
>>> import json

>>> url = 'https://api.github.com/some/endpoint'
>>> payload = {'some': 'data'}

>>> r = requests.post(url, data=json.dumps(payload))

此處除了能夠自行對 dict 進行編碼,你還可使用 json 參數直接傳遞,而後它就會被自動編碼。這是 2.4.2 版的新加功能:

 
   
>>> url = 'https://api.github.com/some/endpoint'
>>> payload = {'some': 'data'}

>>> r = requests.post(url, json=payload)

POST一個多部分編碼(Multipart-Encoded)的文件

Requests 使得上傳多部分編碼文件變得很簡單:

 
   
>>> url = 'http://httpbin.org/post'
>>> files = {'file': open('report.xls', 'rb')}

>>> r = requests.post(url, files=files)
>>> r.text
{
  ...
  "files": {
    "file": "<censored...binary...data>"
  },
  ...
}
 
   

  

 
  

你能夠顯式地設置文件名,文件類型和請求頭:

 
   
>>> url = 'http://httpbin.org/post'
>>> files = {'file': ('report.xls', open('report.xls', 'rb'), 'application/vnd.ms-excel', {'Expires': '0'})}

>>> r = requests.post(url, files=files)
>>> r.text
{
  ...
  "files": {
    "file": "<censored...binary...data>"
  },
  ...
}
 
  

若是你想,你也能夠發送做爲文件來接收的字符串:

 
   
>>> url = 'http://httpbin.org/post'
>>> files = {'file': ('report.csv', 'some,data,to,send\nanother,row,to,send\n')}

>>> r = requests.post(url, files=files)
>>> r.text
{
  ...
  "files": {
    "file": "some,data,to,send\\nanother,row,to,send\\n"
  },
  ...
}
 
   

  

 
  

若是你發送一個很是大的文件做爲 multipart/form-data 請求,你可能但願將請求作成數據流。默認下 requests 不支持, 但有個第三方包 requests-toolbelt 是支持的

響應狀態碼

咱們能夠檢測響應狀態碼:

 
   
>>> r = requests.get('http://httpbin.org/get')
>>> r.status_code
200
 
  

爲方便引用,Requests還附帶了一個內置的狀態碼查詢對象:

 
   
>>> r.status_code == requests.codes.ok
True
 
  

若是發送了一個錯誤請求(一個 4XX 客戶端錯誤,或者 5XX 服務器錯誤響應),咱們能夠經過Response.raise_for_status() 來拋出異常:

 
   
>>> bad_r = requests.get('http://httpbin.org/status/404')
>>> bad_r.status_code
404

>>> bad_r.raise_for_status()
Traceback (most recent call last):
  File "requests/models.py", line 832, in raise_for_status
    raise http_error
requests.exceptions.HTTPError: 404 Client Error
 
   

  

 
  

可是,因爲咱們的例子中 r 的 status_code 是 200 ,當咱們調用 raise_for_status() 時,獲得的是:

 
   
>>> r.raise_for_status()
None
 
   

  

 
  

一切都挺和諧哈。

響應頭

咱們能夠查看以一個 Python 字典形式展現的服務器響應頭:

 
   
>>> r.headers
{
    'content-encoding': 'gzip',
    'transfer-encoding': 'chunked',
    'connection': 'close',
    'server': 'nginx/1.0.4',
    'x-runtime': '148ms',
    'etag': '"e1ca502697e5c9317743dc078f67693f"',
    'content-type': 'application/json'
}
 
   

  

 
  

可是這個字典比較特殊:它是僅爲 HTTP 頭部而生的。根據 RFC 2616, HTTP 頭部是大小寫不敏感的。

所以,咱們可使用任意大寫形式來訪問這些響應頭字段:

 
   
>>> r.headers['Content-Type']
'application/json'

>>> r.headers.get('content-type')
'application/json'
 
  
相關文章
相關標籤/搜索