Requests模块简介
Requests是一个简单易用的Python库,用于发送HTTP请求。它旨在简化HTTP请求的发送和处理,使得开发者可以轻松地与Web服务进行交互。自2011年发布以来,Requests因其易用性、灵活性和强大的功能而广受欢迎,成为Python开发者在进行网络请求时的首选工具。
Requests 支持 Python 2.6—2.7以及3.3—3.7,而且能在 PyPy 下完美运行。
官方文档:https://requests.readthedocs.io/projects/cn/zh-cn/latest/user/install.html
源码地址:https://github.com/psf/requests
[!CAUTION]
以下Python代码中,关于请求的URL地址均来自Requests官方文档或者网络地址,所以各位可以放心使用不用担心调不通。
PS:很早就学了,但是发现自己当时没做笔记,搭建了自己的个人网站发现没几篇文章……
主要特性
- 简洁的API: Requests提供了一个直观的API,使得发送GET、POST、PUT、DELETE等HTTP请求变得异常简单。
- 自动处理查询字符串和表单编码: 无需手动对URL参数进行编码,Requests会自动处理这些细节。
- 自动内容解码: Requests会自动解码来自服务器的响应内容,无论是JSON、HTML还是其他格式。
- 会话和Cookie持久化: 通过会话对象,Requests可以自动处理Cookie,使得维持会话状态变得简单。
- SSL/TLS验证: Requests支持SSL/TLS验证,确保与HTTPS服务的通信安全。
- 身份认证支持: 包括基本认证、摘要认证以及OAuth等身份认证方式。
- 代理支持: Requests允许通过HTTP代理发送请求。
- 流式请求和响应: 对于大文件或长连接,Requests支持流式传输,有效管理内存使用。
- 错误和异常处理: Requests定义了一系列异常,使得错误处理变得简单明了。
安装和使用
安装Requests非常简单,只需通过pip安装即可:
pip install requests
使用Requests发送一个GET请求的示例:
import requests
# 发送get请求
r = requests.get("https://www.baidu.com")
# 设置编码
r.encoding = "utf-8"
# 打印响应内容
print(r.text)
Requests以其优雅的设计和强大的功能,成为了Python开发者在进行HTTP通信时的首选库。无论是简单的API调用,还是复杂的Web服务交互,Requests都能提供稳定而高效的支持。
快速上手
发送请求
发送get请求
import requests
# 发送get请求
r = requests.get('https://api.github.com/events')
# 设置编码
r.encoding = "utf-8"
print(r.text)
发送post请求
# 发送post请求
r = requests.post('https://httpbin.org/post', data={'name': 'taishang'})
# 设置编码
r.encoding = "utf-8"
print(r.text)
其他类型请求
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.get方法向指定的URL发送一个GET请求,并将响应对象赋值给变量r。
- 通过访问响应对象的status_code属性,可以获取到HTTP响应的状态码。r.status_code的值是200,表示请求成功。
- 内置的状态码查询对象:
- requests库提供了一个内置的对象requests.codes,可以用来方便地引用和比较HTTP状态码。
- 通过比较r.status_code和requests.codes.ok(其中ok是200状态码的别名),结果是True,说明请求成功。
- 错误请求的处理:
- 如果发送了一个错误请求,比如一个4XX客户端错误或5XX服务器错误,可以通过调用响应对象的raise_for_status()方法来抛出一个异常。
- bad_r = requests.get('http://httpbin.org/status/404')这个请求会返回一个404状态码,表示资源未找到。
- 当调用bad_r.raise_for_status()时,会抛出一个HTTPError异常,因为404是一个客户端错误。
- 正常请求的处理:
- 对于状态码为200的正常请求,调用raise_for_status()方法不会抛出异常,而是返回None,表示没有错误发生。
成功示例
r = requests.get('http://httpbin.org/get')
print(r.status_code)
print(r.raise_for_status())
# 结果
200
None
失败示例
r = requests.get('http://httpbin.org/status/404')
print(r.status_code)
print(r.raise_for_status())
控制台抛出异常,显示如下:
常见的请求状态码
HTTP状态码(HTTP Status Codes)是服务器对客户端请求的响应状态的代码。以下是一些常见的HTTP状态码及其含义:
1xx:信息性状态码
- 100 Continue:继续。客户端应继续其请求。
- 101 Switching Protocols:切换协议。服务器根据客户端的请求切换协议。
2xx:成功状态码
- 200 OK:请求成功。最常见的成功状态码。
- 201 Created:已创建。成功请求并创建了新的资源。
- 202 Accepted:已接受。已接收请求,但尚未处理。
- 204 No Content:无内容。请求成功,但没有内容返回。
3xx:重定向状态码
- 301 Moved Permanently:永久移动。请求的资源已被永久移动到新位置。
- 302 Found:临时移动。请求的资源临时被移动。
- 304 Not Modified:未修改。自从上次请求后,资源未修改,可使用缓存的版本。
4xx:客户端错误状态码
- 400 Bad Request:错误请求。服务器无法理解请求。
- 401 Unauthorized:未授权。请求需要用户的身份认证。
- 403 Forbidden:禁止访问。服务器理解请求但拒绝执行。
- 404 Not Found:未找到。请求的资源不存在。
- 405 Method Not Allowed:方法不允许。请求方法(如GET、POST)对资源不适用。
- 408 Request Timeout:请求超时。服务器等待请求时超时。
- 409 Conflict:冲突。请求与服务器当前状态冲突。
5xx:服务器错误状态码
- 500 Internal Server Error:内部服务器错误。服务器遇到错误,无法完成请求。
- 501 Not Implemented:未实现。服务器不支持请求的功能。
- 502 Bad Gateway:错误网关。服务器作为网关或代理,从上游服务器收到无效响应。
- 503 Service Unavailable:服务不可用。服务器暂时过载或维护。
- 504 Gateway Timeout:网关超时。网关或代理服务器在等待另一个服务器响应时超时。
响应方法
• response.headers
:返回响应头的字典。
• response.encoding
:返回响应内容的编码。
• response.elapsed
:返回一个timedelta对象,表示从发送请求到接收响应的时间。
• response.close()
:关闭响应的连接。
• response.content
:以字节形式返回响应内容。
• response.cookies
:返回一个CookieJar对象,包含服务器发送的cookies。
• response.history
:返回一个响应对象列表,包含请求的历史记录(URL)。
• response.is_permanent_redirect
:如果响应是永久重定向的URL,返回True。
• response.is_redirect
:如果响应是重定向的,返回True。
• response.iter_content()
:迭代响应内容。
• response.json()
:如果响应是JSON格式的,返回一个JSON对象;否则引发错误。
• response.url
:返回响应的URL。
• response.text
:以Unicode形式返回响应内容。
• response.status_code
:返回状态码。
• response.request
:返回请求对象,该对象请求了这个响应。
• response.reason
:返回与状态码对应的文本。
• response.raise_for_status()
:如果发生错误,返回一个HTTPError对象。
• response.ok
:如果状态码小于200,返回True;否则返回False。
• response.links
:返回响应头中的链接。
传递URL参数
我们平时使用浏览器访问页面时,经常能够看到http://httpbin.org/get?key2=value2&key1=value1
这样格式的参数,在python代码中我们当然也可以这么拼接使用。但是总归不够优雅,Requests给我们提供了一种优雅地方式,使用params参数:
payload = {'name': 'taishang', 'age': '27'}
r = requests.get("http://httpbin.org/get", params=payload)
print(r.url)
注意:
字典里值为 None
的键都不会被添加到 URL 的查询字符串里。
响应编码
正常情况下,Requests 会自动解码来自服务器的内容。大多数 unicode 字符集都能被无缝地解码。请求发出后,Requests 会基于 HTTP 头部对响应的编码作出有根据的推测。当访问 r.text
之时,Requests 会使用其推测的文本编码。
r = requests.get('https://api.github.com/events')
print('响应编码:' + r.encoding)
print('响应内容:' + r.text)
但是有些时候Requests推测的编码是不准确的,例如百度首页,这时候就需要手动设置响应编码了。
r = requests.get('https://www.baidu.com/')
print('响应编码:' + r.encoding)
print('响应内容:' + r.text)
手动设置响应编码为utf-8。
r = requests.get('https://www.baidu.com/')
# 设置编码格式
r.encoding = 'utf-8'
print('响应编码:' + r.encoding)
二进制资源下载
我们可以使用Requests请求网络资源,获取二进制的响应内容,从而将内容以文件的形式保存到本地。
以二进制的方式将响应内容存储到本地
我们用下面这个美女链接为例,图片将会保存到我们当前py文件的文件夹下:
# 使用二进制响应的形式保存图片到本地 https://cdn.pixabay.com/photo/2024/07/03/15/40/beauty-8870258_1280.png
r = requests.get('https://cdn.pixabay.com/photo/2024/07/03/15/40/beauty-8870258_1280.png')
with open('test.png', 'wb') as f:
f.write(r.content)
二进制内容如下:
r = requests.get('https://cdn.pixabay.com/photo/2024/07/03/15/40/beauty-8870258_1280.png')
print(r.content)
大体积资源应使用Response.iter_content分块读取
之所以使用Response.iter_content
主要有以下几点考虑:
- 内存效率:Response.iter_content 允许以流的形式迭代内容,这意味着可以在下载的同时逐块处理数据,而不需要将整个响应体一次性加载到内存中。对于大文件或者大体积的数据,这可以显著减少内存的使用。
- 避免内存溢出:如果一次性将大体积的响应内容加载到内存中,可能会导致内存溢出,特别是在内存资源受限的环境中。使用 Response.iter_content 可以避免这种情况,因为它允许控制每次处理的数据量。
下面使用IDEA进行大体积文件下载的演示,这里我还使用tqdm
添加了进度条功能,以方便我了解下载进度以及下载用时:
import requests
from tqdm import tqdm
def download_file(url, local_filename):
"""
从指定的URL下载文件并显示下载进度。
参数:
url (str): 文件的URL。
local_filename (str): 本地保存的文件名。
"""
# 发送GET请求到URL
with requests.get(url, stream=True) as response:
# 如果请求不成功,抛出异常
response.raise_for_status()
# 从响应头获取总文件大小
total_size_in_bytes = int(response.headers.get('content-length', 0))
# 初始化进度条
with tqdm(total=total_size_in_bytes, unit='iB', unit_scale=True) as progress_bar:
# 以二进制写模式打开本地文件
with open(local_filename, 'wb') as file:
# 分块读取响应数据
for data in response.iter_content(chunk_size=1024):
# 将数据写入本地文件
file.write(data)
# 更新进度条
progress_bar.update(len(data))
# 示例用法
url = 'https://download-cdn.jetbrains.com.cn/idea/ideaIU-2024.3.exe'
local_filename = 'ideaIU-2024.3.exe'
download_file(url, local_filename)
下载进度:
结果展示:
定制请求头
Requests模块支持我们自定义请求头信息,只要简单地传递一个 dict
给 headers
参数就可以了。
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 会被改写。
注意:
所有的 header 值必须是 string
、bytestring 或者 unicode。尽管传递 unicode header 也是允许的,但不建议这样做。
POST 请求的复杂数据发送
发送表单数据
-
字典形式:可以使用字典传递数据,requests 会自动将其编码为表单形式。
payload = {'key1': 'value1', 'key2': 'value2'} r = requests.post("http://httpbin.org/post", data=payload) print(r.text)
响应示例:
{ "args": {}, "data": "", "files": {}, "form": { "key1": "value1", "key2": "value2" }, "headers": { "Accept": "*/*", "Accept-Encoding": "gzip, deflate", "Content-Length": "23", "Content-Type": "application/x-www-form-urlencoded", "Host": "httpbin.org", "User-Agent": "python-requests/2.32.3", "X-Amzn-Trace-Id": "Root=1-674b92cd-48441c8d2b0dd0e022962b81" }, "json": null, "origin": "116.23.222.187", "url": "http://httpbin.org/post" }
-
元组列表形式:适用于表单中
多个元素使用同一 key
的情况。payload = (('key1', 'value1'), ('key1', 'value2')) r = requests.post('http://httpbin.org/post', data=payload) print(r.text)
响应示例:
{ "args": {}, "data": "", "files": {}, "form": { "key1": [ "value1", "value2" ] }, "headers": { "Accept": "*/*", "Accept-Encoding": "gzip, deflate", "Content-Length": "23", "Content-Type": "application/x-www-form-urlencoded", "Host": "httpbin.org", "User-Agent": "python-requests/2.32.3", "X-Amzn-Trace-Id": "Root=1-674b9300-5e32755e6e740f0d732fb8bc" }, "json": null, "origin": "116.23.222.187", "url": "http://httpbin.org/post" }
发送非表单数据
-
字符串形式
如果传递的是字符串而不是字典,数据会被直接发送。
url = 'https://api.github.com/some/endpoint' payload = {'some': 'data'} r = requests.post(url, data=json.dumps(payload))
发送 JSON 数据
-
手动编码:可以手动将字典编码为 JSON 字符串。
import json url = 'https://api.github.com/some/endpoint' payload = {'some': 'data'} r = requests.post(url, data=json.dumps(payload))
-
自动编码:从 requests 2.4.2 版本开始,可以直接传递字典给 json 参数,requests 会自动进行 JSON 编码。
url = 'https://api.github.com/some/endpoint' payload = {'some': 'data'} r = requests.post(url, json=payload)
上传多部分编码文件(Multipart-Encoded)
基本文件上传
- 使用requests.post方法上传文件。
- 将文件以二进制模式打开,并作为字典传递给files参数。
示例:
url = 'http://httpbin.org/post'
files = {'file': open('test.txt', 'rb')}
r = requests.post(url, files=files)
r.encoding = 'utf-8'
print("请求状态码:", r.status_code)
print("请求响应内容:", r.text)
设置文件名、类型和请求头
可以显式地设置上传文件的文件名、文件类型(MIME类型)和请求头。
示例:
url = 'http://httpbin.org/post'
files = {'file': ('test.txt', open('test.txt', 'rb'), 'application/txt', {'Expires': '0'})}
r = requests.post(url, files=files)
print("请求状态码:", r.status_code)
print("请求响应内容:", r.text)
上传字符串作为文件
可以将字符串作为文件上传,只需在元组中包含文件名和字符串数据。
示例:
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.status_code)
print("请求响应内容:", r.text)
Cookie
访问响应中的Cookie
- 当使用requests.get(url)发送一个HTTP GET请求到指定的URL时,如果服务器的响应中包含了Cookie,可以通过r.cookies这个属性来访问这些Cookie。
- r.cookies是一个RequestsCookieJar对象,它的行为类似于字典,可以通过r.cookies['example_cookie_name']的方式来获取名为example_cookie_name的Cookie的值。
示例:
url = 'https://www.baidu.com'
r = requests.get(url)
print(r.cookies.get_dict())
print(r.cookies['BDORZ'])
结果:
{'BDORZ': '27315'}
27315
发送Cookie到服务器
- 如果想在发送请求时附带Cookie,可以使用cookies参数。
- 例如,可以创建一个字典cookies = dict(cookies_are='working'),然后将其作为参数传递给requests.get(url, cookies=cookies)。
- 服务器接收到请求后,可以在响应中看到发送的Cookie,这里显示的响应文本是'{"cookies": {"cookies_are": "working"}}',表明Cookie已经被成功发送并由服务器接收。
示例:
url = 'http://httpbin.org/cookies'
cookies = dict(cookies_are='working')
r = requests.get(url, cookies=cookies)
print(r.text)
结果:
{
"cookies": {
"cookies_are": "working"
}
}
使用RequestsCookieJar
- RequestsCookieJar是一个更为完整的Cookie管理接口,它不仅行为类似于字典,还支持跨域名和跨路径的Cookie使用。
- 可以创建一个RequestsCookieJar对象,使用jar.set方法来添加Cookie。例如,jar.set('tasty_cookie', 'yum', domain='httpbin.org', path='/cookies')会在httpbin.org的/cookies路径下设置一个名为tasty_cookie的Cookie,值为'yum'。
- 同样,可以设置多个Cookie,并且指定它们各自的域名和路径。
- 当将这个CookieJar对象作为cookies参数传递给requests.get(url, cookies=jar)时,所有的Cookie都会被发送到服务器。
- 服务器的响应会显示发送的Cookie,这里显示的是'{"cookies": {"tasty_cookie": "yum"}}',表明只有tasty_cookie被成功发送并由服务器接收,这可能是因为gross_cookie的路径不匹配。
示例:
jar = requests.cookies.RequestsCookieJar()
# 添加cookie,并设置cookie对应的路径和域名
jar.set('tasty_cookie', 'yum', domain='httpbin.org', path='/cookies')
jar.set('gross_cookie', 'blech', domain='baidu.com', path='/')
r = requests.get('http://httpbin.org/cookies', cookies=jar)
print(r.text)
结果:
{
"cookies": {
"tasty_cookie": "yum"
}
}
重定向与请求历史
- 在HTTP请求中,有时服务器会指示客户端(比如浏览器)去另一个URL获取资源,这就是
重定向
。 - requests库默认会自动处理所有的重定向请求,除了HEAD请求。
- GET、OPTIONS、POST、PUT、PATCH 或者 DELETE,可以通过
allow_redirects
参数禁用重定向处理
追踪重定向
可以通过响应对象(Response对象)的history方法来追踪重定向的过程。
Response.history是一个包含Response对象的列表,这些对象代表了为了完成最终请求而创建的所有中间响应。列表按照从最早的请求到最近的
请求排序。
示例:
- 以访问GitHub为例,GitHub会将所有的HTTP请求重定向到HTTPS。
- 当使用requests.get('http://github.com')时,requests库会自动处理这个重定向。
- 最终的URL会变成https://github.com/,状态码是200(成功)。
- r.history会显示一个列表,包含一个状态码为301的Response对象,表示发生了一次重定向。
r = requests.get('http://github.com')
print('最终url:', r.url)
print('请求状态:', r.status_code)
print('重定向历史:')
for response in r.history:
print(response.url)
结果:
最终url: https://github.com/
请求状态: 200
重定向历史:
http://github.com/
禁用重定向
通过设置allow_redirects=Fasle
可以禁用GET、OPTIONS、POST、PUT、PATCH 、DELETE请求的重定向。
示例:
r = requests.get('http://github.com', allow_redirects=False)
print('最终url:', r.url)
print('请求状态:', r.status_code)
print('重定向历史:')
for response in r.history:
print(response.url)
结果:
最终url: http://github.com/
请求状态: 301
重定向历史:
启用HEAD请求的重定向
默认情况下,HEAD请求不会自动处理重定向,但可以通过设置allow_redirects=True
参数来启用重定向处理。这样,requests库会处理HEAD请求的重定向,就像处理其他类型的请求一样。
默认情况
r = requests.head('http://github.com')
print('最终url:', r.url)
print('请求状态:', r.status_code)
print('重定向历史:')
for response in r.history:
print(response.url)
# 结果
最终url: http://github.com/
请求状态: 301
重定向历史:
启用重定向
r = requests.head('http://github.com', allow_redirects=True)
print('最终url:', r.url)
print('请求状态:', r.status_code)
print('重定向历史:')
for response in r.history:
print(response.url)
# 结果
最终url: https://github.com/
请求状态: 200
重定向历史:
http://github.com/
设置请求超时时间
在 Requests 库中,如果没有明确指定 timeout 参数,那么默认情况下是没有超时限制的
。这意味着 Requests 会无限期地等待服务器的响应,直到服务器返回数据或者连接被服务器关闭。
timeout 参数用于指定等待服务器响应的时间,如果在指定的时间内没有收到响应,就会抛出一个 Timeout 异常。这个参数可以在接受请求时设置,例如:
requests.get('http://example.com', timeout=5) # 设置5秒超时
注意:timeout
仅对连接过程有效,与响应体的下载无关。 timeout
并不是整个下载响应的时间限制,而是如果服务器在 timeout
秒内没有应答,将会引发一个异常(更精确地说,是在 timeout
秒内没有从基础套接字上接收到任何字节的数据时)如果未明确指定超时,则请求不会超时。
错误与异常
- 遇到网络问题(如:DNS 查询失败、拒绝连接等)时,Requests 会抛出一个
ConnectionError
异常。 - 如果 HTTP 请求返回了不成功的状态码,
Response.raise_for_status()
会抛出一个HTTPError
异常。 - 若请求超时,则抛出一个
Timeout
异常。 - 若请求超过了设定的最大重定向次数,则会抛出一个
TooManyRedirects
异常。 - 所有Requests显式抛出的异常都继承自
requests.exceptions.RequestException
。
评论区