requests是Python中一個第三方庫,基於 urllib,採用 Apache2 Licensed 開源協議的 HTTP 庫。它比 urllib 更加方便,可以節約我們大量的工作,完全滿足 HTTP 測試需求。接下來將記錄一下requests的使用:
安裝
要使用requests
庫必須先要安裝:
pip install requests
創建請求
通過requests
庫發出一個請求非常簡單,首先我們先導入requests
庫:
import requests
現在我們嘗試創建一個請求,用來獲取百度的網頁信息:
result = requests.get('http://www.baidu.com/')
現在我們獲取到了一個Response
對象result
,我們可以從這個對象中獲得所有我們需要的所有信息。剛剛的栗子是使用的GET
請求,接下來將使用requests
庫進行POST
請求:
result = requests.post('http://www.baidu.com/',data={key:value})
很簡單對吧?那麼其他HTTP請求呢:PUT、DELETE、HEAD和OPTIONS呢?
result = requests.put('http://www.baidu.com/',data={key,value})
result = requests.head('http://www.baidu.com/')
result = requests.delete('http://www.baidu.com/')
result = requests.options('http://www.baidu.com/')
在URL中傳遞參數
你經常想要在URL的查詢字符串中發送某種數據。如果你手動構建網址,那麼這個數據會在問號後作爲網址中的鍵值對,例如https://www.baidu.com/s?wd=requests
。請求允許你使用params
關鍵字參數將這些參數作爲字符串字典提供。舉個栗子,你想傳遞name=zhangsan
並且age=18
到https://www.baidu.com/s
,你可以這樣寫:
data = {"name":"zhangsan","age":18}
result = requests.get("https://www.baidu.com/s",params=data)
此時我們打印一下URL,發現該URL已經被正確編碼:
print result.url # https://www.baidu.com/s?name=zhangsan&age=18
也可以傳遞一個列表進去:
data = {"name":"zhangsan","favorite":["football","basketball"]}
result = requests.get("https://www.baidu.com/s",params=data)
print result.url # https://www.baidu.com/s?name=zhangsan&favorite=football&favorite=basketball
響應內容
在上面的例子可以知道,我們每次請求之後都會返回一個對象,我們可以從此對象中獲取響應內容:
result = requests.get("https://api.github.com/events")
print result.text # [{"id":"6924608641","type":"PushEvent",...}]
- 二進制響應內容
print result.content # b'[{"id":"6924656608","type":"CreateEvent",...}]'
- JSON格式的響應內容,如果解碼失敗,
result.json()
將會引發異常
print result.json() # [{"id":"6924608641","type":"PushEvent",...}]
請求將自動解碼來自服務器的內容。大多數unicode字符集都是無縫解碼的。我們也可以根據如下方法獲取當前的編碼:
print result.encoding
如果響應的內容並不是你想要的編碼格式,你可以在調用result.text
之前,對result.encoding
進行賦值,給予新的編碼格式。
要檢查一個請求是否成功,使用result.raise_for_status()
或者result.status_code
來檢查是否你期望的
套接字響應
在極少數情況下,你希望從服務器中獲得是原始套接字響應,你可以通過result.raw
來獲取。如果你想這樣做,確保你設置stream=True
在你的初始請求。一旦你這樣操作了,你可以這樣:
result = requests.get("https://api.github.com/events",stream=True)
print result.raw # <urllib3.response.HTTPResponse object at 0x10ce52dd8>
print result.raw.read(10) # b'\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\x03'
通常情況下,我們使用如下這種模式來保存正在流式傳輸的內容:
with open("info.txt","wb") as f:
for item in result.iter_content(chunk_size=128):
f.write(item)
自定義頭部
如果你想將自定義請求頭添加到請求當中,只需要傳遞一個字典到headers
參數即可。例如,在請求中指定我們的請求代理:
header = {"user-agent":'my_test/0001'}
result = requests.get("https://api.github.com/events",headers=header)
注意,請求頭的值必須是一個字符串,byte類型的字符串或者unicode。雖然允許unicode,但還是避免使用unicode
複雜的post請求
通常情況下,你想要發送一些表單編碼數據,就像HTML表單一樣。要做到這一點,你只需要將字典傳遞給data
參數即可:
infoDict = {"name":"張三"}
result = requests.post('http://127.0.0.1:5000/test/post',data=infoDict)
你也可以傳遞一個元組數據:
tupleInfo = ("name","張三")
result = requests.post('http://127.0.0.1:5000/test/post',data=tupleInfo)
有時你需要發送一些非編碼格式的數據,即你發送的是一個string
而不是dict
,那麼數據將會直接發送:
import json
infoDict = {"name":"張三"}
result = requests.post('http://127.0.0.1:5000/test/post',data=json.dumps(infoDict))
如果你想要發送一個字典數據,你可以通過它使用json
參數,它會自動編碼:
infoDict = {"name":"張三"}
result = requests.post('http://127.0.0.1:5000/test/post',json=infoDict)
注意,如果你傳遞了data參數或者files,那麼json將會被忽略
post上傳文件
requests
上傳文件其實很簡單:
with open('info.txt','rb') as f:
result = requests.post('http://localhost:5000/post',files={"files":f})
響應狀態碼
我們執行完一個請求之後,我們可以使用如下方法查看狀態碼,檢測請求是否成功:
result = requests.get('http://localhost:5000/get')
print result.status_code # 200
當返回200,表示請求執行成功,我們還可以使用如下方法判斷請求是否成功,True爲成功,False不成功:
print result.staatus_code == requests.codes.ok # True
當我們執行一個錯誤的請求(4XX客戶端錯誤,5XX服務器錯誤)時,我們可以以下方法來拋出異常進行檢車:
result = requests.get('http://localhost:5000/get')
print result.status_code # 404
print result.raise_for_status() # Traceback (most recent call last): ...
但是如果我們的請求是執行成功的,即狀態碼爲200,此時raise_for_status()
的值將會是None
響應頭
我們可以使用Python字典來查看服務器的響應頭文件:
print result.headers # {'Content-Type': 'text/html; charset=utf-8', 'Content-Length': '2', 'Server': 'Werkzeug/0.12.2 Python/2.7.10', 'Date': 'Sun, 03 Dec 2017 14:15:32 GMT'}
Cookies
如果響應包含了Cookie,你可以這樣快速的訪問它:
result = requests.get('http://localhost:5000/get')
print result.cookies['userName']
或者你需要將自己的Cookie發送給服務器,你可以使用cookies參數:
cookie = {'userName':'zhangsan'}
result = requests.get('http://localhost:5000/get',cookies=cookie)
RequestCookieJar
提供了一個完整的接口,適合在多個域和路徑中使用,它將返回一個Cookie,所以它也可以被傳入到cookies
參數中
c = requests.cookies.RequestsCookieJar()
c.set('userName','zhangsan',domain='http://localhost:5000',path='/get')
result = requests.get('http://localhost:5000/get',cookies=c)
Session對象
Session對象允許你在請求中保存某些參數,它將在所有由會話實例創建的請求中保存Cookie,並將使用urllib3連接池。如果你想同一主機發出多個請求,則會重新使用底層的TCP連接,這將使性能顯著提高。Session具有主API的所有請求方法:
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"}}'
但是請注意,方法級參數不會保存在請求,即使使用一個session。這個栗子只會發送第一個請求的Cookie,不會發送第二個:
result = s.get('http://httpbin.org/cookies', cookies={'from-my': 'browser'})
print(result.text)
# '{"cookies": {"from-my": "browser"}}'
result = s.get('http://httpbin.org/cookies')
print(result.text)
# '{"cookies": {}}'
請求和響應對象
每當你發起一個GET
請求,你都在做兩件事。首先,構造一個Request
將被髮送到服務器的對象來請求或查詢某個資源。其次,Response
一旦從服務器中獲得響應,就會生成一個對象。該Response
對象包含服務器鎖返回的所有信息,並且還包含Request
你最初創建的對象。這是一個簡單的請求,從維基百科的服務器獲取一些非常重要的信息:
result = requests.get('http://en.wikipedia.org/wiki/Monty_Python')
現在我們需要獲取服務器發送給我們的頭文件信息:
print result.headers
如果我們需要獲取發送給服務器的頭文件信息,我們可以這樣:
print result.request.headers
SSL證書驗證
請求將驗證HTTPS請求的SSL證書,就像Web瀏覽器一樣。默認情況下,啓用SSL驗證,如果無法驗證SSL證書,將會引發SSLError:
result = reqests.get('https://kyfw.12306.cn/otn/login/init')
# requests.exceptions.SSLError: ("bad handshake: Error([('SSL routines', 'tls_process_server_certificate', 'certificate verify failed')],)",)
爲了避免出現這個錯誤,我們可以將CA證書的CA_BUNDLE文件或目錄傳遞給verify參數裏面:
result = reqests.get('https://kyfw.12306.cn/otn/login/init',verify='/path/...')
或者使用Session方式存儲起來:
s = Session()
s.verify='/path/...'
result = s.get('https://kyfw.12306.cn/otn/login/init')
如果將verify參數設置爲False,請求也可以忽略SSL證書:
result = requests.get('https://kyfw.12306.cn/otn/login/init',verify=False)