Python Requests庫:HTTP for Humans

Python標準庫中用來處理HTTP的模塊是urllib2,不過其中的API太零碎了,requests是更簡單更人性化的第三方庫。python

用pip下載:nginx

pip install requests

或者git:git

git clone git://github.com/kennethreitz/requests.git

發送請求:

GET方法github

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

POST方法:web

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

也可使用其它方法:json

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

也能夠將請求方法放在參數中:api

>>> import requests
>>> req = requests.request('GET', 'http://httpbin.org/get')

傳遞參數或上傳文件:

1.若是要將參數放在url中傳遞,使用params參數,能夠是字典或者字符串:cookie

>>> payload = {'key1': 'value1', 'key2': 'value2'}
>>> r = requests.get("http://httpbin.org/get", params=payload)
>>> r.url
u'http://httpbin.org/get?key2=value2&key1=value1'

2.若是要將參數放在request body中傳遞,使用data參數,能夠是字典,字符串或者是類文件對象。session

使用字典時將發送form-encoded data:app

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

使用字符串時將直接發送數據:

>>> import json
>>> url = 'https://api.github.com/some/endpoint'
>>> payload = {'some': 'data'}
>>> r = requests.post(url, data=json.dumps(payload))

流上傳:

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

Chunk-Encoded上傳:

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

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

3.若是要上傳文件,可使用file參數發送Multipart-encoded數據,file參數是{ 'name': file-like-objects}格式的字典 (or {'name':('filename', fileobj)}) :

>>> url = 'http://httpbin.org/post'
>>> files = {'file': open('report.xls', 'rb')}
>>> r = requests.post(url, files=files)
>>> r.text
{
  ...
  "files": {
    "file": "<censored...binary...data>"
  },
  ...
}

也能夠明確設置filename, content_type and headers:

>>> 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)
>>> print r.text
{
  "args": {}, 
  "data": "", 
  "files": {
    "file": "1\t2\r\n"
  }, 
  "form": {}, 
  "headers": {
    "Content-Type": "multipart/form-data; boundary=e0f9ff1303b841498ae53a903f27e565", 
    "Host": "httpbin.org", 
    "User-Agent": "python-requests/2.2.1 CPython/2.7.3 Windows/7", 
  }, 
  "url": "http://httpbin.org/post"
}

一次性上傳多個文件,好比能夠接受多個值的文件上傳:

<input type="file" name="images" multiple="true" required="true"/>

只要把文件放到一個元組的列表中,其中元組結構爲(form_field_name, file_info):

>>> 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
{
  ...
  'files': {'images': 'data:image/png;base64,iVBORw ....'}
  'Content-Type': 'multipart/form-data; boundary=3131623adb2043caaeb5538cc7aa0b3a',
  ...
}

設置Headers

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

Response對象:

 獲取unicode字符串,會自動根據響應頭部的字符編碼(r.encoding)進行解碼,固然也能夠本身設定r.encoding:

>>> r = requests.get('https://github.com/timeline.json')
>>> r.text
u'{"message":"Hello there, wayfaring stranger...

獲取bytes字符串,會自動解碼gzip和deflate數據:

>>> r.content
'{"message":"Hello there, wayfaring stranger. ..

要存儲web圖片,能夠:

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

能夠解碼json對象:

