Requests 模块中文文档(一)

版权声明:转载请标明出处 https://blog.csdn.net/qq_41556318/article/details/86527763

原文链接 -> 传送门

The User Guide(1)

目录

一、为什么我还要重新翻译该文档?

二、开发哲学和协议

三、安装 Requests

四、快速上手

五、高级用法

六、身份认证


一、为什么我还要重新翻译该文档?

大家可能看到原文网页有中文版,为什么我还要重新翻译该文档?

呃……你们如果看过非转基因的纯天然植物饲养的官方中文文档应该就知道为什么了:

卧槽,这是什么鬼,不是我闲得蛋疼,是我觉得这样的官方文档,你们也看不下去……

好了,以下是正文:


Requests 是唯一一个比 Python 亲儿子还好用的 HTTP 库,无毒无副作用,聪明的程序员必备家居良品!

注意:

我们更提倡你使用 Python3 而不是 Python2。如果你此时还在用 Python2,那么你可能需要考虑升级你的应用程序了,因为 Python2 已经 OUT 了;如果你使用的是 Python3,恭喜,你是一枚与时俱进的程序员!

— Kenneth Reitz

下面,先让你们见识一下 Requests 的强大:

>>> import requests
>>> 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, ...}

实现类似功能,Python 的亲儿子要麻烦许多(注意,上面 requests 是一句代码而已):

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import urllib2

gh_url = 'https://api.github.com'

req = urllib2.Request(gh_url)

password_manager = urllib2.HTTPPasswordMgrWithDefaultRealm()
password_manager.add_password(None, gh_url, 'user', 'pass')

auth_manager = urllib2.HTTPBasicAuthHandler(password_manager)
opener = urllib2.build_opener(auth_manager)

urllib2.install_opener(opener)

handler = urllib2.urlopen(req)

print handler.getcode()
print handler.headers.getheader('content-type')

# ------
# 200
# 'application/json'

Requests 允许你发送纯粹的 HTTP/1.1 请求,无需额外的操作。也就是说不需要在 ULR 中添加额外的查询语句,或者对 POST 提交的数据进行编码。另外,Keep-alive 和 HTTP 连接池都是 100% 自动进行的。Requests 能这么牛逼,都是多亏了 urllib3 的助攻!

功能特性

Requests 完全满足当今 web 的需求:

  • Keep-Alive & 连接池
  • 国际化域名和 URLs
  • 带 Cookie 的持久会话
  • 浏览器式的 SSL 认证
  • 内容自动解码
  • 基本/摘要式身份认证
  • 优雅的键/值 Cookie
  • 自动解压
  • Unicode 响应体
  • 支持 HTTP(S) 代理
  • 文件分块上传
  • 流下载
  • 连接超时
  • 分块请求
  • 支持 .netrc

Requests 正式支持 Python 2.6-2.7 和 Python 3.4-3.7,并且在 PyPy 上可以很好的运行哦~

下面这些牛逼的团队正在使用我们的产品:

Twitter、Spotify、Microsoft、Amazon、Lyft、BuzzFeed、Reddit、NSA、英国皇室、Amazon、Google、Twilio、Mozilla、Heroku、PayPal、NPR、奥巴马政府、Transifex、Native Instruments、Washington Post、Twitter、SoundCloud、Kippt、Readability、以及若干不愿意公开身份的联邦政府机构都在内部偷偷地使用我们的产品。

Armin Ronacher ——
Requests 诠释了什么才是完美的 API。

Matt DeBoard ——
我要想办法把 Kenneth Reitz 的 requests 一字不漏的做成纹身。

Daniel Greenfeld ——
感谢 Kenneth Reitz 的 Requests 库,刚刚用 10 行代码就完爆了原来 1200 行意大利面代码,今天真是爽呆了!

Kenny Meyers ——
Python HTTP:疑惑与否,都去用 Requests 吧。简单、优美,并符合 Python 风格。

Requests 是 Python 所有模块中最受欢迎的一个,不是我吹,每个月有 13,000,000 下载量,全世界优秀的人都在使用它,你还等什么?!

哦,对了,你可能早就听人们这么描述程序员 ——“话少钱多死得早,毫无情趣女友跑”……

但伟大的 Kenneth Reitz(Requests 的作者)却扛起厚厚的一块板砖,用实际行动生疼的砸了所有人的脸。

告诉世界:程序员才是最牛逼的潜力股!


二、开发哲学和协议

开发哲学

Requests 是以 PEP20(Python 之禅) 为指导思想开发的:

  • Beautiful is better than ugly.(美丽优于丑陋)
  • Explicit is better than implicit.(直白优于含蓄)
  • Simple is better than complex.(简单优于复杂)
  • Complex is better than complicated.(复杂优于繁琐)
  • Readability counts.(可读性很重要)

如果你想为 Requests 的开发做贡献,那么需要谨记上面的箴言!

Apache2 协议

现在你找到的许多开源项目都是以 GPL 协议发布的。虽然 GPL 有它自己的一席之地,但我们不建议使用这个协议。因为一旦项目发行于 GPL 协议之后,就不能应用于任何本身没开源的商业产品中。

MIT、BSD、ISC、Apache2 协议都是优秀的替代品,它们允许你的开源软件自由地应用在私有闭源的软件中。

因此,Requests 的发布协议为 Apache2 License

Requests 协议

Copyright 2017 Kenneth Reitz

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.


三、安装 Requests

这部分文档包含了 Requests 的安装过程,使用任何软件的第一步就是正确地安装它。

pipenv install requests

要安装 Requests,只需要在你的终端上运行下面这条简单的命令即可:

$ pipenv install requests

如果你的机子上还没有安装 pipenv(啧啧),那么请先安装 pipenv(pipenv 是比 pip 更高级的工具,可以简化依赖关系的管理,在终端上使用 pip install pipenv 命令即可安装);当然你也可以使用 pip 来安装……

获取源代码

Requests 正热火朝天地在不断进化中,你可以在 Github 上获取该项目的源代码。

你可以选择克隆公共仓库的源代码:

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

或者直接下载压缩包

$ curl -OL https://github.com/requests/requests/tarball/master
# 对于 Windows 用户来说,你可以将上述链接的“tarball”换成“zipball”,这样下载下来的就是一个 zip 压缩包。

获得代码之后,你就可以轻松的将它嵌入到你的 python 包里,或者安装到你的 site-packages:

$ cd requests
$ pip install

四、快速上手

已经迫不及待了吗?

本页内容将指引你快速地开始使用 Requests。

让我们先从一些简单的示例开始吧!

发送请求

使用 Requests 发送网络请求非常简单。

一开始先要导入 Requests 模块:

>>> import requests

然后,尝试获取某个网页。本例子中,我们尝试获取 Github 的公共时间轴:

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

现在,我们有一个名为 r 的 Response 对象。我们可以从这个对象中获取所有想要的信息。

Requests 简便的 API 意味着所有 HTTP 请求类型都是显而易见的。

例如,你可以这样发送一个 HTTP POST 请求:

>>> r = requests.post('http://httpbin.org/post', data = {'key':'value'})

很漂亮,对吧?那么其他 HTTP 请求类型:PUT,DELETE,HEAD 以及 OPTIONS 又是如何的呢?

都是一样的简单:

>>> r = requests.put('http://httpbin.org/put', data = {'key':'value'})
>>> r = requests.delete('http://httpbin.org/delete')
>>> r = requests.head('http://httpbin.org/get')
>>> r = requests.options('http://httpbin.org/get')

帅呆了,对吧?但这也仅仅只是 Requests 的冰山一角而已!

传递 URL 参数

我们经常需要通过 URL 的查询字符串传递某种数据,如果是手工构建 URL,那么数据是以键/值对的形式置于 URL 中的。例如,httpbin.org/get?key=val

通过 params 关键字参数,Requests 允许你将这些参数打包为一个字符串字典的形式传递,比如你想传递 key1=value1  和  key2=value2  参数到 httpbin.org/get 中,你可以将代码写成下面这样:

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

看,URL 已经被正确地编码:

>>> print(r.url)
http://httpbin.org/get?key2=value2&key1=value1

注意,字典里值为 None 的键都不会被添加到 URL 的查询字符串里。

你还可以将一个列表作为值传入,Requests 会自动帮你展开:

>>> payload = {'key1': 'value1', 'key2': ['value2', 'value3']}

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

响应内容

我们可以读取服务器响应的内容。再次以 GitHub 的时间轴作为例子:

>>> import requests

>>> r = requests.get('https://api.github.com/events')
>>> r.text
u'[{"repository":{"open_issues":0,"url":"https://github.com/...

Requests 会自动解码来自服务器的内容,大多数 unicode 字符集都能够被自动地解码。

请求发出后,Requests 会基于 HTTP 头部对响应的编码作出有根据的推测。当你访问 r.text 的时候,Requests 会使用其推测出来的文本编码进行解码。你可以通过查看 r.encoding 属性来得知 Requests 使用了什么编码,还能对它进行修改:

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

如果人为地改变了编码,那么每当访问 r.text,Request 都将使用 r.encoding 的新值进行代替。在某些情况下,你还可以应用一些特殊的逻辑计算来获得文本的编码。比如 HTTP 和 XML 自身就可以指定编码,如果是这样的话,你应该使用 r.content 来获取编码,然后设置 r.encoding 为相应的编码值。这样就能使用正确的编码来解析 r.text 了。

在你需要的情况下,Requests 也可以使用定制的编码。如果你创建了自己的编码,并已经使用了 codecs 模块进行注册,就可以轻松地使用这个解码器名称作为 r.encoding 的值, 然后交由 Requests 来为你处理。

二进制响应内容

你也能以字节的方式访问响应的内容,对于非文本请求:

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

Requests 会自动为你解码 gzip 和 deflate 传输编码(为了提高效率,很多服务器将内容进行压缩后再传输)的响应数据。

例如,从服务器返回的二进制数据中创建出一张图片,你可以使用如下代码:

>>> from PIL import Image
>>> from io import BytesIO

>>> i = Image.open(BytesIO(r.content))

JSON 响应内容

Requests 内置了一个 JSON 解码器,可以帮你处理 JSON 格式的数据:

>>> import requests

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

如果 JSON 解码失败, r.json() 就会抛出一个异常。例如响应内容是 204(意思是无内容)的时候;或者当响应内容包含无效的 JSON 数据时,尝试访问 r.json() 就会抛出 ValueError: No JSON object could be decoded 异常。

需要注意的是,成功调用 r.json() 意味着就是响应成功了……因为有的服务器会在失败的响应中包含一个 JSON 对象(比如 HTTP 500 的错误细节)。这种 JSON 同样会被解码后返回。所以若要检查发送的请求是否成功,请使用 r.raise_for_status() 函数或者检查 r.status_code 的值。

原始响应内容

在少数情况下,你可能想要获取来自服务器的原始套接字响应信息,那么你可以通过访问 r.raw 实现。但是在你这么干之前,请先确保在初始请求中设置了 stream=True。具体你可以这么做:

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

然而在通常情况下,你应该以下面的模式将文本流保存到文件中:

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

Response.iter_content 将会帮你处理大量由于直接使用 Response.raw 而不得不处理的内容。 当使用流下载时,我们推荐使用上面代码来获取内容。注意,请根据你的实际情况设置 chunk_size 的值。

自定义请求头

如果你想为请求添加 HTTP 头部,只需要简单地传递一个字典给 headers 参数就可以了。

例如,在前一个示例中我们没有指定 user-agent,现在我们为其加上:

>>> url = 'https://api.github.com/some/endpoint'
>>> headers = {'user-agent': 'my-app/0.0.1'}

>>> r = requests.get(url, headers=headers)

定制 header 的优先级低于某些特定的信息源,例如:

  • 如果在 .netrc 中设置了用户认证信息,使用 headers= 设置的授权就不会生效。而如果设置了 auth= 参数,.netrc 的设置就无效了。
  • 如果被重定向到别的主机,header 的授权就会被删除。
  • header 代理授权会被 URL 中提供的代理身份覆盖掉。
  • 在我们能判断内容长度的情况下,header 的 Content-Length 会被改写。

此外,Requests 不会基于自定义 header 而改变自己的行为。只不过在最后的请求中,所有的 header 信息都会被传递进去。

注意:所有的 header 值必须是 string、bytestring 或者 unicode。尽管传递 unicode header 也是允许的,但我们不建议你这样做。

更复杂的 POST 请求

通常,你经常会需要发送一些编码为表单形式的数据 —— 比如一个 HTML 表单。要实现这个,只需要简单地传递一个字典给 data 参数,这样你的数据字典在发出请求时就会自动编码为表单形式:

>>> payload = {'key1': 'value1', 'key2': 'value2'}

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

你还可以为 data 参数传入一个元组列表。在表单中如果多个元素使用同一个 key,那么这种方式尤其有效:

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

很多时候你想要发送的数据并非表单形式的编码。如果你传递一个 string 而不是一个 dict,那么数据会被直接发送出去。

例如,GitHub API v3 接受编码为 JSON 的 POST/PATCH 数据:

>>> import json

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

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

除了可以自己对 dict 进行编码,你还可以使用 json 参数直接传递数据,它将被自动编码(Requests 2.4.2 版新增特性):

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

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

POST 多部分编码(Multipart-Encoded)的文件

Requests 使得上传多部分编码文件变得很简单:

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

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

你可以显式地设置文件名,文件类型和请求头:

>>> 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)
>>> r.text
{
  ...
  "files": {
    "file": "<censored...binary...data>"
  },
  ...
}

除此之外,你还可以发送作为文件来接收的字符串:

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

