Python request 簡單使用


Requests 是用Python語言編寫,基於 urllib,采用 Apache2 Licensed 開源協議的 HTTP 庫。它比 urllib 更加方便,可以節約我們大量的工作,完全滿足 HTTP 測試需求。Requests 的哲學是以 PEP 20 的習語為中心開發的,所以它比 urllib 更加 Pythoner。更重要的一點是它支持 Python3 哦!

發送請求

使用 Requests 發送網絡請求非常簡單。

一開始要導入 Requests 模塊:

import requests
 
          

然后,嘗試獲取某個網頁。本例子中,我們來獲取 Github 的公共時間線:

 

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

 

現在,我們有一個名為 r 的 Response 對象。我們可以從這個對象中獲取所有我們想要的信息。

Requests 簡便的 API 意味着所有 HTTP 請求類型都是顯而易見的。例如,你可以這樣發送一個 HTTP POST 請求:

 
           
>>> 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 ,那么你可以使用如下代碼:

 
           
>>> 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'
 
          
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM