pythonrequest得替代_python的扩展包requests的高级用法
Python 標準庫中的?urllib2?模塊提供了你所需要的大多數(shù) HTTP 功能,但是它的 API 太渣了。它是為另一個時代、另一個互聯(lián)網(wǎng)所創(chuàng)建的。它需要巨量的工作,甚至包括各種方法覆蓋,來完成最簡單的任務。
Requests 完全滿足如今網(wǎng)絡的需求。
國際化域名和 URLs
Keep-Alive & 連接池
持久的 Cookie 會話
類瀏覽器式的 SSL 加密認證
基本/摘要式的身份認證
優(yōu)雅的鍵/值 Cookies
自動解壓
Unicode 編碼的響應體
多段文件上傳
連接超時
支持?.netrc
適用于 Python 2.6—3.4
線程安全
會話對象:
會話就是session,session的實現(xiàn)是基于cookie的,所以會話對象能夠跨請求保持一些參數(shù),也可以在同一個session實例發(fā)出的所有請求之間保持cookies。
import requests
s=requests.Session()
s.get('http://httpbin.org/cookies/set/sessioncookie/123456789')
r=s.get('http://httpbin.org/cookies')
會話對象也可以為其你去提供缺省數(shù)據(jù),通過會話對象的屬性提哦給你數(shù)據(jù)來實現(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://httpbin.org/headers', headers={'x-test2': 'true'})
會話對象傳入的參數(shù)會自動覆蓋初始化中的默認參數(shù)。
請求與響應對象
任何時候調用requests.*()你都在做兩件主要的事情。其一,你在構建一個?Request?對象, 該對象將被發(fā)送到某個服務器請求或查詢一些資源。其二,一旦?requests?得到一個從 服務器返回的響應就會產生一個?Response?對象。該響應對象包含服務器返回的所有信息, 也包含你原來創(chuàng)建的?Request?對象。
r = requests.get('http://www.baidu.com')
r.headers
獲取響應頭的信息。查看http協(xié)議了解響應頭的內容
下面的代碼是獲取請求的內容
r.request.headers
Prepared Requests
當你從一個api請求或者一個session請求接受到一個響應對象的時候,請求的參數(shù)實際上是PreparedRequest?對象使用的,如果你想在提交請求之前在請求體body或者請求頭header做一些操作的時候。
from requests importRequest, Session
s=Session()
req= Request('GET', url,
data=data,
headers=header
)
prepped=req.prepare()#do something with prepped.body#do something with prepped.headers
resp=s.send(prepped,
stream=stream,
verify=verify,
proxies=proxies,
cert=cert,
timeout=timeout
)print(resp.status_code)
可以理解。Requests對象其實就是當PreparedRequest?沒有被修改時直接提交的。最后的請求方式是?requests.*?或者?Session.*.
上面的代碼在使用Requests的session對象時很可能會丟失一些優(yōu)勢,session級別的狀態(tài),比如說cookie就不會在request請求中,用Session.prepare_request()代替Request.prepare()?就可以完美的實現(xiàn)session級別的狀態(tài)。
from requests importRequest, Session
s=Session()
req= Request('GET', url,
data=data
headers=headers
)
prepped=s.prepare_request(req)#do something with prepped.body#do something with prepped.headers
resp=s.send(prepped,
stream=stream,
verify=verify,
proxies=proxies,
cert=cert,
timeout=timeout
)print(resp.status_code)
SSL證書驗證
SSL證書通過在客戶端瀏覽器和Web服務器之間建立一條SSL安全通道(Secure socket layer(SSL)安全協(xié)議是由Netscape Communication公司設計開發(fā)。該安全協(xié)議主要用來提供對用戶和服務器的認證;對傳送的數(shù)據(jù)進行加密和隱藏;確保數(shù)據(jù)在傳送中不被改變,即數(shù)據(jù)的完整性,現(xiàn)已成為該領域中全球化的標準。由于SSL技術已建立到所有主要的瀏覽器和WEB服務器程序中,因此,僅需安裝服務器證書就可以激活該功能了)。即通過它可以激活SSL協(xié)議,實現(xiàn)數(shù)據(jù)信息在客戶端和服務器之間的加密傳輸,可以防止數(shù)據(jù)信息的泄露。保證了雙方傳遞信息的安全性,而且用戶可以通過服務器證書驗證他所訪問的網(wǎng)站是否是真實可靠。
Requests可以為HTTPS請求驗證SSL證書,就像web瀏覽器一樣。要想檢查某個主機的SSL證書,你可以使用?verify?參數(shù):
requests.get('https://kennethreitz.com', verify=True)
在該域名上我沒有設置SSL,所以失敗了。但Github設置了SSL:
requests.get('https://github.com', verify=True)
如果你將?verify?設置為False,Requests也能忽略對SSL證書的驗證
requests.get('https://kennethreitz.com', verify=False)
默認情況下,?verify?是設置為True的。選項?verify?僅應用于主機證書。
你也可以指定一個本地證書用作客戶端證書,可以是單個文件(包含密鑰和證書)或一個包含兩個文件路徑的元組:
requests.get('https://kennethreitz.com', cert=('/path/server.crt', '/path/key'))
如果你指定了一個錯誤路徑或一個無效的證書:
requests.get('https://kennethreitz.com', cert='/wrong_path/server.pem')
SSLError: [Errno336265225] _ssl.c:347: error:140B0009:SSL routines:SSL_CTX_use_PrivateKey_file:PEM lib
響應體內容工作流
默認情況下,當你進行網(wǎng)絡請求后,響應體會立即被下載。你可以通過?stream?參數(shù)覆蓋這個行為,推遲下載響應體直到訪問?Response.content?屬性:
tarball_url = 'https://github.com/kennethreitz/requests/tarball/master'r= requests.get(tarball_url, stream=True)
此時僅有響應頭被下載下來了,連接保持打開狀態(tài),因此允許我們根據(jù)條件獲取內容:
if int(r.headers['content-length'])
content=r.content
...
當講一個request請求的stream=True時,連接connection不會被返回放入到連接池中去除非你讀取完requests中所有的數(shù)據(jù)或者直接調用Requests.close()方法。這必然導致連接的效率很低,當只需要響應的正文部分(或者什么都不需要讀取),可以試試contextlib.closing
from contextlib importclosing
with closing(requests.get('http://httpbin.org/get', stream=True)) as r:#Do things with the response here.
保持活動狀態(tài)(持久連接)
好消息 - 歸功于urllib3,同一會話內的持久連接是完全自動處理的!同一會話內你發(fā)出的任何請求都會自動復用恰當?shù)倪B接!只有所有的響應體數(shù)據(jù)被讀取完畢連接才會被釋放為連接池;所以確保將?stream設置為?False?或讀取?Response?對象的?content?屬性。
流式上傳
Requests支持流式上傳,這允許你發(fā)送大的數(shù)據(jù)流或文件而無需先把它們讀入內存。要使用流式上傳,僅需為你的請求體提供一個類文件對象即可:
with open('massive-body') as f:
requests.post('http://some.url/streamed', data=f)
塊編碼請求
對于出去和進來的請求,Requests也支持分塊傳輸編碼。要發(fā)送一個塊編碼的請求,僅需為你的請求體提供一個生成器(或任意沒有具體長度(without a length)的迭代器)
defgen():yield 'hi'
yield 'there'requests.post('http://some.url/chunked', data=gen())
多文件同時上傳
當需要在一次請求中上傳多個文件的時候,如:
這時候可以將文件設置成一個元組列表(文件名稱,文件信息)。
url = 'http://httpbin.org/post'multiple_files= [('images', ('foo.png', open('foo.png', 'rb'), 'image/png')),
('images', ('bar.png', open('bar.png', 'rb'), 'image/png'))]
r= requests.post(url, files=multiple_files)
r.text
流式請求
importjsonimportrequests
r= requests.get('http://httpbin.org/stream/20', stream=True)for line inr.iter_lines():#filter out keep-alive new lines
ifline:print(json.loads(line))
代理
如果需要使用代理,你可以通過為任意請求方法提供?proxies?參數(shù)來配置單個請求:
importrequests
proxies={"http": "http://10.10.1.10:3128","https": "http://10.10.1.10:1080",
}
requests.get("http://example.org", 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"$ pythonimportrequests
requests.get("http://example.org")
若你的代理需要使用HTTP Basic Auth,可以使用?http://user:password@host/?語法:
proxies ={"http": "http://user:pass@10.10.1.10:3128/",
}
編碼方式
當你收到一個響應時,Requests會猜測響應的編碼方式,用于在你調用?Response.text方法時 對響應進行解碼。Requests首先在HTTP頭部檢測是否存在指定的編碼方式,如果不存在,則會使用?charade?來嘗試猜測編碼方式
只有當HTTP頭部不存在明確指定的字符集,并且?Content-Type?頭部字段包含?text?值之時, Requests才不去猜測編碼方式
在這種情況下,?RFC 2616?指定默認字符集 必須是?ISO-8859-1?。Requests遵從這一規(guī)范。如果你需要一種不同的編碼方式,你可以手動設置?Response.encoding?屬性,或使用原始的?Response.content
HTTP動詞
Requests提供了幾乎所有HTTP動詞的功能:GET,OPTIONS, HEAD,POST,PUT,PATCH和DELETE。 以下內容為使用Requests中的這些動詞以及Github API提供了詳細示例。
我將從最常使用的動詞GET開始。HTTP GET是一個冪等的方法,從給定的URL返回一個資源。因而, 當你試圖從一個web位置獲取數(shù)據(jù)之時,你應該使用這個動詞。一個使用示例是嘗試從Github上獲取 關于一個特定commit的信息。假設我們想獲取Requests的commit?a050faf?的信息。我們可以 這樣去做
importrequests
r= requests.get('https://api.github.com/repos/kennethreitz/requests/git/commits/a050faf084662f3a352dd1a941f2c7c9f886d4ad')
我們應該確認Github是否正確響應。如果正確響應,我們想弄清響應內容是什么類型的。像這樣去做:
if (r.status_code ==requests.codes.ok):
...print r.headers['content-type']
...
application/json; charset=utf-8
可見,GitHub返回了JSON數(shù)據(jù),非常好,這樣就可以使用?r.json?方法把這個返回的數(shù)據(jù)解析成Python對象
>>> commit_data =r.json()>>> printcommit_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@kennethreitz.com', u'name': u'Kenneth Reitz'}>>> print commit_data[u'message']
makin'history
到目前為止,一切都非常簡單。嗯,我們來研究一下GitHub的API。我們可以去看看文檔, 但如果使用Requests來研究也許會更有意思一點。我們可以借助Requests的OPTIONS動詞來看看我們剛使用過的url 支持哪些HTTP方法
>>> verbs =requests.options(r.url)>>>verbs.status_code500
額,這是怎么回事?毫無幫助嘛!原來GitHub,與許多API提供方一樣,實際上并未實現(xiàn)OPTIONS方法。 這是一個惱人的疏忽,但沒關系,那我們可以使用枯燥的文檔。然而,如果GitHub正確實現(xiàn)了OPTIONS, 那么服務器應該在響應頭中返回允許用戶使用的HTTP方法,例如
>>> verbs = requests.options('http://a-good-website.com/api/cats')>>> print verbs.headers['allow']
GET,HEAD,POST,OPTIONS
轉而去查看文檔,我們看到對于提交信息,另一個允許的方法是POST,它會創(chuàng)建一個新的提交。 由于我們正在使用Requests代碼庫,我們應盡可能避免對它發(fā)送笨拙的POST。作為替代,我們來 玩玩GitHub的Issue特性
>>> r = requests.get('https://api.github.com/repos/kennethreitz/requests/issues/482')>>>r.status_code200
>>> issue =json.loads(r.text)>>> print issue[u'title']
Feature any http verbindocs>>> print issue[u'comments']3
使用https://api.github.com/repos/kennethreitz/requests/issues/482為例
r = requests.get('https://api.github.com/repos/kennethreitz/requests/issues/482')>>>r.status_code200
>>> issue =json.loads(r.text)>>> print issue[u'title']
Feature any http verbindocs>>> print issue[u'comments']
有3個評論。我們來看一下最后一個評論
>>> r = requests.get(r.url + u'/comments')>>>r.status_code200
>>> comments =r.json()>>> printcomments[0].keys()
[u'body', u'url', u'created_at', u'updated_at', u'user', u'id']>>> print comments[2][u'body']
Probablyin the "advanced" section
嗯,那看起來似乎是個愚蠢之處。我們發(fā)表個評論來告訴這個評論者他自己的愚蠢。那么,這個評論者是誰呢?
>>> print comments[2][u'user'][u'login']
kennethreitz
好,我們來告訴這個叫肯尼思的家伙,這個例子應該放在快速上手指南中。根據(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_code404
這有點古怪哈。可能我們需要驗證身份。那就有點糾結了,對吧?不對。Requests簡化了多種身份驗證形式的使用, 包括非常常見的Basic Auth
>>> from requests.auth importHTTPBasicAuth>>> auth = HTTPBasicAuth('fake@example.com', 'not_a_real_password')>>> r = requests.post(url=url, data=body, auth=auth)>>>r.status_code201
>>> content =r.json()>>> print(content[u'body'])
Sounds great! I'll get right on it.
精彩!噢,不!我原本是想說等我一會,因為我得去喂一下我的貓。如果我能夠編輯這條評論那就好了! 幸運的是,GitHub允許我們使用另一個HTTP動詞,PATCH,來編輯評論。我們來試試
>>> 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_code200
非常好。現(xiàn)在,我們來折磨一下這個叫肯尼思的家伙,我決定要讓他急得團團轉,也不告訴他是我在搗蛋。 這意味著我想刪除這條評論。GitHub允許我們使用完全名副其實的DELETE方法來刪除評論。我們來清除該評論。
>>> r = requests.delete(url=url, auth=auth)>>>r.status_code204
>>> r.headers['status']'204 No Content'
很好。不見了。最后一件我想知道的事情是我已經(jīng)使用了多少限額(ratelimit)。查查看,GitHub在響應頭部發(fā)送這個信息, 因此不必下載整個網(wǎng)頁,我將使用一個HEAD請求來獲取響應頭
>>> r = requests.head(url=url, auth=auth)>>> printr.headers
...'x-ratelimit-remaining': '4995'
'x-ratelimit-limit': '5000'...
響應頭鏈接字段
許多HTTP API都有響應頭鏈接字段的特性,它們使得API能夠更好地自我描述和自我顯露。
GitHub在API中為?分頁?使用這些特性,例如:
>>> url = 'https://api.github.com/users/kennethreitz/repos?page=1&per_page=10'
>>> r = requests.head(url=url)>>> r.headers['link']'; rel="next", ; rel="last"'
Requests會自動解析這些響應頭鏈接字段,并使得它們非常易于使用:
>>> 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'}
Blocking Or Non-Blocking:阻塞、非阻塞
使用默認傳輸適配器,不提供任何形式的非阻塞IO請求。響應。內容屬性將阻塞,直到整個反應已經(jīng)被下載。如果你需要更多的粒度,庫的流特性(見流式請求)允許您檢索響應的小批量。然而,這些調用仍然阻止。
如果你擔心使用阻塞IO,有很多的項目,將請求與Python的一個異步性框架。兩個優(yōu)秀的例子是grequests和requests-futures。
Timeouts:超時
大多數(shù)請求外部服務器應該有一個超時,以防服務器沒有響應及時。沒有超時,那么您的代碼就會掛幾分鐘或者更多。
連接超時的秒數(shù)請求將等待你的客戶建立一個連接到一個遠程計算機(對應于connect())調用套接字。它是一個很好的實踐設置連接超時略大于3的倍數(shù),這是默認的TCP數(shù)據(jù)包傳輸窗口。
一旦客戶端連接到服務器,發(fā)送HTTP請求,讀取超時的秒數(shù)客戶端將等待服務器發(fā)送一個響應。(具體地說,它的秒數(shù),客戶端從服務器將字節(jié)之間等待發(fā)送。在99.9%的情況下,這是時間服務器發(fā)送的第一個字節(jié))。
如果你為超時指定一個值,如下:
r = requests.get('https://github.com', timeout=5)
超時的值將被應用到連接和讀取超時。指定一個元組如果你想單獨設置值:
r = requests.get('https://github.com', timeout=(3.05, 27))
如果遠程服務器非常緩慢,你可以告訴請求永遠等待響應,通過沒有作為一個超時值,然后等待
r = requests.get('https://github.com', timeout=None)
總結
以上是生活随笔為你收集整理的pythonrequest得替代_python的扩展包requests的高级用法的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: php获取周几,php怎么获得星期几
- 下一篇: oracle对查询结果求和_oracle
