一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

Python實(shí)踐:Requests模塊

 CodeNutter 2016-08-04


參考:http://www./2013/01/13/python-requests/

比urllib好用的requests

requests-sidebarPython標(biāo)準(zhǔn)庫里提供了httplib以及urllib、urllib2,但是學(xué)習(xí)了好幾次,都沒有記?。ㄏ碌墓Ψ虿粔颍?。今天推薦了一個(gè)requests庫,看了一下樣例,幾乎立即就會(huì)使用了,所以推薦給大家。
看官方是怎么描述這種情況的:
“Python’s standard urllib2 module provides most of the HTTP capabilities you need, but the API is thoroughly broken. It was built for a different time — and a different web. It requires an enormous amount of work (even method overrides) to perform the simplest of tasks.

Things shouldn’t be this way. Not in Python.”

http://docs./en/latest/

可見urllib2確實(shí)不太容易使用。
常用功能羅列如下,以便查詢。

# 0. 認(rèn)證、狀態(tài)碼、header、編碼、json
>>> r = requests.get('https://api.github.com/user', auth=('user', 'pass'))
>>> r.status_code
200
>>> r.headers['content-type']
'application/json; charset=utf8'
>>> r.encoding
'utf-8'
>>> r.text
u'{"type":"User"...'
>>> r.json()
{u'private_gists': 419, u'total_private_repos': 77, ...}
# 1. 發(fā)起請(qǐng)求
import requests
URL="http://www./"
r = requests.get(URL)
r = requests.post(URL)
r = requests.put(URL)
r = requests.delete(URL)
r = requests.head(URL)
r = requests.options(URL)
# 2. 通過URL傳遞參數(shù)
>>> payload = {'key1': 'value1', 'key2': 'value2'}
>>> r = requests.get("http:///get", params=payload)
>>> print r.url
u'http:///get?key2=value2&key1=value1'
# 3. 返回內(nèi)容
>>> import requests
>>> r = requests.get('https://github.com/timeline.json')
>>> r.text
'[{"repository":{"open_issues":0,"url":"https://github.com/...
>>> r.encoding
'utf-8'
>>> r.encoding = 'ISO-8859-1'
# 4. 二進(jìn)制內(nèi)容
You can also access the response body as bytes, for non-text requests:

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

The gzip and deflate transfer-encodings are automatically decoded for you.

For example, to create an image from binary data returned by a request,
 ou can use the following code:

>>> from PIL import Image
>>> from StringIO import StringIO
>>> i = Image.open(StringIO(r.content))
# 5. JSON
>>> import requests
>>> r = requests.get('https://github.com/timeline.json')
>>> r.json()
[{u'repository': {u'open_issues': 0, u'url': 'https://github.com/...
# 6. 超時(shí)
>>> requests.get('http://github.com', timeout=0.001)
# 7. 自定義header
>>> import json
>>> url = 'https://api.github.com/some/endpoint'
>>> payload = {'some': 'data'}
>>> headers = {'content-type': 'application/json'}

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

參考:http://cn./en/latest/user/quickstart.html#id8

發(fā)送請(qǐng)求

使用Requests發(fā)送網(wǎng)絡(luò)請(qǐng)求非常簡單。

一開始要導(dǎo)入Requests模塊:

>>> import requests

然后,嘗試獲取某個(gè)網(wǎng)頁。本例子中,我們來獲取Github的公共時(shí)間線

>>> r = requests.get('https://github.com/timeline.json')

現(xiàn)在,我們有一個(gè)名為 r 的 Response 對(duì)象??梢詮倪@個(gè)對(duì)象中獲取所有我們想要的信息。

Requests簡便的API意味著所有HTTP請(qǐng)求類型都是顯而易見的。例如,你可以這樣發(fā)送一個(gè)HTTP POST請(qǐng)求:

>>> r = requests.post("http:///post")

漂亮,對(duì)吧?那么其他HTTP請(qǐng)求類型:PUT, DELETE, HEAD以及OPTIONS又是如何的呢?都是一樣的簡單:

>>> r = requests.put("http:///put")
>>> r = requests.delete("http:///delete")
>>> r = requests.head("http:///get")
>>> r = requests.options("http:///get")

都很不錯(cuò)吧,但這也僅是Requests的冰山一角呢。

為URL傳遞參數(shù)

你也許經(jīng)常想為URL的查詢字符串(query string)傳遞某種數(shù)據(jù)。如果你是手工構(gòu)建URL,那么數(shù)據(jù)會(huì)以鍵/值 對(duì)的形式置于URL中,跟在一個(gè)問號(hào)的后面。例如,/get?key=val 。 Requests允許你使用 params 關(guān)鍵字參數(shù),以一個(gè)字典來提供這些參數(shù)。舉例來說,如果你想傳遞 key1=value1 和 key2=value2 到 /get ,那么你可以使用如下代碼:

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

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

>>> print r.url
u'http:///get?key2=value2&key1=value1'

響應(yīng)內(nèi)容

我們能讀取服務(wù)器響應(yīng)的內(nèi)容。再次以Github時(shí)間線為例:

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

Requests會(huì)自動(dòng)解碼來自服務(wù)器的內(nèi)容。大多數(shù)unicode字符集都能被無縫地解碼。

請(qǐng)求發(fā)出后,Requests會(huì)基于HTTP頭部對(duì)響應(yīng)的編碼作出有根據(jù)的推測(cè)。當(dāng)你訪問r.text 之時(shí),Requests會(huì)使用其推測(cè)的文本編碼。你可以找出Requests使用了什么編碼,并且能夠使用 r.encoding 屬性來改變它:

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

如果你改變了編碼,每當(dāng)你訪問 r.text ,Request都將會(huì)使用 r.encoding 的新值。

在你需要的情況下,Requests也可以使用定制的編碼。如果你創(chuàng)建了自己的編碼,并使用codecs 模塊進(jìn)行注冊(cè),你就可以輕松地使用這個(gè)解碼器名稱作為 r.encoding 的值, 然后由Requests來為你處理編碼。

二進(jìn)制響應(yīng)內(nèi)容

你也能以字節(jié)的方式訪問請(qǐng)求響應(yīng)體,對(duì)于非文本請(qǐng)求:

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

Requests會(huì)自動(dòng)為你解碼 gzip 和 deflate 傳輸編碼的響應(yīng)數(shù)據(jù)。

例如,以請(qǐng)求返回的二進(jìn)制數(shù)據(jù)創(chuàng)建一張圖片,你可以使用如下代碼:

>>> from PIL import Image
>>> from StringIO import StringIO
>>> i = Image.open(StringIO(r.content))

JSON響應(yīng)內(nèi)容

Requests中也有一個(gè)內(nèi)置的JSON解碼器,助你處理JSON數(shù)據(jù):

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

如果JSON解碼失敗, r.json 就會(huì)拋出一個(gè)異常。

原始響應(yīng)內(nèi)容

在罕見的情況下你可能想獲取來自服務(wù)器的原始套接字響應(yīng),那么你可以訪問 r.raw 。 如果你確實(shí)想這么干,那請(qǐng)你確保在初始請(qǐng)求中設(shè)置了 stream=True 。具體的你可以這么做:

>>> r = requests.get('https://github.com/timeline.json', 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'

定制請(qǐng)求頭

如果你想為請(qǐng)求添加HTTP頭部,只要簡單地傳遞一個(gè) dict 給 headers 參數(shù)就可以了。

例如,在前一個(gè)示例中我們沒有指定content-type:

>>> import json
>>> url = 'https://api.github.com/some/endpoint'
>>> payload = {'some': 'data'}
>>> headers = {'content-type': 'application/json'}

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

更加復(fù)雜的POST請(qǐng)求

通常,你想要發(fā)送一些編碼為表單形式的數(shù)據(jù)—非常像一個(gè)HTML表單。 要實(shí)現(xiàn)這個(gè),只需簡單地傳遞一個(gè)字典給 data 參數(shù)。你的數(shù)據(jù)字典 在發(fā)出請(qǐng)求時(shí)會(huì)自動(dòng)編碼為表單形式:

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

很多時(shí)候你想要發(fā)送的數(shù)據(jù)并非編碼為表單形式的。如果你傳遞一個(gè) string 而不是一個(gè)dict ,那么數(shù)據(jù)會(huì)被直接發(fā)布出去。

例如,Github API v3接受編碼為JSON的POST/PATCH數(shù)據(jù):

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

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

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

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

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

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

你可以顯式地設(shè)置文件名:

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

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

如果你想,你也可以發(fā)送作為文件來接收的字符串:

>>> url = 'http:///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"
  },
  ...
}

響應(yīng)狀態(tài)碼

我們可以檢測(cè)響應(yīng)狀態(tài)碼:

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

為方便引用,Requests還附帶了一個(gè)內(nèi)置的狀態(tài)碼查詢對(duì)象:

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

如果發(fā)送了一個(gè)失敗請(qǐng)求(非200響應(yīng)),我們可以通過 Response.raise_for_status() 來拋出異常:

>>> bad_r = requests.get('http:///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 ,當(dāng)我們調(diào)用 raise_for_status() 時(shí),得到的是:

>>> r.raise_for_status()
None

一切都挺和諧哈。

響應(yīng)頭

我們可以查看以一個(gè)Python字典形式展示的服務(wù)器響應(yīng)頭:

>>> r.headers
{
    'status': '200 OK',
    'content-encoding': 'gzip',
    'transfer-encoding': 'chunked',
    'connection': 'close',
    'server': 'nginx/1.0.4',
    'x-runtime': '148ms',
    'etag': '"e1ca502697e5c9317743dc078f67693f"',
    'content-type': 'application/json; charset=utf-8'
}

但是這個(gè)字典比較特殊:它是僅為HTTP頭部而生的。根據(jù) RFC 2616 , HTTP頭部是大小寫不敏感的。

因此,我們可以使用任意大寫形式來訪問這些響應(yīng)頭字段:

>>> r.headers['Content-Type']
'application/json; charset=utf-8'

>>> r.headers.get('content-type')
'application/json; charset=utf-8'

如果某個(gè)響應(yīng)頭字段不存在,那么它的默認(rèn)值為 None

>>> r.headers['X-Random']
None

Cookies

如果某個(gè)響應(yīng)中包含一些Cookie,你可以快速訪問它們:

>>> url = 'http:///some/cookie/setting/url'
>>> r = requests.get(url)

>>> r.cookies['example_cookie_name']
'example_cookie_value'

要想發(fā)送你的cookies到服務(wù)器,可以使用 cookies 參數(shù):

>>> url = 'http:///cookies'
>>> cookies = dict(cookies_are='working')

>>> r = requests.get(url, cookies=cookies)
>>> r.text
'{"cookies": {"cookies_are": "working"}}'

重定向與請(qǐng)求歷史

使用GET或OPTIONS時(shí),Requests會(huì)自動(dòng)處理位置重定向。

Github將所有的HTTP請(qǐng)求重定向到HTTPS。可以使用響應(yīng)對(duì)象的 history 方法來追蹤重定向。 我們來看看Github做了什么:

>>> r = requests.get('http://github.com')
>>> r.url
'https://github.com/'
>>> r.status_code
200
>>> r.history
[<Response [301]>]

Response.history 是一個(gè):class:Request 對(duì)象的列表,為了完成請(qǐng)求而創(chuàng)建了這些對(duì)象。這個(gè)對(duì)象列表按照從最老到最近的請(qǐng)求進(jìn)行排序。

如果你使用的是GET或OPTIONS,那么你可以通過 allow_redirects 參數(shù)禁用重定向處理:

>>> r = requests.get('http://github.com', allow_redirects=False)
>>> r.status_code
301
>>> r.history
[]

如果你使用的是POST,PUT,PATCH,DELETE或HEAD,你也可以啟用重定向:

>>> r = requests.post('http://github.com', allow_redirects=True)
>>> r.url
'https://github.com/'
>>> r.history
[<Response [301]>]

超時(shí)

你可以告訴requests在經(jīng)過以 timeout 參數(shù)設(shè)定的秒數(shù)時(shí)間之后停止等待響應(yīng):

>>> requests.get('http://github.com', timeout=0.001)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
requests.exceptions.Timeout: HTTPConnectionPool(host='github.com', port=80): Request timed out. (timeout=0.001)

注:

timeout 僅對(duì)連接過程有效,與響應(yīng)體的下載無關(guān)。

錯(cuò)誤與異常

遇到網(wǎng)絡(luò)問題(如:DNS查詢失敗、拒絕連接等)時(shí),Requests會(huì)拋出一個(gè)ConnectionError 異常。

遇到罕見的無效HTTP響應(yīng)時(shí),Requests則會(huì)拋出一個(gè) HTTPError 異常。

若請(qǐng)求超時(shí),則拋出一個(gè) Timeout 異常。

若請(qǐng)求超過了設(shè)定的最大重定向次數(shù),則會(huì)拋出一個(gè) TooManyRedirects 異常。

所有Requests顯式拋出的異常都繼承自 requests.exceptions.RequestException 。


高級(jí)用法

本篇文檔涵蓋了Requests的一些更加高級(jí)的特性。

會(huì)話對(duì)象

會(huì)話對(duì)象讓你能夠跨請(qǐng)求保持某些參數(shù)。它也會(huì)在同一個(gè)Session實(shí)例發(fā)出的所有請(qǐng)求之間保持cookies。

會(huì)話對(duì)象具有主要的Requests API的所有方法。

我們來跨請(qǐng)求保持一些cookies:

s = requests.Session()

s.get('http:///cookies/set/sessioncookie/123456789')
r = s.get("http:///cookies")

print r.text
# '{"cookies": {"sessioncookie": "123456789"}}'

會(huì)話也可用來為請(qǐng)求方法提供缺省數(shù)據(jù)。這是通過為會(huì)話對(duì)象的屬性提供數(shù)據(jù)來實(shí)現(xiàn)的:

s = requests.Session()
s.auth = ('user', 'pass')
s.headers.update({'x-test': 'true'})

# both 'x-test' and 'x-test2' are sent
s.get('http:///headers', headers={'x-test2': 'true'})

任何你傳遞給請(qǐng)求方法的字典都會(huì)與已設(shè)置會(huì)話層數(shù)據(jù)合并。方法層的參數(shù)覆蓋會(huì)話的參數(shù)。

從字典參數(shù)中移除一個(gè)值

有時(shí)你會(huì)想省略字典參數(shù)中一些會(huì)話層的鍵。要做到這一點(diǎn),你只需簡單地在方法層參數(shù)中將那個(gè)鍵的值設(shè)置為 None ,那個(gè)鍵就會(huì)被自動(dòng)省略掉。

包含在一個(gè)會(huì)話中的所有數(shù)據(jù)你都可以直接使用。學(xué)習(xí)更多細(xì)節(jié)請(qǐng)閱讀 會(huì)話API文檔 。

請(qǐng)求與響應(yīng)對(duì)象

任何時(shí)候調(diào)用requests.*()你都在做兩件主要的事情。其一,你在構(gòu)建一個(gè) Request 對(duì)象, 該對(duì)象將被發(fā)送到某個(gè)服務(wù)器請(qǐng)求或查詢一些資源。其二,一旦 requests 得到一個(gè)從 服務(wù)器返回的響應(yīng)就會(huì)產(chǎn)生一個(gè) Response 對(duì)象。該響應(yīng)對(duì)象包含服務(wù)器返回的所有信息, 也包含你原來創(chuàng)建的 Request 對(duì)象。如下是一個(gè)簡單的請(qǐng)求,從Wikipedia的服務(wù)器得到 一些非常重要的信息:

>>> r = requests.get('http://en./wiki/Monty_Python')

如果想訪問服務(wù)器返回給我們的響應(yīng)頭部信息,可以這樣做:

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

然而,如果想得到發(fā)送到服務(wù)器的請(qǐng)求的頭部,我們可以簡單地訪問該請(qǐng)求,然后是該請(qǐng)求的頭部:

>>> r.request.headers
{'Accept-Encoding': 'identity, deflate, compress, gzip',
'Accept': '*/*', 'User-Agent': 'python-requests/0.13.1'}

SSL證書驗(yàn)證

Requests可以為HTTPS請(qǐng)求驗(yàn)證SSL證書,就像web瀏覽器一樣。要想檢查某個(gè)主機(jī)的SSL證書,你可以使用 verify 參數(shù):

>>> requests.get('https://', verify=True)
requests.exceptions.SSLError: hostname '' doesn't match either of '*.herokuapp.com', 'herokuapp.com'

在該域名上我沒有設(shè)置SSL,所以失敗了。但Github設(shè)置了SSL:

>>> requests.get('https://github.com', verify=True)
<Response [200]>

對(duì)于私有證書,你也可以傳遞一個(gè)CA_BUNDLE文件的路徑給 verify 。你也可以設(shè)置REQUEST_CA_BUNDLE 環(huán)境變量。

如果你將 verify 設(shè)置為False,Requests也能忽略對(duì)SSL證書的驗(yàn)證。

>>> requests.get('https://', verify=False)
<Response [200]>

默認(rèn)情況下, verify 是設(shè)置為True的。選項(xiàng) verify 僅應(yīng)用于主機(jī)證書。

你也可以指定一個(gè)本地證書用作客戶端證書,可以是單個(gè)文件(包含密鑰和證書)或一個(gè)包含兩個(gè)文件路徑的元組:

>>> requests.get('https://', cert=('/path/server.crt', '/path/key'))
<Response [200]>

如果你指定了一個(gè)錯(cuò)誤路徑或一個(gè)無效的證書:

>>> requests.get('https://', cert='/wrong_path/server.pem')
SSLError: [Errno 336265225] _ssl.c:347: error:140B0009:SSL routines:SSL_CTX_use_PrivateKey_file:PEM lib

響應(yīng)體內(nèi)容工作流

默認(rèn)情況下,當(dāng)你進(jìn)行網(wǎng)絡(luò)請(qǐng)求后,響應(yīng)體會(huì)立即被下載。你可以通過 stream 參數(shù)覆蓋這個(gè)行為,推遲下載響應(yīng)體直到訪問 Response.content 屬性:

tarball_url = 'https://github.com/kennethreitz/requests/tarball/master'
r = requests.get(tarball_url, stream=True)

此時(shí)僅有響應(yīng)頭被下載下來了,連接保持打開狀態(tài),因此允許我們根據(jù)條件獲取內(nèi)容:

if int(r.headers['content-length']) < TOO_LONG:
  content = r.content
  ...

你可以進(jìn)一步使用 Response.iter_content 和 Response.iter_lines 方法來控制工作流,或者以 Response.raw 從底層urllib3的 urllib3.HTTPResponse 讀取。

保持活動(dòng)狀態(tài)(持久連接)

好消息 - 歸功于urllib3,同一會(huì)話內(nèi)的持久連接是完全自動(dòng)處理的!同一會(huì)話內(nèi)你發(fā)出的任何請(qǐng)求都會(huì)自動(dòng)復(fù)用恰當(dāng)?shù)倪B接!

注意:只有所有的響應(yīng)體數(shù)據(jù)被讀取完畢連接才會(huì)被釋放為連接池;所以確保將 stream設(shè)置為 False 或讀取 Response 對(duì)象的 content 屬性。

流式上傳

Requests支持流式上傳,這允許你發(fā)送大的數(shù)據(jù)流或文件而無需先把它們讀入內(nèi)存。要使用流式上傳,僅需為你的請(qǐng)求體提供一個(gè)類文件對(duì)象即可:

with open('massive-body') as f:
    requests.post('http://some.url/streamed', data=f)

塊編碼請(qǐng)求

對(duì)于出去和進(jìn)來的請(qǐng)求,Requests也支持分塊傳輸編碼。要發(fā)送一個(gè)塊編碼的請(qǐng)求,僅需為你的請(qǐng)求體提供一個(gè)生成器(或任意沒有具體長度(without a length)的迭代器):

def gen():
    yield 'hi'
    yield 'there'

requests.post('http://some.url/chunked', data=gen())

事件掛鉤

Requests有一個(gè)鉤子系統(tǒng),你可以用來操控部分請(qǐng)求過程,或信號(hào)事件處理。

可用的鉤子:

response:

從一個(gè)請(qǐng)求產(chǎn)生的響應(yīng)

你可以通過傳遞一個(gè) {hook_name: callback_function} 字典給 hooks 請(qǐng)求參數(shù) 為每個(gè)請(qǐng)求分配一個(gè)鉤子函數(shù):

hooks=dict(response=print_url)

callback_function 會(huì)接受一個(gè)數(shù)據(jù)塊作為它的第一個(gè)參數(shù)。

def print_url(r):
    print(r.url)

若執(zhí)行你的回調(diào)函數(shù)期間發(fā)生錯(cuò)誤,系統(tǒng)會(huì)給出一個(gè)警告。

若回調(diào)函數(shù)返回一個(gè)值,默認(rèn)以該值替換傳進(jìn)來的數(shù)據(jù)。若函數(shù)未返回任何東西, 也沒有什么其他的影響。

我們來在運(yùn)行期間打印一些請(qǐng)求方法的參數(shù):

>>> requests.get('http://', hooks=dict(response=print_url))
http://
<Response [200]>

自定義身份驗(yàn)證

Requests允許你使用自己指定的身份驗(yàn)證機(jī)制。

任何傳遞給請(qǐng)求方法的 auth 參數(shù)的可調(diào)用對(duì)象,在請(qǐng)求發(fā)出之前都有機(jī)會(huì)修改請(qǐng)求。

自定義的身份驗(yàn)證機(jī)制是作為 requests.auth.AuthBase 的子類來實(shí)現(xiàn)的,也非常容易定義。

Requests在 requests.auth 中提供了兩種常見的的身份驗(yàn)證方案: HTTPBasicAuth 和HTTPDigestAuth 。

假設(shè)我們有一個(gè)web服務(wù),僅在 X-Pizza 頭被設(shè)置為一個(gè)密碼值的情況下才會(huì)有響應(yīng)。雖然這不太可能, 但就以它為例好了

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

然后就可以使用我們的PizzaAuth來進(jìn)行網(wǎng)絡(luò)請(qǐng)求:

>>> requests.get('http:///admin', auth=PizzaAuth('kenneth'))
<Response [200]>

流式請(qǐng)求

使用 requests.Response.iter_lines() 你可以很方便地對(duì)流式API(例如 Twitter的流式API )進(jìn)行迭代。

使用Twitter流式API來追蹤關(guān)鍵字“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)

代理

如果需要使用代理,你可以通過為任意請(qǐng)求方法提供 proxies 參數(shù)來配置單個(gè)請(qǐng)求:

import requests

proxies = {
  "http": "http://10.10.1.10:3128",
  "https": "http://10.10.1.10:1080",
}

requests.get("http://", proxies=proxies)

你也可以通過環(huán)境變量 HTTP_PROXY 和 HTTPS_PROXY 來配置代理。

$ export HTTP_PROXY="http://10.10.1.10:3128"
$ export HTTPS_PROXY="http://10.10.1.10:1080"
$ python
>>> import requests
>>> requests.get("http://")

若你的代理需要使用HTTP Basic Auth,可以使用 http://user:password@host/ 語法:

proxies = {
    "http": "http://user:pass@10.10.1.10:3128/",
}

合規(guī)性

Requests符合所有相關(guān)的規(guī)范和RFC,這樣不會(huì)為用戶造成不必要的困難。但這種對(duì)規(guī)范的考慮 導(dǎo)致一些行為對(duì)于不熟悉相關(guān)規(guī)范的人來說看似有點(diǎn)奇怪。

編碼方式

當(dāng)你收到一個(gè)響應(yīng)時(shí),Requests會(huì)猜測(cè)響應(yīng)的編碼方式,用于在你調(diào)用 Response.text 方法時(shí) 對(duì)響應(yīng)進(jìn)行解碼。Requests首先在HTTP頭部檢測(cè)是否存在指定的編碼方式,如果不存在,則會(huì)使用 charade 來嘗試猜測(cè)編碼方式。

只有當(dāng)HTTP頭部不存在明確指定的字符集,并且 Content-Type 頭部字段包含 text 值之時(shí), Requests才不去猜測(cè)編碼方式。

在這種情況下, RFC 2616 指定默認(rèn)字符集 必須是 ISO-8859-1 。Requests遵從這一規(guī)范。如果你需要一種不同的編碼方式,你可以手動(dòng)設(shè)置 Response.encoding 屬性,或使用原始的 Response.content 。

HTTP動(dòng)詞

Requests提供了幾乎所有HTTP動(dòng)詞的功能:GET,OPTIONS, HEAD,POST,PUT,PATCH和DELETE。 以下內(nèi)容為使用Requests中的這些動(dòng)詞以及Github API提供了詳細(xì)示例。

我將從最常使用的動(dòng)詞GET開始。HTTP GET是一個(gè)冪等的方法,從給定的URL返回一個(gè)資源。因而, 當(dāng)你試圖從一個(gè)web位置獲取數(shù)據(jù)之時(shí),你應(yīng)該使用這個(gè)動(dòng)詞。一個(gè)使用示例是嘗試從Github上獲取 關(guān)于一個(gè)特定commit的信息。假設(shè)我們想獲取Requests的commit a050faf 的信息。我們可以 這樣去做:

>>> import requests
>>> r = requests.get('https://api.github.com/repos/kennethreitz/requests/git/commits/a050faf084662f3a352dd1a941f2c7c9f886d4ad')

我們應(yīng)該確認(rèn)Github是否正確響應(yīng)。如果正確響應(yīng),我們想弄清響應(yīng)內(nèi)容是什么類型的。像這樣去做:

>>> if (r.status_code == requests.codes.ok):
...     print r.headers['content-type']
...
application/json; charset=utf-8

可見,GitHub返回了JSON數(shù)據(jù),非常好,這樣就可以使用 r.json 方法把這個(gè)返回的數(shù)據(jù)解析成Python對(duì)象。

>>> commit_data = r.json()
>>> print commit_data.keys()
[u'committer', u'author', u'url', u'tree', u'sha', u'parents', u'message']
>>> print commit_data[u'committer']
{u'date': u'2012-05-10T11:10:50-07:00', u'email': u'me@', u'name': u'Kenneth Reitz'}
>>> print commit_data[u'message']
makin' history

到目前為止,一切都非常簡單。嗯,我們來研究一下GitHub的API。我們可以去看看文檔, 但如果使用Requests來研究也許會(huì)更有意思一點(diǎn)。我們可以借助Requests的OPTIONS動(dòng)詞來看看我們剛使用過的url 支持哪些HTTP方法。

>>> verbs = requests.options(r.url)
>>> verbs.status_code
500

額,這是怎么回事?毫無幫助嘛!原來GitHub,與許多API提供方一樣,實(shí)際上并未實(shí)現(xiàn)OPTIONS方法。 這是一個(gè)惱人的疏忽,但沒關(guān)系,那我們可以使用枯燥的文檔。然而,如果GitHub正確實(shí)現(xiàn)了OPTIONS, 那么服務(wù)器應(yīng)該在響應(yīng)頭中返回允許用戶使用的HTTP方法,例如

>>> verbs = requests.options('http:///api/cats')
>>> print verbs.headers['allow']
GET,HEAD,POST,OPTIONS

轉(zhuǎn)而去查看文檔,我們看到對(duì)于提交信息,另一個(gè)允許的方法是POST,它會(huì)創(chuàng)建一個(gè)新的提交。 由于我們正在使用Requests代碼庫,我們應(yīng)盡可能避免對(duì)它發(fā)送笨拙的POST。作為替代,我們來 玩玩GitHub的Issue特性。

本篇文檔是回應(yīng)Issue #482而添加的。鑒于該問題已經(jīng)存在,我們就以它為例。先獲取它。

>>> r = requests.get('https://api.github.com/repos/kennethreitz/requests/issues/482')
>>> r.status_code
200
>>> issue = json.loads(r.text)
>>> print issue[u'title']
Feature any http verb in docs
>>> print issue[u'comments']
3

Cool,有3個(gè)評(píng)論。我們來看一下最后一個(gè)評(píng)論。

>>> r = requests.get(r.url + u'/comments')
>>> r.status_code
200
>>> comments = r.json()
>>> print comments[0].keys()
[u'body', u'url', u'created_at', u'updated_at', u'user', u'id']
>>> print comments[2][u'body']
Probably in the "advanced" section

嗯,那看起來似乎是個(gè)愚蠢之處。我們發(fā)表個(gè)評(píng)論來告訴這個(gè)評(píng)論者他自己的愚蠢。那么,這個(gè)評(píng)論者是誰呢?

>>> print comments[2][u'user'][u'login']
kennethreitz

好,我們來告訴這個(gè)叫肯尼思的家伙,這個(gè)例子應(yīng)該放在快速上手指南中。根據(jù)GitHub API文檔, 其方法是POST到該話題。我們來試試看。

>>> body = json.dumps({u"body": u"Sounds great! I'll get right on it!"})
>>> url = u"https://api.github.com/repos/kennethreitz/requests/issues/482/comments"
>>> r = requests.post(url=url, data=body)
>>> r.status_code
404

額,這有點(diǎn)古怪哈??赡芪覀冃枰?yàn)證身份。那就有點(diǎn)糾結(jié)了,對(duì)吧?不對(duì)。Requests簡化了多種身份驗(yàn)證形式的使用, 包括非常常見的Basic Auth。