>>> r.json()
{u'documentation_url': u'https://developer...

返回raw response,須要在requests請求中將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'

若是不想一次性處理所有的數據,能夠:

tarball_url = 'https://github.com/kennethreitz/requests/tarball/master'
r = requests.get(tarball_url, stream=True)
if int(r.headers['content-length']) < TOO_LONG:
  content = r.content
  ...

也能夠迭代的處理數據:

with open(filename, 'wb') as fd:
    for chunk in r.iter_content(chunk_size):
        fd.write(chunk)

或者:

import json
import requests
r = requests.get('http://httpbin.org/stream/20', stream=True)
for line in r.iter_lines():
    # filter out keep-alive new lines
    if line:
        print(json.loads(line))

獲取響應代碼:

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

獲取響應headers:

>>> r.headers
{
    'content-encoding': 'gzip',
    'transfer-encoding': 'chunked',
    'connection': 'close',
    'server': 'nginx/1.0.4',
    'x-runtime': '148ms',
    'etag': '"e1ca502697e5c9317743dc078f67693f"',
    'content-type': 'application/json'
}

獲取發送的headers

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

Cookie

獲取cookie,返回CookieJar對象:

>>> url = 'http://www.baidu.com'
>>> r = requests.get(url)
>>> r.cookies

將CookieJar轉爲字典:

>>> requests.utils.dict_from_cookiejar(r.cookies)
{'BAIDUID': '84722199DF8EDC372D549EC56CA1A0E2:FG=1', 'BD_HOME': '0', 'BDSVRTM': '0'}

將字典轉爲CookieJar:

requests.utils.cookiejar_from_dict(cookie_dict, cookiejar=None, overwrite=True)

上傳本身設置的cookie,使用cookies參數,能夠是字典或者CookieJar對象:

>>> url = 'http://httpbin.org/cookies'
>>> cookies = dict(cookies_are='working')
>>> r = requests.get(url, cookies=cookies)
>>> r.text
'{"cookies": {"cookies_are": "working"}}'

若是須要在會話中保留cookie,須要用到後面要說的Session。

Redirection and History重定向

默認狀況下,除了 HEAD, Requests 會自動處理全部重定向。

可使用響應對象的history屬性來追蹤重定向。

Response.history 是一個 Response 對象的列表。這個對象列表按照從最老到最近的請求進行排序。

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

若是你使用的是GET、OPTIONS、POST、PUT、PATCH 或者 DELETE,那麼你能夠經過 allow_redirects 參數禁用重定向處理:

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

若是你使用了 HEAD,你也能夠啓用重定向:

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

Session

要在會話中保留狀態,可使用request.Session()。

Session可使用get,post等方法,Session對象在請求時容許你保留必定的參數和自動設置cookie

s = requests.Session()
s.get('http://httpbin.org/cookies/set/sessioncookie/123456789')   #cookie保留在s中
r = s.get("http://httpbin.org/cookies") #再次訪問時會保留cookie
print(r.text)
# '{"cookies": {"sessioncookie": "123456789"}}'

也能夠本身設置headers,cookies:

s = requests.Session()
s.auth = ('user', 'pass')
s.headers.update({'x-test': 'true'})
s.get('http://httpbin.org/headers', headers={'x-test2': 'true'})    #  'x-test' and 'x-test2' 都會被髮送

預設Request

能夠在發送request前作些額外的設定

from requests import Request, 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) 

驗證

Basic Authentication

>>> from requests.auth import HTTPBasicAuth
>>> requests.get('https://api.github.com/user', auth=HTTPBasicAuth('user', 'pass'))
<Response [200]>

由於HTTP Basic Auth很經常使用,因此也能夠直接驗證:

>>> requests.get('https://api.github.com/user', auth=('user', 'pass'))
<Response [200]>

Digest Authentication

>>> from requests.auth import HTTPDigestAuth
>>> url = 'http://httpbin.org/digest-auth/auth/user/pass'
>>> requests.get(url, auth=HTTPDigestAuth('user', 'pass'))
<Response [200]>

OAuth 1 Authentication

>>> import requests
>>> from requests_oauthlib import OAuth1
>>> url = 'https://api.twitter.com/1.1/account/verify_credentials.json'
>>> auth = OAuth1('YOUR_APP_KEY', 'YOUR_APP_SECRET',
                  'USER_OAUTH_TOKEN', 'USER_OAUTH_TOKEN_SECRET')
>>> requests.get(url, auth=auth)
<Response [200]>

也可使用本身寫的驗證類。好比某個web服務接受將X-Pizza報頭設置成密碼的驗證,能夠這樣寫驗證類:

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

使用:

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

SSL證書驗證

檢查主機的ssl證書:

>>> requests.get('https://kennethreitz.com', verify=True)
    raise ConnectionError(e)
ConnectionError: HTTPSConnectionPool(host='kennethreitz.com', port=443): Max retries exceeded with url: / (Caused by <class 'socket.error'>: [Errno 10061] )

github是有的:

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

若是你設置驗證設置爲False,也能夠忽略驗證SSL證書:

>>> requests.get('https://github.com', verify=False)

 會有警告,忽略警告:

from requests.packages import urllib3
urllib3.disable_warnings()

能夠指定一個本地證書用做客戶端證書,能夠是單個文件(包含密鑰和證書)或一個包含兩個文件路徑的元組:

>>> requests.get('https://kennethreitz.com', cert=('/path/server.crt', '/path/key'))

或者在session中保持:

s = requests.Session()
s.cert = '/path/client.cert'

能夠直接信任全部ssl證書:

import ssl
ssl._create_default_https_context = ssl._create_unverified_context

代理

使用代理:

import requests
proxies = {
  "http": "http://10.10.1.10:3128",
  "https": "http://10.10.1.10:1080",
}
requests.get("http://example.org", proxies=proxies)

能夠設置環境變量:

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

若是代理須要驗證:

proxies = {
    "http": "http://user:pass@10.10.1.10:3128/",
}
相關文章
相關標籤/搜索