Python Requests Lib

1. Requests库 开发哲学

Requests 是以 PEP 20 的箴言为中心开发的

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

注意Requests是以Apache2协议发布的。

2. 快速上手

2.1 发送请求

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

r是一个Response对象,其内部有header, text, status_code等参数。

类似的,对于其它类型的请求,我们有

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

2.2 传递URL参数

使用formData类型传递参数。

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

我们输出被正确编码的网址。

http://httpbin.org/get?key1=value1&key2=value2

2.3 响应内容

2.3.1 普通响应
import requests
r = requests.get('https://api.github.com/events')
print(r.text)

request会自动推测编码的类型,当然,你也可以手动设置编码方式。

print(r.encoding)
# out : 'utf-8'
r.encoding = 'ISO-8859-1'
2.3.2 二进制响应

对于非文本请求,可以使用r.content的值来获得响应字节。

from PIL import Image
from io import BytesIO

# 读取r.content图片
i = Image.open(BytesIO(r.content))
2.3.3 JSON响应
import requests

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

需要注意,成功调用r.json()并不意味着响应一定是成功的。有的服务器会在失败的响应中包含一个JSON对象(比如HTTP500的错误细节)。要使用 **r.raise_for_status()**或者检查 r.status_code来确认请求的成功与否。

2.3.4 原始响应内容

直接获取来自服务器的socket响应。

在请求时,打开开关stream=True,并且使用r.raw变量。

r = requests.get('https://api.github.com/events', stream=True)
r.raw
print(r.raw.read(10))

通常情况下,我们将响应的文本流保存至文件。

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

这种模式我们通常用于下载文件。

2.4 定制请求头

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 信息都会被传递进去。

2.5 构造复杂的POST请求

2.5.1 使用Dict模拟formData
payload = {
    'key1': 'value1', 'key2': 'value2'
}

r = requests.post("http://httpbin.org/post", data=payload)
print(r.text)
2.5.2 使用Tuple模拟formData
payload = (('key1', 'value1'), ('key1', 'value2'))
r = requests.post('http://httpbin.org/post', data=payload)
print(r.text)

使用这种构造formData,可以将多个键值设为相同。此时,相同键值的value会合并为一个列表。

{
  ...
  "form": {
    "key1": [
      "value1",
      "value2"
    ]
  },
  ...
}
2.5.3 构造一个字符串形式的请求
import json

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

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

也可以使用json参数直接传递。

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

r = requests.post(url, json=payload)
2.5.4 传递一个多部分编码的文件(Multipart Encoded File)
url = 'http://httpbin.org/post'
files = {'file': open('report.xls', 'rb')}

r = requests.post(url, files=files)
print(r.text)

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

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
# output:
{
  ...
  "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)
print(r.text)
# output: 
{
  ...
  "files": {
    "file": "some,data,to,send\\nanother,row,to,send\\n"
  },
  ...
}

如果你发送一个非常大的文件作为 multipart/form-data 请求,你可能希望将请求做成数据流。默认下 requests 不支持, 但有个第三方包 requests-toolbelt 是支持的。你可以阅读 toolbelt 文档 来了解使用方法。

我们推荐使用二进制的形式打开文件,以防止被错误地默认操作,因为requests库太聪明了,聪明反被聪明误。

2.6 响应状态码

r = request.get('http://httpbin.org/get')
print(r.status_code) # output: 200

库中有常量可供引用。

r.status_code == requests.codes.ok
# output : True

当响应异常时,我们使用Response.raise_for_status()主动抛出异常(因为库函数默认不会抛出异常)。该函数在响应正常时不会抛出异常,无返回值(即返回值为None)。

bad_r = requests.get('http://httpbin.org/status/404')
print(bad_r.status_code)
# output: 404

bad_r.raise_for_status()

2.7 响应头

响应由响应头和响应体构成。r.header对象是响应头,它是一个字典。

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

2.8 Cookie

2.8.1 接收响应Cookie
url = 'http://example.com/some/cookie/setting/url'
r = requests.get(url)

print(r.cookies['example_cookie_name'])
# output: 
'example_cookie_value'
2.8.2 发送Cookie
url = 'http://httpbin.org/cookies'
cookies = dict(cookies_are='working')

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

Cookie的返回对象是RequestsCookieJar,它的行为和字典类似,但接口更为完整,适合跨域名跨路径使用。你还可以把 Cookie Jar 传到 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)
# 只会自动使用指定domain和path下的cookie,因此适合跨域名跨路径使用
r.text
'{"cookies": {"tasty_cookie": "yum"}}'

2.9 重定向与历史请求

默认情况下,除了 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]>]

2.10 超时,错误与异常

2.10.1 超时

生产代码中,我们需要使用超时限制,否则程序可能永远失去响应。

>>> 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)
2.10.2 错误与异常

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

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

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

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值