>>> from requests.auth import HTTPBasicAuth
>>> auth = HTTPBasicAuth('fake@', 'not_a_real_password')
>>> r = requests.post(url=url, data=body, auth=auth)
>>> r.status_code
201
>>> content = r.json()
>>> print content[u'body']
Sounds great! I'll get right on it.

精彩!噢,不!我原本是想說等我一會(huì),因?yàn)槲业萌ノ挂幌挛业呢垺H绻夷軌蚓庉嬤@條評(píng)論那就好了! 幸運(yùn)的是,GitHub允許我們使用另一個(gè)HTTP動(dòng)詞,PATCH,來編輯評(píng)論。我們來試試。

>>> print content[u"id"]
5804413
>>> body = json.dumps({u"body": u"Sounds great! I'll get right on it once I feed my cat."})
>>> url = u"https://api.github.com/repos/kennethreitz/requests/issues/comments/5804413"
>>> r = requests.patch(url=url, data=body, auth=auth)
>>> r.status_code
200

非常好?,F(xiàn)在,我們來折磨一下這個(gè)叫肯尼思的家伙,我決定要讓他急得團(tuán)團(tuán)轉(zhuǎn),也不告訴他是我在搗蛋。 這意味著我想刪除這條評(píng)論。GitHub允許我們使用完全名副其實(shí)的DELETE方法來刪除評(píng)論。我們來清除該評(píng)論。

