源 / 代碼與藝術(shù) && 編程禪師 requests 庫(kù)是用來(lái)在Python中發(fā)出標(biāo)準(zhǔn)的HTTP請(qǐng)求。它將請(qǐng)求背后的復(fù)雜性抽象成一個(gè)漂亮,簡(jiǎn)單的API,以便你可以專注于與服務(wù)交互和在應(yīng)用程序中使用數(shù)據(jù)。 在本文中,你將看到 requests 提供的一些有用的功能,以及如何針對(duì)你可能遇到的不同情況來(lái)自定義和優(yōu)化這些功能。你還將學(xué)習(xí)如何有效的使用 requests ,以及如何防止對(duì)外部服務(wù)的請(qǐng)求導(dǎo)致減慢應(yīng)用程序的速度。 在本教程中,你將學(xué)習(xí)如何: 使用常見(jiàn)的HTTP方法發(fā)送請(qǐng)求 定制你的請(qǐng)求頭和數(shù)據(jù),使用查詢字符串和消息體 檢查你的請(qǐng)求和響應(yīng)的數(shù)據(jù) 發(fā)送帶身份驗(yàn)證的請(qǐng)求 配置你的請(qǐng)求來(lái)避免阻塞或減慢你的應(yīng)用程序
雖然我試圖包含盡可能多的信息來(lái)理解本文中包含的功能和示例,但閱讀此文需要對(duì)HTTP有基礎(chǔ)的了解。 現(xiàn)在讓我們深入了解如何在你的應(yīng)用程序中使用請(qǐng)求! 開始使用 requests讓我們首先安裝 requests 庫(kù)。為此,請(qǐng)運(yùn)行以下命令: 如果你喜歡使用 Pipenv 管理Python包,你可以運(yùn)行下面的命令: pipenv install requests
一旦安裝了 requests ,你就可以在應(yīng)用程序中使用它。像這樣導(dǎo)入 requests : 現(xiàn)在你已經(jīng)都準(zhǔn)備完成了,那么是時(shí)候開始使用 requests 的旅程了。你的第一個(gè)目標(biāo)是學(xué)習(xí)如何發(fā)出GET請(qǐng)求。
GET 請(qǐng)求HTTP方法(如GET和POST)決定當(dāng)發(fā)出HTTP請(qǐng)求時(shí)嘗試執(zhí)行的操作。除了GET和POST之外,還有其他一些常用的方法,你將在本教程的后面部分使用到。 最常見(jiàn)的HTTP方法之一是GET。GET方法表示你正在嘗試從指定資源獲取或檢索數(shù)據(jù)。要發(fā)送GET請(qǐng)求,請(qǐng)調(diào)用 requests.get() 。 你可以通過(guò)下面方式來(lái)向GitHub的 Root REST API 發(fā)出GET請(qǐng)求: >>> requests.get( https://api.github.com )
<Response [200]>
恭喜!你發(fā)出了你的第一個(gè)請(qǐng)求。接下來(lái)讓我們更深入地了解該請(qǐng)求的響應(yīng)。
響應(yīng)Response 是檢查請(qǐng)求結(jié)果的強(qiáng)有力的對(duì)象。讓我們?cè)俅伟l(fā)出相同的請(qǐng)求,但這次將返回值存儲(chǔ)在一個(gè)變量中,以便你可以仔細(xì)查看其屬性和方法:
>>> response = requests.get( https://api.github.com )
在此示例中,你捕獲了 get() 的返回值,該值是 Response 的實(shí)例,并將其存儲(chǔ)在名為 response 的變量中。你現(xiàn)在可以使用 response 來(lái)查看有關(guān)GET請(qǐng)求結(jié)果的全部信息。 狀態(tài)碼您可以從 Response 獲取的第一部分信息是狀態(tài)碼。狀態(tài)碼會(huì)展示你請(qǐng)求的狀態(tài)。 例如, 200OK 狀態(tài)表示你的請(qǐng)求成功,而 404NOT FOUND 狀態(tài)表示找不到你要查找的資源。還有許多其它的狀態(tài)碼 ,可以為你提供關(guān)于你的請(qǐng)求所發(fā)生的具體情況。 通過(guò)訪問(wèn) .status_code ,你可以看到服務(wù)器返回的狀態(tài)碼: >>> response.status_code
200
.status_code 返回 200 意味著你的請(qǐng)求是成功的,并且服務(wù)器返回你要請(qǐng)求的數(shù)據(jù)。
有時(shí),你可能想要在代碼中使用這些信息來(lái)做判斷: if response.status_code == 200:
print( Success! )
elif response.status_code == 404:
print( Not Found. )
按照這個(gè)邏輯,如果服務(wù)器返回 200 狀態(tài)碼,你的程序?qū)⒋蛴?Success! 如果結(jié)果是 404 ,你的程序?qū)⒋蛴?NotFound. 。 requests 更進(jìn)一步為你簡(jiǎn)化了此過(guò)程。如果在條件表達(dá)式中使用 Response 實(shí)例,則在狀態(tài)碼介于 200 和 400 之間時(shí)將被計(jì)算為為 True ,否則為 False 。
因此,你可以通過(guò)重寫 if 語(yǔ)句來(lái)簡(jiǎn)化上一個(gè)示例: if response:
print( Success! )
else:
print( An error has occurred. )
技術(shù)細(xì)節(jié) : 因?yàn)?__bool__() 是 Response 上的重載方法 ,因此真值測(cè)試才成立。 這意味著重新定義了 Response 的默認(rèn)行為,用來(lái)在確定對(duì)象的真值時(shí)考慮狀態(tài)碼。
請(qǐng)記住,此方法 不會(huì)驗(yàn)證 狀態(tài)碼是否等于 200 。原因是 200 到 400 范圍內(nèi)的其他狀態(tài)代碼,例如 204NO CONTENT 和 304NOT MODIFIED ,就意義而言也被認(rèn)為是成功的響應(yīng)。 例如, 204 告訴你響應(yīng)是成功的,但是下消息體中沒(méi)有返回任何內(nèi)容。 因此,通常如果你想知道請(qǐng)求是否成功時(shí),請(qǐng)確保使用這方便的簡(jiǎn)寫,然后在必要時(shí)根據(jù)狀態(tài)碼適當(dāng)?shù)靥幚眄憫?yīng)。 假設(shè)你不想在 if 語(yǔ)句中檢查響應(yīng)的狀態(tài)碼。相反,如果請(qǐng)求不成功,你希望拋出一個(gè)異常。你可以使用 .raise_for_status() 執(zhí)行此操作: import requests
from requests.exceptions import HTTPError
for url in [ https://api.github.com , https://api.github.com/invalid ]:
try:
response = requests.get(url)
# If the response was successful, no Exception will be raised
response.raise_for_status()
except HTTPError as http_err:
print(f HTTP error occurred: {http_err} ) # Python 3.6
except Exception as err:
print(f Other error occurred: {err} ) # Python 3.6
else:
print( Success! )
如果你調(diào)用 .raise_for_status() ,將針對(duì)某些狀態(tài)碼引發(fā) HTTPError 異常。如果狀態(tài)碼指示請(qǐng)求成功,則程序?qū)⒗^續(xù)進(jìn)行而不會(huì)引發(fā)該異常。 進(jìn)一步閱讀:如果你不熟悉Python 3.6的 f-strings,我建議你使用它們,因?yàn)樗鼈兪呛?jiǎn)化格式化字符串的好方法。
現(xiàn)在,你對(duì)于如何處理從服務(wù)器返回的響應(yīng)的狀態(tài)碼了解了許多。但是,當(dāng)你發(fā)出GET請(qǐng)求時(shí),你很少只關(guān)心響應(yīng)的狀態(tài)碼。通常,你希望看到更多。接下來(lái),你將看到如何查看服務(wù)器在響應(yīng)正文中返回的實(shí)際數(shù)據(jù)。 響應(yīng)內(nèi)容GET 請(qǐng)求的響應(yīng)通常在消息體中具有一些有價(jià)值的信息,稱為有效負(fù)載。使用 Response 的屬性和方法,你可以以各種不同的格式查看有效負(fù)載。
要以 字節(jié) 格式查看響應(yīng)的內(nèi)容,你可以使用 .content : >>> response = requests.get( https://api.github.com )
>>> response.content
b {'current_user_url':'https://api.github.com/user','current_user_authorizations_html_url':'https://github.com/settings/connections/applications{/client_id}','authorizations_url':'https://api.github.com/authorizations','code_search_url':'https://api.github.com/search/code?q={query}{&page,per_page,sort,order}','commit_search_url':'https://api.github.com/search/commits?q={query}{&page,per_page,sort,order}','emails_url':'https://api.github.com/user/emails','emojis_url':'https://api.github.com/emojis','events_url':'https://api.github.com/events','feeds_url':'https://api.github.com/feeds','followers_url':'https://api.github.com/user/followers','following_url':'https://api.github.com/user/following{/target}','gists_url':'https://api.github.com/gists{/gist_id}','hub_url':'https://api.github.com/hub','issue_search_url':'https://api.github.com/search/issues?q={query}{&page,per_page,sort,order}','issues_url':'https://api.github.com/issues','keys_url':'https://api.github.com/user/keys','notifications_url':'https://api.github.com/notifications','organization_repositories_url':'https://api.github.com/orgs/{org}/repos{?type,page,per_page,sort}','organization_url':'https://api.github.com/orgs/{org}','public_gists_url':'https://api.github.com/gists/public','rate_limit_url':'https://api.github.com/rate_limit','repository_url':'https://api.github.com/repos/{owner}/{repo}','repository_search_url':'https://api.github.com/search/repositories?q={query}{&page,per_page,sort,order}','current_user_repositories_url':'https://api.github.com/user/repos{?type,page,per_page,sort}','starred_url':'https://api.github.com/user/starred{/owner}{/repo}','starred_gists_url':'https://api.github.com/gists/starred','team_url':'https://api.github.com/teams','user_url':'https://api.github.com/users/{user}','user_organizations_url':'https://api.github.com/user/orgs','user_repositories_url':'https://api.github.com/users/{user}/repos{?type,page,per_page,sort}','user_search_url':'https://api.github.com/search/users?q={query}{&page,per_page,sort,order}'}
雖然 .content 允許你訪問(wèn)響應(yīng)有效負(fù)載的原始字節(jié),但你通常希望使用 UTF-8 等字符編碼將它們轉(zhuǎn)換為字符串。當(dāng)你訪問(wèn) .text 時(shí), response 將為你執(zhí)行此操作: >>> response.text
{'current_user_url':'https://api.github.com/user','current_user_authorizations_html_url':'https://github.com/settings/connections/applications{/client_id}','authorizations_url':'https://api.github.com/authorizations','code_search_url':'https://api.github.com/search/code?q={query}{&page,per_page,sort,order}'...}'}
因?yàn)閷?duì) bytes 解碼到 str 需要一個(gè)編碼格式,所以如果你沒(méi)有指定,請(qǐng)求將嘗試根據(jù)響應(yīng)頭來(lái)猜測(cè)編碼格式。你也可以在訪問(wèn) .text 之前通過(guò) .encoding 來(lái)顯式設(shè)置編碼: >>> response.encoding = utf-8 # Optional: requests infers this internally
>>> response.text
{'current_user_url':'https://api.github.com/user','current_user_authorizations_html_url':'https://github.com/settings/connections/applications{/client_id}','authorizations_url':'https://api.github.com/authorizations','code_search_url':'https://api.github.com/search/code?q={query}{&page,per_page,sort,order}'...}'}
如果你看看響應(yīng),你會(huì)發(fā)現(xiàn)它實(shí)際上是序列化的 JSON 內(nèi)容。要獲取字典內(nèi)容,你可以使用 .text 獲取 str 并使用 json.loads() 對(duì)其進(jìn)行反序列化。但是,完成此任務(wù)的更簡(jiǎn)單方法是使用 .json() : >>> response.json()
{ current_user_url : https://api.github.com/user , current_user_authorizations_html_url : https://github.com/settings/connections/applications{/client_id} ...} }
.json() 返回值的類型是字典類型,因此你可以使用鍵值對(duì)的方式訪問(wèn)對(duì)象中的值。
你可以使用狀態(tài)碼和消息體做許多事情。但是,如果你需要更多信息,例如有關(guān) response 本身的元數(shù)據(jù),則需要查看響應(yīng)頭部。 響應(yīng)頭部響應(yīng)頭部可以為你提供有用的信息,例如響應(yīng)有效負(fù)載的內(nèi)容類型以及緩存響應(yīng)的時(shí)間限制。要查看這些頭部,請(qǐng)?jiān)L問(wèn) .headers : >>> response.headers
{ Server : GitHub.com , Date : Mon, 10 Dec 2018 17:49:54 GMT , Content-Type : application/json; charset=utf-8 ,...}
.headers 返回類似字典的對(duì)象,允許你使用鍵來(lái)獲取頭部中的值。例如,要查看響應(yīng)有效負(fù)載的內(nèi)容類型,你可以訪問(wèn) Content-Type :
>>> response.headers[ Content-Type ]
application/json; charset=utf-8
但是,這個(gè)類似于字典的頭部對(duì)象有一些特別之處。HTTP規(guī)范定義頭部不區(qū)分大小寫,這意味著我們可以訪問(wèn)這些頭信息而不必?fù)?dān)心它們的大小寫: >>> response.headers[ content-type ]
application/json; charset=utf-8
無(wú)論您使用 content-type 還是 Content-Type ,你都將獲得相同的值。 現(xiàn)在,你已經(jīng)學(xué)習(xí)了有關(guān) Response 的基礎(chǔ)知識(shí)。你已經(jīng)看到了它最有用的屬性和方法。讓我們退后一步,看看自定義 GET 請(qǐng)求時(shí)你的響應(yīng)如何變化。
查詢字符串參數(shù)自定義 GET 請(qǐng)求的一種常用方法是通過(guò)URL中的 查詢字符串 參數(shù)傳遞值。要使用 get() 執(zhí)行此操作,請(qǐng)將數(shù)據(jù)傳遞給 params 。例如,你可以使用GitHub的Search API來(lái)查找 requests 庫(kù): import requests
# Search GitHub s repositories for requests
response = requests.get(
https://api.github.com/search/repositories ,
params={ q : requests+language:python },
)
# Inspect some attributes of the `requests` repository
json_response = response.json()
repository = json_response[ items ][0]
print(f Repository name: {repository['name']} ) # Python 3.6+
print(f Repository description: {repository['description']} ) # Python 3.6+
通過(guò)將字典 { q :requests + language:python } 傳遞給 .get() 的 params 參數(shù),你可以修改從Search API返回的結(jié)果。 你可以像你剛才那樣以字典的形式或以元組列表形式將 params 傳遞給 get() : >>> requests.get(
... https://api.github.com/search/repositories ,
... params=[( q , requests+language:python )],
... )
<Response [200]>
你甚至可以傳 bytes 作為值: >>> requests.get(
... https://api.github.com/search/repositories ,
... params=b q=requests+language:python ,
... )
<Response [200]>
查詢字符串對(duì)于參數(shù)化GET請(qǐng)求很有用。你還可以通過(guò)添加或修改發(fā)送的請(qǐng)求的頭部來(lái)自定義你的請(qǐng)求。
請(qǐng)求頭要自定義請(qǐng)求頭,你可以使用 headers 參數(shù)將HTTP頭部組成的字典傳遞給 get() 。例如,你可以通過(guò) Accept 中指定文本匹配媒體類型來(lái)更改以前的搜索請(qǐng)求,以在結(jié)果中突出顯示匹配的搜索字詞: import requests
response = requests.get(
https://api.github.com/search/repositories ,
params={ q : requests+language:python },
headers={ Accept : application/vnd.github.v3.text-match+json },
)
# View the new `text-matches` array which provides information
# about your search term within the results
json_response = response.json()
repository = json_response[ items ][0]
print(f Text matches: {repository['text_matches']} )
Accept 告訴服務(wù)器你的應(yīng)用程序可以處理哪些內(nèi)容類型。由于你希望突出顯示匹配的搜索詞,所以使用的是 application/vnd.github.v3.text-match+json ,這是一個(gè)專有的GitHub的 Accept 標(biāo)頭,其內(nèi)容為特殊的JSON格式。
在你了解更多自定義請(qǐng)求的方法之前,讓我們通過(guò)探索其他HTTP方法來(lái)拓寬視野。
其他HTTP方法除了 GET 之外,其他流行的HTTP方法包括 POST , `PUT , DELETE , HEAD , PATCH 和 OPTIONS 。requests 為每個(gè)HTTP方法提供了一個(gè)方法,與 get() `具有類似的結(jié)構(gòu): >>> requests.post( https:///post , data={ key : value })
>>> requests.put( https:///put , data={ key : value })
>>> requests.delete( https:///delete )
>>> requests.head( https:///get )
>>> requests.patch( https:///patch , data={ key : value })
>>> requests.options( https:///get )
調(diào)用每個(gè)函數(shù)使用相應(yīng)的HTTP方法向httpbin服務(wù)發(fā)出請(qǐng)求。對(duì)于每種方法,你可以像以前一樣查看其響應(yīng): >>> response = requests.head( https:///get )
>>> response.headers[ Content-Type ]
application/json
>>> response = requests.delete( https:///delete )
>>> json_response = response.json()
>>> json_response[ args ]
{}
每種方法的響應(yīng)中都會(huì)返回頭部,響應(yīng)正文,狀態(tài)碼等。接下來(lái),你將進(jìn)一步了解 POST , `PUT 和 PATCH 方法,并了解它們與其他請(qǐng)求類型的區(qū)別。
消息體根據(jù)HTTP規(guī)范, POST , `PUT 和不太常見(jiàn)的 PATCH 請(qǐng)求通過(guò)消息體而不是通過(guò)查詢字符串參數(shù)傳遞它們的數(shù)據(jù)。使用 requests ,你將有效負(fù)載傳遞給相應(yīng)函數(shù)的 data 參數(shù)。 data 接收字典,元組列表,字節(jié)或類文件對(duì)象。你需要將在請(qǐng)求正文中發(fā)送的數(shù)據(jù)調(diào)整為與你交互的服務(wù)的特定格式。
例如,如果你的請(qǐng)求的內(nèi)容類型是 application/x-www-form-urlencoded ,則可以將表單數(shù)據(jù)作為字典發(fā)送: >>> requests.post( https:///post , data={ key : value })
<Response [200]>
你還可以將相同的數(shù)據(jù)作為元組列表發(fā)送: >>> requests.post( https:///post , data=[( key , value )])
<Response [200]>
但是,如果需要發(fā)送JSON數(shù)據(jù),則可以使用 json 參數(shù)。當(dāng)你通過(guò) json 傳遞JSON數(shù)據(jù)時(shí), requests 將序列化你的數(shù)據(jù)并為你添加正確的 Content-Type 標(biāo)頭。 是 requests 作者 Kenneth Reitz 創(chuàng)建的一個(gè)很好的資源。它是一種接收測(cè)試請(qǐng)求并響應(yīng)有關(guān)請(qǐng)求數(shù)據(jù)的服務(wù)。例如,你可以使用它來(lái)檢查基本的POST請(qǐng)求: >>> response = requests.post( https:///post , json={ key : value })
>>> json_response = response.json()
>>> json_response[ data ]
{'key': 'value'}
>>> json_response[ headers ][ Content-Type ]
application/json
你可以從響應(yīng)中看到服務(wù)器在你發(fā)送請(qǐng)求時(shí)收到了請(qǐng)求數(shù)據(jù)和標(biāo)頭。requests 還以 PreparedRequest 的形式向你提供此信息。
檢查你的請(qǐng)求當(dāng)你發(fā)出請(qǐng)求時(shí), requests 庫(kù)會(huì)在將請(qǐng)求實(shí)際發(fā)送到目標(biāo)服務(wù)器之前準(zhǔn)備該請(qǐng)求。請(qǐng)求準(zhǔn)備包括像驗(yàn)證頭信息和序列化JSON內(nèi)容等。 你可以通過(guò)訪問(wèn) .request 來(lái)查看 PreparedRequest : >>> response = requests.post( https:///post , json={ key : value })
>>> response.request.headers[ Content-Type ]
application/json
>>> response.request.url
https:///post
>>> response.request.body
b {'key': 'value'}
通過(guò)檢查 PreparedRequest ,你可以訪問(wèn)有關(guān)正在進(jìn)行的請(qǐng)求的各種信息,例如有效負(fù)載,URL,頭信息,身份驗(yàn)證等。 到目前為止,你已經(jīng)發(fā)送了許多不同類型的請(qǐng)求,但它們都有一個(gè)共同點(diǎn):它們是對(duì)公共API的未經(jīng)身份驗(yàn)證的請(qǐng)求。你遇到的許多服務(wù)可能都希望你以某種方式進(jìn)行身份驗(yàn)證。
身份驗(yàn)證身份驗(yàn)證可幫助服務(wù)了解你的身份。通常,你通過(guò)將數(shù)據(jù)傳遞到 Authorization 頭信息或服務(wù)定義的自定義頭信息來(lái)向服務(wù)器提供憑據(jù)。你在此處看到的所有請(qǐng)求函數(shù)都提供了一個(gè)名為 auth 的參數(shù),允許你傳遞憑據(jù)。 需要身份驗(yàn)證的一個(gè)示例API的是GitHub的 Authenticated User API。此端點(diǎn)提供有關(guān)經(jīng)過(guò)身份驗(yàn)證的用戶配置文件的信息。要向 AuthenticatedUserAPI 發(fā)出請(qǐng)求,你可以將你的GitHub的用戶名和密碼以元組傳遞給 get() : >>> from getpass import getpass
>>> requests.get( https://api.github.com/user , auth=( username , getpass()))
<Response [200]>
如果你在元組中傳遞給 auth 的憑據(jù)有效,則請(qǐng)求成功。如果你嘗試在沒(méi)有憑據(jù)的情況下發(fā)出此請(qǐng)求,你將看到狀態(tài)代碼為 401Unauthorized : >>> requests.get( https://api.github.com/user )
<Response [401]>
當(dāng)你以元組形式吧用戶名和密碼傳遞給 auth 參數(shù)時(shí), rqeuests 將使用HTTP的基本訪問(wèn)認(rèn)證方案來(lái)應(yīng)用憑據(jù)。 因此,你可以通過(guò)使用 HTTPBasicAuth 傳遞顯式的基本身份驗(yàn)證憑據(jù)來(lái)發(fā)出相同的請(qǐng)求: >>> from requests.auth import HTTPBasicAuth
>>> from getpass import getpass
>>> requests.get(
... https://api.github.com/user ,
... auth=HTTPBasicAuth( username , getpass())
... )
<Response [200]>
雖然你不需要明確進(jìn)行基本身份驗(yàn)證,但你可能希望使用其他方法進(jìn)行身份驗(yàn)證。requests 提供了開箱即用的其他身份驗(yàn)證方法,例如 HTTPDigestAuth 和 HTTPProxyAuth 。 你甚至可以提供自己的身份驗(yàn)證機(jī)制。為此,你必須首先創(chuàng)建AuthBase的子類。然后,實(shí)現(xiàn) __call __() : import requests
from requests.auth import AuthBase
class TokenAuth(AuthBase):
'''Implements a custom authentication scheme.'''
def __init__(self, token):
self.token = token
def __call__(self, r):
'''Attach an API token to a custom auth header.'''
r.headers[ X-TokenAuth ] = f {self.token} # Python 3.6+
return r
requests.get( https:///get , auth=TokenAuth( 12345abcde-token ))
在這里,你自定義的 TokenAuth 接收一個(gè)令牌,然后在你的請(qǐng)求頭中的 X-TokenAuth 頭中包含該令牌。 錯(cuò)誤的身份驗(yàn)證機(jī)制可能會(huì)導(dǎo)致安全漏洞,因此,除非服務(wù)因某種原因需要自定義身份驗(yàn)證機(jī)制,否則你始終希望使用像 Basic 或 OAuth 這樣經(jīng)過(guò)驗(yàn)證的身份驗(yàn)證方案。 在考慮安全性時(shí),讓我們考慮使用 requests 處理SSL證書。
SSL證書驗(yàn)證每當(dāng)你嘗試發(fā)送或接收的數(shù)據(jù)都很敏感時(shí),安全性就很重要。通過(guò)HTTP與站點(diǎn)安全通信的方式是使用SSL建立加密連接,這意味著驗(yàn)證目標(biāo)服務(wù)器的SSL證書至關(guān)重要。 好消息是 requests 默認(rèn)為你執(zhí)行此操作。但是,在某些情況下,你可能希望更改此行為。 如果要禁用SSL證書驗(yàn)證,請(qǐng)將 False 傳遞給請(qǐng)求函數(shù)的 verify 參數(shù): >>> requests.get( https://api.github.com , verify=False)
InsecureRequestWarning: Unverified HTTPS request is being made. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#ssl-warnings
InsecureRequestWarning)
<Response [200]>
當(dāng)你提出不安全的請(qǐng)求時(shí), requests 甚至?xí)l(fā)出警告來(lái)幫助你保護(hù)數(shù)據(jù)安全。
性能在使用 requests 時(shí),尤其是在生產(chǎn)應(yīng)用程序環(huán)境中,考慮性能影響非常重要。超時(shí)控制,會(huì)話和重試限制等功能可以幫助你保持應(yīng)用程序平穩(wěn)運(yùn)行。 超時(shí)控制當(dāng)你向外部服務(wù)發(fā)出請(qǐng)求時(shí),系統(tǒng)將需要等待響應(yīng)才能繼續(xù)。如果你的應(yīng)用程序等待響應(yīng)的時(shí)間太長(zhǎng),則可能會(huì)阻塞對(duì)你的服務(wù)的請(qǐng)求,你的用戶體驗(yàn)可能會(huì)受到影響,或者你的后臺(tái)作業(yè)可能會(huì)掛起。 默認(rèn)情況下, requests 將無(wú)限期地等待響應(yīng),因此你幾乎應(yīng)始終指定超時(shí)時(shí)間以防止這些事情發(fā)生。要設(shè)置請(qǐng)求的超時(shí),請(qǐng)使用 timeout 參數(shù)。timeout 可以是一個(gè)整數(shù)或浮點(diǎn)數(shù),表示在超時(shí)之前等待響應(yīng)的秒數(shù): >>> requests.get( https://api.github.com , timeout=1)
<Response [200]>
>>> requests.get( https://api.github.com , timeout=3.05)
<Response [200]>
在第一個(gè)請(qǐng)求中,請(qǐng)求將在1秒后超時(shí)。在第二個(gè)請(qǐng)求中,請(qǐng)求將在3.05秒后超時(shí)。 你還可以將元組傳遞給 timeout ,第一個(gè)元素是連接超時(shí)(它允許客戶端與服務(wù)器建立連接的時(shí)間),第二個(gè)元素是讀取超時(shí)(一旦你的客戶已建立連接而等待響應(yīng)的時(shí)間): >>> requests.get( https://api.github.com , timeout=(2, 5))
<Response [200]>
如果請(qǐng)求在2秒內(nèi)建立連接并在建立連接的5秒內(nèi)接收數(shù)據(jù),則響應(yīng)將按原樣返回。如果請(qǐng)求超時(shí),則該函數(shù)將拋出 Timeout 異常: import requests
from requests.exceptions import Timeout
try:
response = requests.get( https://api.github.com , timeout=1)
except Timeout:
print( The request timed out )
else:
print( The request did not time out )
你的程序可以捕獲 Timeout 異常并做出相應(yīng)的響應(yīng)。 Session對(duì)象到目前為止,你一直在處理高級(jí)請(qǐng)求API,例如 get() 和 post() 。這些函數(shù)是你發(fā)出請(qǐng)求時(shí)所發(fā)生的事情的抽象。為了你不必?fù)?dān)心它們,它們隱藏了實(shí)現(xiàn)細(xì)節(jié),例如如何管理連接。 在這些抽象之下是一個(gè)名為 Session 的類。如果你需要微調(diào)對(duì)請(qǐng)求的控制方式或提高請(qǐng)求的性能,則可能需要直接使用 Session 實(shí)例。 Session 用于跨請(qǐng)求保留參數(shù)。例如,如果要跨多個(gè)請(qǐng)求使用相同的身份驗(yàn)證,則可以使用 session :
import requests
from getpass import getpass
# By using a context manager, you can ensure the resources used by
# the session will be released after use
with requests.Session() as session:
session.auth = ( username , getpass())
# Instead of requests.get(), you ll use session.get()
response = session.get( https://api.github.com/user )
# You can inspect the response just like you did before
print(response.headers)
print(response.json())
每次使用 session 發(fā)出請(qǐng)求時(shí),一旦使用身份驗(yàn)證憑據(jù)初始化,憑據(jù)將被保留。 session 的主要性能優(yōu)化以持久連接的形式出現(xiàn)。當(dāng)你的應(yīng)用程序使用 Session 建立與服務(wù)器的連接時(shí),它會(huì)在連接池中保持該連接。當(dāng)你的應(yīng)用程序想要再次連接到同一服務(wù)器時(shí),它將重用池中的連接而不是建立新連接。
最大重試請(qǐng)求失敗時(shí),你可能希望應(yīng)用程序重試相同的請(qǐng)求。但是,默認(rèn)情況下, requests 不會(huì)為你執(zhí)行此操作。要應(yīng)用此功能,您需要實(shí)現(xiàn)自定義 Transport Adapter。 通過(guò) TransportAdapters ,你可以為每個(gè)與之交互的服務(wù)定義一組配置。例如,假設(shè)你希望所有對(duì)于https://api.github.com的請(qǐng)求在最終拋出 ConnectionError 之前重試三次。你將構(gòu)建一個(gè) TransportAdapter ,設(shè)置其 max_retries 參數(shù),并將其裝載到現(xiàn)有的 Session : import requests
from requests.adapters import HTTPAdapter
from requests.exceptions import ConnectionError
github_adapter = HTTPAdapter(max_retries=3)
session = requests.Session()
# Use `github_adapter` for all requests to endpoints that start with this URL
session.mount( https://api.github.com , github_adapter)
try:
session.get( https://api.github.com )
except ConnectionError as ce:
print(ce)
當(dāng)您將 HTTPAdapter(github_adapter) 掛載到 session 時(shí), session 將遵循其對(duì)https://api.github.com的每個(gè)請(qǐng)求的配置。 Timeouts , TransportAdapters 和 Sessions 用于保持代碼高效和應(yīng)用程序的魯棒性。
總結(jié)在學(xué)習(xí)Python中強(qiáng)大的 requests 庫(kù)方面,你已經(jīng)走了很長(zhǎng)的路。 你現(xiàn)在能夠: 使用各種不同的HTTP方法發(fā)出請(qǐng)求,例如GET,POST和PUT 通過(guò)修改請(qǐng)求頭,身份驗(yàn)證,查詢字符串和消息體來(lái)自定義你的請(qǐng)求 檢查發(fā)送到服務(wù)器的數(shù)據(jù)以及服務(wù)器發(fā)回給你的數(shù)據(jù) 使用SSL證書驗(yàn)證 高效的使用 requests 通過(guò)使用 max_retries , timeout , Sessions 和 TransportAdapters
因?yàn)槟鷮W(xué)會(huì)了如何使用 requests ,所以你可以使用他們提供的迷人數(shù)據(jù)探索廣泛的Web服務(wù)世界并構(gòu)建出色的應(yīng)用程序了。
|