在某种情况下,你可能需要发送一个非常大的文件作为 multipart/form-data 请求,你可能希望将请求当作数据流处理。默认情况下 requests 是不支持这种操作的,但有个第三方包 requests-toolbelt 可以拓展这项需求。你可以通过阅读 toolbelt 的文档来了解具体的用法。

在一个请求中发送多个文件,请参考【高级用法】一节

警告

我们强烈建议你用二进制模式(binary mode)打开文件。因为 Requests 可能会试图为你提供 Content-Length 头,当它这样做的时候,这个值会被设为文件的字节数(bytes)。如果用文本模式(text mode)打开文件,就可能会发生错误。

响应状态码

Requests 可以检测响应的状态码:

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

为方便引用,Requests 自带了一个内置的状态码查询对象:

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

如果发送的请求导致错误(一个 4XX 客户端错误,或者 5XX 服务器错误响应),可以通过 Response.raise_for_status() 来抛出异常:

>>> bad_r = requests.get('http://httpbin.org/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 ,当我们调用 raise_for_status() 时,得到的是:

>>> r.raise_for_status()
None

一切都挺和谐的哈~

响应头

我们可以通过一个 Python 字典地形式来查看服务器响应头:

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

这个字典比较特殊:它是仅为 HTTP 头部而生的。根据 RFC 7230 规定,HTTP 头部信息是不缺分大小写的。因此,我们可以使用任意的大小写形式来访问这些响应头字段:

>>> r.headers['Content-Type']
'application/json'

>>> r.headers.get('content-type')
'application/json'

它还有一个特殊的地方,就是服务器可以多次发送同一个 header,但每次都使用不同的值。Requests 会将它们合并,然后通过字典将映射关系表示出来,参见 RFC 7230:

接收者可以合并多个相同名称的 header 栏目,把它们合为一个“field-name: field-value”的键值对,将每个后续的栏目值依次追加到合并的栏目值中,并使用逗号隔开,这样做就不会改变信息的语义。

Cookies

如果某个响应中包含一些 Cookies,你可以快速访问它们:

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

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

要想发送你自己的 cookies 给服务器,可以使用 cookies 参数实现:

>>> url = 'http://httpbin.org/cookies'
>>> cookies = dict(cookies_are='FishC')

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

返回的 Cookies 是 RequestsCookieJar 类的对象,它的行为和字典类似,适合跨域名或跨路径使用。你还可以把 CookieJar 对象传递到 Requests 中去:

>>> jar = requests.cookies.RequestsCookieJar()
>>> jar.set('tasty_cookie', 'yum', domain='httpbin.org', path='/cookies')
>>> jar.set('gross_cookie', 'blech', domain='httpbin.org', path='/elsewhere')
>>> url = 'http://httpbin.org/cookies'
>>> r = requests.get(url, cookies=jar)
>>> r.text
'{"cookies": {"tasty_cookie": "yum"}}'

重定向和历史

默认情况下除了 HEAD,Requests 会自动处理所有重定向。

可以使用响应对象的 history 属性来追踪重定向。

Response.history 是一个 Response 对象的列表,这些对象是为了完成请求而创建的。这个对象列表是按照从旧到新的请求进行排序。

例如,Github 将所有的 HTTP 请求重定向到 HTTPS:

>>> 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
[]

如果你使用了 HEAD,你也可以启用重定向:

>>> r = requests.head('http://github.com', allow_redirects=True)

>>> r.url
'https://github.com/'

>>> r.history
[<Response [301]>]

超时

你可以告诉 Requests 在经过以 timeout 参数设定的秒数后停止等待响应,基本上所有的生产代码都应该使用这一参数,否则你的程序可能会永远地卡在那里:

>>> 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 仅对连接过程有效,与响应体的下载时间无关。因为 timeout 并不是整个下载响应的时间限制,而是如果服务器在 timeout 秒内没有应答,将会引发一个异常(更精确地说,是在 timeout 秒内没有从基础套接字上接收到任何字节的数据时)。如果没有明确填写 timeout 的时间,那么 requests 默认是没有超时限制的。

错误与异常

遇到网络问题(如:DNS 查询失败、拒绝连接等)时,Requests 会抛出一个 ConnectionError 异常。

如果 HTTP 请求返回了不成功的状态码, Response.raise_for_status() 会抛出一个 HTTPError 异常。

若请求超时,则抛出一个 Timeout 异常。

若请求超过了设定的最大重定向次数,则会抛出一个 TooManyRedirects 异常。

所有 Requests 显式抛出的异常都继承自 requests.exceptions.RequestException

猜你喜欢

转载自blog.csdn.net/qq_41556318/article/details/86527763