>>> r = requests.delete(url=url, auth=auth)
>>> r.status_code
204
>>> r.headers['status']
'204 No Content'

很好。不見了。最后一件我想知道的事情是我已經(jīng)使用了多少限額(ratelimit)。查查看,GitHub在響應(yīng)頭部發(fā)送這個(gè)信息, 因此不必下載整個(gè)網(wǎng)頁,我將使用一個(gè)HEAD請(qǐng)求來獲取響應(yīng)頭。

>>> r = requests.head(url=url, auth=auth)
>>> print r.headers
...
'x-ratelimit-remaining': '4995'
'x-ratelimit-limit': '5000'
...

很好。是時(shí)候?qū)憘€(gè)Python程序以各種刺激的方式濫用GitHub的API,還可以使用4995次呢。

響應(yīng)頭鏈接字段

許多HTTP API都有響應(yīng)頭鏈接字段的特性,它們使得API能夠更好地自我描述和自我顯露。

GitHub在API中為 分頁 使用這些特性,例如:

>>> url = 'https://api.github.com/users/kennethreitz/repos?page=1&per_page=10'
>>> r = requests.head(url=url)
>>> r.headers['link']
'<https://api.github.com/users/kennethreitz/repos?page=2&per_page=10>; rel="next", <https://api.github.com/users/kennethreitz/repos?page=6&per_page=10>; rel="last"'

Requests會(huì)自動(dòng)解析這些響應(yīng)頭鏈接字段,并使得它們非常易于使用:

>>> r.links["next"]
{'url': 'https://api.github.com/users/kennethreitz/repos?page=2&per_page=10', 'rel': 'next'}

>>> r.links["last"]
{'url': 'https://api.github.com/users/kennethreitz/repos?page=7&per_page=10', 'rel': 'last'}

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多

    麻豆亚州无矿码专区视频| 亚洲国产欧美精品久久| 日韩精品第一区二区三区| 夜夜嗨激情五月天精品| 老司机精品福利视频在线播放| 欧美一区二区三区在线播放| 亚洲一区二区亚洲日本| 国产情侣激情在线对白| 91欧美日韩精品在线| 国产三级不卡在线观看视频| 免费福利午夜在线观看| 蜜桃传媒视频麻豆第一区| 亚洲熟妇av一区二区三区色堂| 日韩三极片在线免费播放| 亚洲精品av少妇在线观看| 午夜色午夜视频之日本| 久久永久免费一区二区| 国产午夜在线精品视频| 大香伊蕉欧美一区二区三区| 久久精品a毛片看国产成人| 国产乱淫av一区二区三区| 日本精品理论在线观看| 国产亚洲视频香蕉一区| 国产欧美日韩在线精品一二区| 欧美日韩综合免费视频| 国产午夜福利不卡片在线观看| 日韩精品少妇人妻一区二区| 欧美日韩国产午夜福利| 久热人妻中文字幕一区二区| 亚洲超碰成人天堂涩涩| 日本少妇三级三级三级| 91免费精品国自产拍偷拍| 99久久精品国产日本| 夫妻性生活黄色录像视频| 中文字幕亚洲精品乱码加勒比| 欧美黑人精品一区二区在线| 亚洲欧美精品伊人久久| 精品日韩av一区二区三区| 亚洲欧美国产网爆精品| 大香蕉网国产在线观看av| 亚洲视频一级二级三级|