1 安装 requests 库
打开终端运行:
pip install requests2 发送请求
Requests 库使得发送 HTTP 请求变得异常简单。无论是发送 GET 请求还是其他类型的请求,都只需几行代码。
import requests
# 发送 GET 请求,
r = requests.get('https://api.github.com/events')
# 发送 POST 请求,常用于提交数据
r = requests.post('http://httpbin.org/post')
# 发送 PUT 请求,通常用于更新资源
r = requests.put('http://httpbin.org/put')
# 发送 DELETE 请求,用于删除资源
r = requests.delete('http://httpbin.org/delete')
# 发送 HEAD 请求,会返回响应头,但不包含响应体,通常用于获取响应的元数据
r = requests.head('http://httpbin.org/get')
# 发送 OPTIONS 请求,用来查看服务器支持哪些 HTTP 方法
r = requests.options('http://httpbin.org/get')3 传递 URL参数
在使用 HTTP 请求时,常常需要在 URL 中传递查询参数,requests 提供了方便的方式来处理这类需求。
3.1 使用 params 传递查询参数
如果要将查询参数添加到 URL 中,只需使用 params 关键字参数,它接受一个字典,其中的键值对将被编码为查询字符串。 传递简单的键值对:
import requests
payload = {'key': 'value', 'user': 'admin'}
r = requests.get("http://httpbin.org/get",params=payload)
print(r.url)
# http://httpbin.org/get?key=value&user=admin传递包含 None 值的参数:
import requests
payload = {'key1': 'value1', 'key2': None}
r = requests.get('http://httpbin.org/get', params=payload)
print(r.url)  # http://httpbin.org/get?key1=value1
3.2 传递列表作为参数
也可以将一个列表作为查询参数的值,这样会生成多个相同键的查询参数项。
import 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
4 响应内容解析
Requests 提供了多种方式来读取服务器返回的数据,包括:
- 文本 (
r.text) - 二进制 (
r.content) - JSON (
r.json()) - 原始数据流 (
r.raw) 
| 方法 | 作用 | 适用场景 | 
|---|---|---|
| r.text | 以 str 形式返回响应 | 文本数据(HTML、XML、JSON) | 
| r.encoding | 获取/修改编码 | 服务器返回编码不正确时调整 | 
| r.content | 以 bytes 形式返回 | 图片、视频、二进制文件 | 
| r.json() | 解析 JSON 响应 | API 数据交互 | 
| r.raw | 获取原始 HTTP 响应 | 处理大文件、流式数据 | 
4.1 获取文本内容
r.text 返回的是 解码后的字符串,适用于文本数据。
import requests
r = requests.get('https://api.github.com/events')
print(r.text)  # 以文本方式返回响应内容4.2 处理编码问题
Requests 自动推测 服务器返回的编码:
import requests
r = requests.get('https://api.github.com/events')
print(r.encoding)  # 查看默认编码如果编码不正确,可以手动设置:
适用于服务器返回错误编码时手动调整。
r.encoding = 'ISO-8859-1'  # 修改编码方式4.3 获取二进制内容
r.content 适用于:
- 下载图片
 - 音频、视频文件
 - 其他二进制数据 下载并保存图片:
 
import requests
from PIL import Image
from io import BytesIO
r = requests.get("https://www.example.com/image.jpg")
image = Image.open(BytesIO(r.content))
image.show()  # 显示图片
image.save("downloaded_image.jpg")  # 保存图片4.4 获取JSON 内容
r.json() 适用于 解析 JSON API 响应。
import requests
r = requests.get('https://api.github.com/events')
data = r.json()
print(data)
print(r.json())成功调用 
r.json() 并不意味着响应的成功。有的服务器会在失败的响应中包含一个 JSON 对象(比如 HTTP 500 的错误细节),这种 JSON 会被解码返回。 要检查请求是否成功,请使用 r.raise_for_status() 或者检查 r.status_code 是否和你的期望相同。
判断 JSON 响应是否表示请求失败:
if r.status_code == 200:
    print("请求成功")
else:
    print(f"请求失败,状态码:{r.status_code}")r.raise_for_status() 可以直接抛出错误:
import requests
r = requests.get('https://api.github.com/events')
# 返回 http 响应状态码
print(r.status_code) # 200
# 检查 HTTP 响应的状态码是否表示请求失败(即 4xx 或 5xx 错误)
print(r.raise_for_status()) # None4.5 获取原始响应数据
在 requests.get() 方法中,使用 stream=True 参数会以流式传输的方式获取响应内容(来自服务器的原始套接字响应),而不会立即下载整个响应数据。这样可以减少内存占用,适用于处理大文件或数据流。 r.raw 适用于:
- 大文件下载
 - 需要直接处理 HTTP 数据流
 
import requests
r = requests.get('https://api.github.com/events',stream=True)
# r.raw 是一个 urllib3 的 HTTPResponse 对象
print(r.raw)
# 读取前 10 个字节的数据,返回 `bytes` 类型
print(r.raw.read(10))
# <urllib3.response.HTTPResponse object at 0x00000197A2FD5300>
# b'<!DOCTYPE '正确方式:流式写入文件,避免一次性加载大文件,节省内存!
with open("large_file.bin", "wb") as f:
    for chunk in r.iter_content(chunk_size=1024):  # 每次写入 1KB
        f.write(chunk)5 定制请求头
在 requests 中,通过 headers 参数传递一个字典来添加 HTTP 头部。 使用 requests 访问 httpbin.org/get(该网站会返回所有请求信息):
import requests
url = 'https://httpbin.org/get'
# 自定义请求头
headers = {'User-Agent': 'Python'}
# 自定义请求参数
params = {'name': 'python', 'age': 18}
# 发送 GET 请求
r = requests.get(url, params=params,headers=headers)
# 打印服务器返回的请求信息(包括完整的请求头)
print(r.json())发送的请求信息:
{
    "args": {
        "age": "18",
        "name": "python"
    },
    "headers": {
        "Accept": "*/*",
        "Accept-Encoding": "gzip, deflate",
        "Host": "httpbin.org",
        "User-Agent": "Python",
        "X-Amzn-Trace-Id": "Root=1-67a47fdd-15f1a6ec428509c360ddf41c"
    },
    "origin": "159.65.5.218",
    "url": "https://httpbin.org/get?name=python&age=18"
}优先级注意事项:
.netrc中设置的认证信息优先于headers中的授权信息。- 重定向时,授权头部会被删除。
 - 代理授权头部被 URL 中的代理身份覆盖。
 Content-Length会在内容长度可计算时被改写。 注意:所有头部值必须是string,bytestring或unicode,但不建议使用unicode。
6 POST 请求
6.1 发送表单数据
application/x-www-form-urlencoded
import requests
url = "http://httpbin.org/post"
payload = {'key1': 'value1', 'key2': 'value2'}
r = requests.post(url, data=payload)
print(r.json())  # 返回的数据中 "form" 字段包含提交的内容
多值表单数据:
payload = (('key1', 'value1'), ('key1', 'value2'))
r = requests.post(url, data=payload)6.2 发送 JSON 数据
application/json
import requests
import json
url = "https://api.github.com/some/endpoint"
payload = {'some': 'data'}
# 方式 1:手动编码 JSON
r = requests.post(url, data=json.dumps(payload), headers={'Content-Type': 'application/json'})
# 方式 2:自动编码 JSON(推荐)
r = requests.post(url, json=payload)6.3 上传文件
multipart/form-data
url = "http://httpbin.org/post"
files = {'file': open('report.xls', 'rb')}
r = requests.post(url, files=files)
print(r.json())  # "files" 字段包含上传的文件
自定义文件名、MIME 类型/Headers
files = {'file': ('report.xls', open('report.xls', 'rb'), 'application/vnd.ms-excel', {'Expires': '0'})}
r = requests.post(url, files=files)上传文本文件:
files = {'file': ('report.csv', 'some,data,to,send\nanother,row,to,send\n')}
r = requests.post(url, files=files)6.4 发送超大文件
默认情况下 requests 不支持流式传输大文件,可以使用 requests-toolbelt:
from requests_toolbelt.multipart.encoder import MultipartEncoder
encoder = MultipartEncoder(
    fields={'file': ('large_file.zip', open('large_file.zip', 'rb'), 'application/zip')}
)
headers = {'Content-Type': encoder.content_type}
r = requests.post(url, data=encoder, headers=headers)6.5 注意点
- 建议以二进制模式 (
rb) 打开文件,避免requests计算Content-Length时出错。 requests.post(url, json=payload)自动设置Content-Type: application/json。data=适用于 表单数据,json=适用于 JSON 数据。
7 响应状态码
r.status_code获取响应的 HTTP 状态码。requests.codes.ok提供了对常见状态码的引用(如 200 OK)。raise_for_status()在响应状态码为 4XX 或 5XX 时会抛出HTTPError异常,可以用来处理错误。
7.1 检查状态码
可以通过 status_code 属性来检查 HTTP 响应状态码。
import requests
r = requests.get('http://httpbin.org/get')
print(r.status_code)  # 输出 200,表示请求成功7.2 使用内置状态码对象
Requests 提供了 requests.codes,可以方便地引用常见的 HTTP 状态码:
import requests
r = requests.get('http://httpbin.org/get')
print(r.status_code == requests.codes.ok)  # True,200 OK7.3 处理错误响应
当响应状态码表示客户端错误(4XX)或服务器错误(5XX)时,可以使用 raise_for_status() 来自动抛出异常:
import requests
bad_r = requests.get('http://httpbin.org/status/404')
print(bad_r.status_code)  # 输出 404
# 抛出异常
bad_r.raise_for_status()
# 会引发 requests.exceptions.HTTPError: 404 Client Error7.4 对正常响应调用 raise_for_status()
如果响应状态码是 200(即成功),调用 raise_for_status() 不会做任何事情:
import requests
r = requests.get('http://httpbin.org/get')
r.raise_for_status()  # 没有异常发生8 响应头
- 响应头: 使用 
r.headers获取,返回字典形式的 HTTP 响应头。 - 大小写不敏感: 可以使用不同的大小写来访问响应头字段。
 - 多值字段: 同名的 HTTP 头部字段会被合并为一个值,用逗号分隔。
 
8.1 查看响应头
可以通过 r.headers 查看服务器返回的响应头,它会以一个字典的形式展示:
import requests
r = requests.get('http://httpbin.org/get')
print(r.headers)输出:
{
	'Connection': 'close', 
	'Content-Length': '305', 
	'Access-Control-Allow-Credentials': 'true', 
	'Access-Control-Allow-Origin': '*', 
	'Content-Type': 'application/json', 
	'Date': 'Thu, 06 Feb 2025 09:40:09 GMT', 
	'Server': 'gunicorn/19.9.0'
}8.2 访问响应头字段
响应头是大小写不敏感的,可以使用任意大小写形式来访问字段:
import requests
r = requests.get('http://httpbin.org/get')
print(r.headers['Content-Type'])  # 'application/json'
print(r.headers.get('content-type'))  # 'application/json'8.3 多值响应头
根据 RFC 7230,HTTP 头部允许同一字段多次出现,服务器会将它们合并:
import requests
# 假设服务器返回的响应头包括多个 'set-cookie'
r = requests.get('http://httpbin.org/cookies/set?name=value')
print(r.headers['set-cookie'])  # 服务器将多个值合并这种合并会将多个字段值用逗号隔开,确保信息语义不变。
9 Cookie
- 获取响应 Cookie: 使用 
r.cookies访问返回的 cookies。 - 发送 Cookie: 使用 
cookies参数传递自定义 cookies 给服务器。 - RequestsCookieJar: 适用于更复杂的 Cookie 管理,支持跨域名和路径的 Cookie 操作。
 
9.1 获取响应中的 Cookie
通过 r.cookies 可以获取服务器返回的 cookies。返回的是一个类似字典的对象:
import requests
url = 'http://example.com/some/cookie/setting/url'
r = requests.get(url)
print(r.cookies['example_cookie_name'])  # 输出 Cookie 值9.2 发送 Cookies 到服务器
可以通过 cookies 参数将自定义的 cookies 发送给服务器:
import requests
url = 'http://httpbin.org/cookies'
cookies = {'cookies_are': 'working'}
r = requests.get(url, cookies=cookies)
print(r.text)  # 服务器返回的 cookies 信息输出的 cookies 信息:
{
  "cookies": {
    "cookies_are": "working"
  }
}9.3 管理 Cookie
RequestsCookieJar 提供了更强大的 Cookie 管理功能,可以跨多个域名和路径使用:
import 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)
print(r.text)  # 只会返回设置路径 `/cookies` 下的 cookie输出:
{
  "cookies": {
    "tasty_cookie": "yum"
  }
}10 重定向与请求历史
| 场景 | 默认行为 | 结果 | 
|---|---|---|
GET 请求 | 自动重定向 | r.url 为最终地址,r.history 记录所有跳转 | 
| 禁用重定向 | allow_redirects=False | r.url 为原始地址,r.history 为空 | 
HEAD 请求 | 不自动重定向 | r.history 为空 | 
启用 HEAD 重定向 | allow_redirects=True | r.history 记录跳转 | 
如果需要手动处理重定向,可以禁用 allow_redirects 并从 r.headers['Location'] 读取新的 URL 进行处理。 | 
10.1 默认的重定向
Requests 默认会自动跟随重定向(除了 HEAD 请求)。可以通过 r.history 追踪重定向路径:
import requests
r = requests.get('http://github.com')
print(r.url)           # 最终跳转后的 URL
print(r.status_code)   # 最终响应的状态码(如 200)
print(r.history)       # 记录所有重定向响应对象输出:
https://github.com/
200
[<Response [301]>]说明:
301表示 Github 进行了永久重定向(HTTP → HTTPS)。r.history记录了301的响应对象。
10.2 禁用自动重定向
如果不想让 Requests 自动跟随重定向,可以设置 allow_redirects=False:
r = requests.get('http://github.com', allow_redirects=False)
print(r.status_code)  # 301
print(r.history)      # []说明:r.status_code 为 301,但 r.history 为空,因为没有跟随重定向。
10.3 HEAD 请求的重定向
HEAD 请求默认不会跟随重定向,但可以手动启用:
r = requests.head('http://github.com', allow_redirects=True)
print(r.url)        # 'https://github.com/'
print(r.history)    # [<Response [301]>]11 超时(timeout)
| 超时类型 | 作用 | 示例 | 
|---|---|---|
| 单一超时 | 连接+读取总超时时间 | timeout=5 | 
| 连接超时 | 仅限制 TCP 连接时间 | timeout=(3, None) | 
| 读取超时 | 服务器响应时间 | timeout=(None, 5) | 
| 连接 + 读取 | 连接 3s,读取 5s | timeout=(3, 5) | 
- 生产环境中必须使用 
timeout,避免程序无限等待。 - 推荐 
timeout=(5, 10)作为一般用途的设置。 
11.1 作用
timeout 参数用于设置请求等待服务器响应的超时时间。如果服务器在指定时间内没有响应,则抛出 requests.exceptions.Timeout 异常。
11.2 使用示例
import requests
try:
    r = requests.get('http://github.com', timeout=0.001)
except requests.exceptions.Timeout:
    print("请求超时!")说明:timeout=0.001 设置了 1 毫秒的超时时间,因此请求直接超时并抛出异常。
超时并非请求整个过程的时间:
timeout只影响服务器响应的等待时间,不包括数据传输时间。- 例如,服务器在 1 秒内响应,但传输数据需要 10 秒,
timeout=2仍然不会触发超时异常。 
11.3 设置超时
可以分别指定连接超时和读取超时:
requests.get('http://github.com', timeout=(3, 5))3秒:连接超时时间(建立 TCP 连接的时间)。5秒:读取超时时间(等待服务器响应的时间)。
如果所有请求都需要超时,可以使用 requests.adapters:
from requests.adapters import HTTPAdapter
from requests.sessions import Session
session = Session()
adapter = HTTPAdapter(max_retries=3)  # 允许最多 3 次重试
session.mount('http://', adapter)
session.mount('https://', adapter)
session.get('http://github.com', timeout=5)12 错误与异常处理
raise_for_status()可用于检查响应状态码。- 网络错误 用 
ConnectionError处理,超时 用Timeout处理。 - 捕获所有异常 用 
RequestException,适合用于通用错误处理。 - 推荐 先处理具体异常(如 
HTTPError、Timeout),再用RequestException兜底。 
12.1 常见异常类型
| 异常类型 | 触发条件 | 示例 | 
|---|---|---|
| requests.exceptions.ConnectionError | 网络问题,如 DNS 解析失败、服务器拒绝连接等 | 服务器宕机或域名错误 | 
| requests.exceptions.HTTPError | HTTP 响应状态码为 4xx 或 5xx | r.raise_for_status() 触发 | 
| requests.exceptions.Timeout | 请求超时 | 服务器未在指定时间内响应 | 
| requests.exceptions.TooManyRedirects | 重定向次数超过最大限制 | 发生无限 301/302 循环 | 
| requests.exceptions.RequestException | Requests 的基类异常,捕获所有异常 | 适用于通用异常处理 | 
12.2 异常处理示例
import requests
url = "http://httpbin.org/status/404"  # 触发 404 错误
try:
    r = requests.get(url, timeout=5)
    r.raise_for_status()  # 检查 HTTP 状态码
except requests.exceptions.ConnectionError:
    print("连接错误,可能是网络问题或服务器宕机!")
except requests.exceptions.HTTPError as err:
    print(f"HTTP 错误: {err}")  # 例如 404、500 等错误
except requests.exceptions.Timeout:
    print("请求超时!")
except requests.exceptions.TooManyRedirects:
    print("重定向次数过多!")
except requests.exceptions.RequestException as e:
    print(f"请求异常: {e}")  # 捕获其他异常
else:
    print("请求成功!")
    print(r.text)
12.3 处理所有异常
如果只想捕获 requests 相关异常,可以使用 RequestException:
try:
    r = requests.get(url)
    r.raise_for_status()
except requests.exceptions.RequestException as e:
    print(f"请求失败: {e}")13 会话对象 (Session)
| 功能 | 作用 | 示例 | 
|---|---|---|
共享 cookie | 适用于模拟登录等场景 | s.cookies.set() | 
共享 headers | 设置默认 headers,减少重复代码 | s.headers.update() | 
共享 auth | 适用于 API 认证 | s.auth = (‘user’, ‘pass’) | 
| 保持 TCP 连接 | 避免每次请求重新建立连接,提升性能 | requests.Session() | 
手动管理 cookie | 可手动操作 Session.cookies | s.cookies.set() | 
使用 with 语句 | 确保 Session 退出时自动释放资源 | with requests.Session() as s: | 
13.1 Session 作用
- 保持 
cookie:多个请求之间共享cookie,如模拟用户登录后连续访问页面。 - 减少 TCP 连接:利用 
urllib3的 连接池,减少重复建立 HTTP 连接的开销,提高请求效率。 - 共享默认参数:可以在 
Session对象中定义 默认参数(如headers、auth),避免重复指定。 
13.2 Session 共享 cookie
使用 Session 共享 cookie,多个请求间 cookie 仍然有效!
import requests
s = requests.Session()
# 设置 Cookie
s.get('http://httpbin.org/cookies/set/sessioncookie/123456789')
# 再次请求,Cookie 依然有效
r = s.get("http://httpbin.org/cookies")
print(r.text)  # {"cookies": {"sessioncookie": "123456789"}}
13.3 Session 共享 headers
Session 默认 headers 会与方法级别 headers 合并,方法级别 headers 具有更高优先级!
import requests
s = requests.Session()
s.headers.update({'User-Agent': 'my-app', 'x-test': 'true'})
# 额外增加一个 `headers`,不会覆盖 `Session` 中的默认值
r = s.get('http://httpbin.org/headers', headers={'x-test2': 'true'})
print(r.json())13.4 Session 共享 auth(认证)
Session 适用于 API 认证,避免每次都传递 auth 参数!
import requests
s = requests.Session()
s.auth = ('user', 'pass')
r = s.get('http://httpbin.org/basic-auth/user/pass')
print(r.status_code)  # 200,认证成功13.5 Session 不会自动保留方法级参数
方法级参数(如 cookies)仅对当前请求有效,不会影响后续请求!
import requests
s = requests.Session()
# 仅第一个请求携带 cookies
r1 = s.get('http://httpbin.org/cookies', cookies={'from-my': 'browser'})
print(r1.text)  # {"cookies": {"from-my": "browser"}}
# 第二个请求不会携带 cookies(方法级 cookies 不会跨请求共享)
r2 = s.get('http://httpbin.org/cookies')
print(r2.text)  # {"cookies": {}}13.6 手动操作 Session.cookies
Session.cookies.set() 可以手动添加 cookie,适用于模拟登录等场景!
import requests
s.cookies.set('custom_cookie', 'cookie_value', domain='httpbin.org', path='/')
r = s.get("http://httpbin.org/cookies")
print(r.text)  # {"cookies": {"custom_cookie": "cookie_value"}}13.7 使用 with 语句管理 Session
with 语句确保 Session 退出后自动关闭,避免资源泄露!
import requests
with requests.Session() as s:
    r = s.get('http://httpbin.org/cookies/set/sessioncookie/123456789')
    print(r.status_code)13.8 移除 Session 默认参数
如果需要在 Session 的请求中省略某个默认参数,可以传递 None:
import requests
s = requests.Session()
s.headers.update({'User-Agent': 'my-app', 'x-test': 'true'})
# 移除 `x-test`
r = s.get('http://httpbin.org/headers', headers={'x-test': None})
print(r.json())  # "x-test" 被移除14 请求与响应对象
使用 requests 进行 HTTP 请求时,会涉及两个核心对象:
Request对象:表示发送给服务器的 HTTP 请求。Response对象:表示服务器返回的 HTTP 响应。
| 方法 | 作用 | 
|---|---|
| r.headers | 获取 服务器返回 的响应头 | 
| r.request.headers | 获取 发送请求时 的请求头 | 
r.text / r.content | 获取响应内容(文本 / 字节) | 
| r.json() | 解析 JSON 响应 | 
| r.status_code | 获取 HTTP 状态码 | 
| r.ok | 判断请求是否成功 | 
| r.url | 获取最终请求 URL(考虑重定向) | 
| r.history | 获取请求重定向历史 | 
14.1 发送请求
requests.get() 发送 GET 请求,返回一个 Response 对象 r
import requests
r = requests.get('http://en.wikipedia.org/wiki/Monty_Python')14.2 查看服务器返回的 headers
r.headers 以字典形式存储 HTTP 响应头!
content-length:返回数据的大小(字节)。content-encoding:返回数据的压缩方式(如gzip)。content-type:返回数据的类型(如text/html)。server:服务器使用的软件(如Apache)。
import requests
r = requests.get('http://en.wikipedia.org/wiki/Monty_Python')
print(r.headers)输出:
{
    'content-length': '56170',
    'x-content-type-options': 'nosniff',
    'content-encoding': 'gzip',
    'content-language': 'en',
    'server': 'Apache',
    'cache-control': 'private, must-revalidate',
    'content-type': 'text/html; charset=UTF-8'
}14.3 查看请求头
r.request.headers 获取的是 发送请求时 的 headers!
Accept-Encoding:请求支持的压缩方式(gzip、deflate)。Accept:请求接受的内容类型。User-Agent:发送请求的客户端信息(默认是python-requests)。
import requests
r = requests.get('http://en.wikipedia.org/wiki/Monty_Python')
print(r.request.headers)输出:
{
	'User-Agent': 'python-requests/2.32.3', 
	'Accept-Encoding': 'gzip, deflate', 
	'Accept': '*/*', 
	'Connection': 'keep-alive'
}14.4 获取响应内容
r.text 返回 str(解码后的文本),r.content 返回 bytes(原始数据)! 如果服务器返回 JSON,使用 r.json() 直接解析!
import requests
r = requests.get('http://en.wikipedia.org/wiki/Monty_Python')
print(r.text)  # 以文本形式返回响应内容
print(r.content)  # 以字节形式返回响应内容
print(r.json())  # 解析 JSON 格式的响应14.5 获取状态码
r.status_code 可用于判断请求是否成功! r.ok 返回 True 代表请求成功,False 代表失败!
import requests
r = requests.get('http://en.wikipedia.org/wiki/Monty_Python')
print(r.status_code)  # 200 表示请求成功
print(r.ok)  # True 表示请求成功(状态码 200-399)14.6 获取最终 URL(考虑重定向)
r.url 返回最终的请求 URL,适用于网站重定向!
import requests
r = requests.get('http://en.wikipedia.org/wiki/Monty_Python')
print(r.url)14.7 获取请求历史(重定向情况)
r.history 记录了所有重定向的 Response 对象!
- 如果 
r.history为空,表示没有发生重定向。 - 如果不想自动跟随重定向,可以使用 
allow_redirects=False。 
import requests
r = requests.get('http://en.wikipedia.org/wiki/Monty_Python')
print(r.history) # [<Response [301]>]15 代理设置
对于某些网站,一旦开始大规模、频繁地爬取,网站可能会弹出验证码,或者跳转到登录验证页面,更有甚者可能会直接封禁客户端的IP,导致一定时间内无法访问。为了防止这种情况,需要使用代理来解决这个问题,这就需要用到proxies参数。
15.1 设置代理
通过 proxies 参数配置代理服务器。可以设置 http 和 https 协议的代理:
import requests
proxies = {
    'http': 'http://161.35.4.201:80',
    'https': 'https://161.35.4.201:80'
}
try:
    response = requests.get('http://httpbin.org/get', proxies=proxies)
    print(response.text)
except requests.exceptions.ConnectionError as e:
    print('Error', e.args)15.2 HTTP Basic Auth
如果代理服务器需要身份验证,可以将用户名和密码嵌入代理 URL 中,格式为 http://user:password@host:port:
import requests
proxies = {
    "http": "http://user:password@161.35.4.201:80"
}
r = requests.get("https://www.taobao.com", proxies=proxies)
print(r.text)15.3 Socks 5 代理
Requests 也支持 SOCKS 协议的代理,但需要先安装 socks 库:pip3 install 'requests[socks]' 设置 SOCKS5 代理,支持 http 和 https:
import requests
proxies = {
    'http': 'socks5://user:password@host:port',
    'https': 'socks5://user:password@host:port'
}
requests.get('https://www.taobao.com', proxies=proxies)16 身份验证
访问某网站时,可能会遇到如下的验证页面: 
16.1 HTTP Basic Authentication
使用 requests.auth.HTTPBasicAuth 类或者元组,传入用户名和密码进行身份验证:
import requests
from requests.auth import HTTPBasicAuth
# 使用 HTTPBasicAuth 类
r = requests.get('http://localhost:8080/manager/html', auth=HTTPBasicAuth('admin', '123456'))
print(r.status_code)
# 使用元组
r = requests.get('http://localhost:8080/manager/html', auth=('admin', '123456'))
print(r.status_code)16.2 OAuth 验证
使用 requests_oauthlib 提供的 OAuth1 类进行 OAuth 验证 安装请求库:pip install requests_oauthlib
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)17 PreparedRequest
在 requests 库中,PreparedRequest (准备好的请求)是一种高级功能,允许你在发送请求之前对请求进行更多的控制和处理。相比直接使用 requests.get() 或 requests.post(),通过 PreparedRequest 你可以更细致地操作请求的内容,特别是当你需要将请求头(headers)、请求体(body)等内容分开处理时。
- 步骤:
- 创建 
Request对象并指定请求参数。 - 使用 
Session.prepare_request()预处理请求(保留会话状态和 cookie)。 - 使用 
Session.send()发送处理过的请求。 
 - 创建 
 
from requests import Request, Session
url = 'http://httpbin.org/post'
data = {'name': 'germey'}
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:95.0) Gecko/20100101 Firefox/95.0'
}
# 创建一个 Session 实例
s = Session()
# 构建 Request 对象,包含 URL、数据和请求头
req = Request('POST', url, data=data, headers=headers)
# 使用 Session 对象将 Request 转换为 PreparedRequest
prepped = s.prepare_request(req)
# 发送请求并获取响应
r = s.send(prepped)
# 输出响应内容
print(r.text)
关键点:
- Request 对象:构造请求时,首先通过 
Request类创建一个请求对象,传入 URL、数据、请求头等参数。 - PreparedRequest:通过 
Session.prepare_request()方法将Request对象转换为PreparedRequest,这时可以对请求做额外处理,比如修改请求体、请求头等。 - Session:
Session对象的好处是它能保持会话状态(例如 cookies),并能通过send()方法发送请求。 
18 SSL 证书验证
SSL证书验证是确保你访问的网站安全的过程。当你访问一个HTTPS网站时,浏览器或工具会检查网站的SSL证书是否有效,确保你访问的是合法的网站。
verify=True:默认验证证书。verify='/path/to/certfile':自定义证书验证。verify=False:忽略证书验证(不推荐在生产环境使用)。- 会话保持设置:使用 
Session来保持验证设置。 
18.1 默认验证(verify=True)
默认情况下,requests 会自动验证 SSL 证书。-如果证书验证失败,会抛出 SSLError 错误。
requests.get('https://github.com', verify=True)  # 正常访问18.2 自定义证书文件
如果有自己的 SSL 证书文件,可以传给 verify 参数,进行证书验证:
requests.get('https://github.com', verify='/path/to/certfile')如果将
verify设置为文件夹路径,文件夹需通过 OpenSSL 的c_rehash工具处理。
18.3 忽略证书验证
有时可能不想验证 SSL 证书,特别是访问的是测试网站或者自己搭建的服务器时,通过设置 verify=False,就可以跳过证书验证:
requests.get('https://kennethreitz.org', verify=False)18.4 会话设置
如果需要多次请求相同的服务器,可以用 Session 来保持验证设置,避免每次都传递证书:
s = requests.Session()
s.verify = '/path/to/certfile'18.5 环境变量
如果有全局的证书信任列表,可以通过设置环境变量 REQUESTS_CA_BUNDLE 来让 requests 使用:
export REQUESTS_CA_BUNDLE=/path/to/ca-bundle.crt19 证书
19.1 客户端证书
一些网站要求你提供证书来证明你的身份。你可以将本地证书传给 cert 参数来使用它。 使用客户端证书:可以通过 cert 参数指定本地证书,支持单个文件或证书与私钥的元组。示例:
requests.get('https://kennethreitz.org', cert=('/path/client.cert', '/path/client.key'))会话中设置证书,还可以在会话对象中设置证书。
s = requests.Session()
s.cert = '/path/client.cert'错误路径或无效证书:指定错误路径或无效证书会抛出 SSLError 错误。示例:
requests.get('https://kennethreitz.org', cert='/wrong_path/client.pem')私钥要求解密:私有 key 必须是解密状态,Requests 不支持加密的 key。
19.2 CA 证书
根证书:Requests 默认会使用一套信任的根证书,确保连接的安全。 默认根证书:Requests 默认使用 Mozilla 信任的根证书。 certifi 包:从 Requests 2.4.0 版本后,若系统装有 certifi 包,Requests 会使用它的证书,确保用户可以在不修改代码的情况下更新可信证书。
20 巩固练习
20.1 传递 URL 参数
题目1:如何在 GET 请求中传递多个 URL 参数?
payload = {'key1': 'value1', 'key2': 'value2'}
r = requests.get('http://httpbin.org/get', params=payload)题目2:如果参数字典中的某个值为 None,该值是否会被包含在 URL 中? 不会,None 类型的值不会被添加到 URL 的查询字符串中。 题目3:如何传递一个列表作为 URL 参数?
payload = {'key1': 'value1', 'key2': ['value2', 'value3']}
r = requests.get('http://httpbin.org/get', params=payload)20.2 定制请求头
题目1:如何向请求中添加一个 User-Agent 头部?
headers = {'User-Agent': 'my-app/0.0.1'} r = requests.get('https://api.github.com/some/endpoint', headers=headers)题目2:如何为一个 POST 请求添加 Content-Type 头部?
headers = {'Content-Type': 'application/json'} r = requests.post('https://api.example.com/data', headers=headers, data={'key': 'value'})题目3:当你在请求中设置了 Authorization 头部时,如何确保它不会被 .netrc 中的设置覆盖? 使用 auth 参数时,.netrc 中的认证信息会被忽略,确保 Authorization 头部按照我们手动设置的值进行传递。示例:
headers = {'Authorization': 'Bearer your_token'}
r = requests.get('https://api.example.com/data', headers=headers, auth=('username', 'password'))20.3 响应内容
题目1:如何访问响应的文本内容?
r.text题目2:如何在响应内容中手动设置编码?
r.encoding = 'ISO-8859-1'题目3:如何读取响应的二进制数据并保存为文件?
with open('image.jpg', 'wb') as f: 
	f.write(r.content)20.4 响应头
题目1:如何从响应对象中获取 Content-Type 头部信息?
r.headers['Content-Type']题目2:如何获取响应头的所有字段并展示它们?
print(r.headers)题目3:如何使用 get() 方法访问响应头中的 Content-Encoding 字段?
r.headers.get('Content-Encoding')20.5 请求与响应对象
题目1:如何查看发送的请求头部?
r.request.headers题目2:如何访问响应的原始内容?
r.raw题目3:如何通过 requests.get() 获取一个 JSON 格式的响应?
r = requests.get('https://api.github.com/events') 
data = r.json()20.6 Cookie
题目1:如何通过 requests.get() 获取响应中的 cookies?
r.cookies题目2:如何发送一个自定义 cookie 到服务器?
cookies = {'my_cookie': 'cookie_value'} r = requests.get('http://httpbin.org/cookies', cookies=cookies)题目3:如何为请求手动设置 requests.cookies.RequestsCookieJar 并发送?
jar = requests.cookies.RequestsCookieJar() jar.set('cookie_name', 'cookie_value', domain='httpbin.org', path='/') r = requests.get('http://httpbin.org/cookies', cookies=jar)20.7 重定向与请求历史
题目1:如何查看请求历史中的重定向记录?
r.history题目2:如果要禁用请求的重定向,应该怎么做?
r = requests.get('http://github.com', allow_redirects=False)题目3:如何获取重定向后的 URL 地址?
r.url20.8 Timeout
题目1:如何设置请求的超时时间为 2 秒?
r = requests.get('http://github.com', timeout=2)题目2:超时发生时,如何捕获 Timeout 异常?
try: r = requests.get('http://github.com', timeout=0.001) except requests.exceptions.Timeout: print("请求超时")题目3:超时只对哪个过程有效? 超时仅对连接过程有效,不影响响应体的下载。
20.9 错误与异常
题目1:当 HTTP 状态码不是 2xx 时,如何抛出 HTTPError 异常?
r.raise_for_status()题目2:如何捕获请求中的 ConnectionError 异常?
try: r = requests.get('http://example.com') except requests.exceptions.ConnectionError: print("网络连接错误")题目3:如果请求超时,应该捕获哪个异常?
requests.exceptions.Timeout20.10 Session
题目1:如何创建一个 Session 对象并发出一个请求?
s = requests.Session() r = s.get('http://httpbin.org/get')题目2:如何在会话中保存登录凭证,并在后续请求中使用?
s = requests.Session() s.auth = ('user', 'password') r = s.get('http://httpbin.org/get')题目3:如何确保会话在退出时被关闭?
with requests.Session() as s: s.get('http://httpbin.org/cookies/set/sessioncookie/123456789')20.11 代理
题目 1: 使用一个代理服务器(http://123.45.67.89:8080)发送 GET 请求到 https://httpbin.org/get,并打印出服务器返回的内容。
import requests
proxies = {
    'http': 'http://123.45.67.89:8080'
}
response = requests.get('https://httpbin.org/get', proxies=proxies)
print(response.text)题目 2: 代理服务器需要用户名和密码验证。代理的地址是 http://user123:pass123@45.67.89.101:8080,请使用这个代理访问 http://httpbin.org/get,并打印出返回的内容。
import requests
proxies = {
    'http': 'http://user123:pass123@45.67.89.101:8080'
}
response = requests.get('http://httpbin.org/get', proxies=proxies)
print(response.text)题目 3: 使用 SOCKS5 代理服务器(socks5://user:pass@10.0.0.1:1080)发送一个 GET 请求到 https://api.github.com/users/octocat,并将返回的 JSON 数据打印出来。
import requests
proxies = {
    'http': 'socks5://user:pass@10.0.0.1:1080',
    'https': 'socks5://user:pass@10.0.0.1:1080'
}
response = requests.get('https://api.github.com/users/octocat', proxies=proxies)
print(response.json())20.12 身份验证
题目 1: 使用 HTTP Basic Authentication,访问一个需要认证的页面。已知用户名为 user,密码为 pass,目标 URL 为 http://example.com/protected。请编写代码进行访问,并打印返回的状态码。
import requests
from requests.auth import HTTPBasicAuth
r = requests.get('http://example.com/protected', auth=HTTPBasicAuth('user', 'pass'))
print(r.status_code)题目 2: 使用元组形式的 HTTP Basic Authentication 进行身份验证,访问 http://localhost:5000/dashboard 页面。假设用户名为 admin,密码为 admin123,请编写代码并打印响应的内容。
import requests
r = requests.get('http://localhost:5000/dashboard', auth=('admin', 'admin123'))
print(r.text)题目 3: 使用 OAuth 1.0 验证方式,访问 Twitter API,目标 URL 为 https://api.twitter.com/1.1/statuses/home_timeline.json。请使用以下假设的认证信息:
- 应用密钥: 
YOUR_APP_KEY - 应用密钥秘钥: 
YOUR_APP_SECRET - 用户访问令牌: 
USER_OAUTH_TOKEN - 用户访问令牌秘钥: 
USER_OAUTH_TOKEN_SECRET,编写代码并请求该 API。 
from requests_oauthlib import OAuth1
import requests
url = 'https://api.twitter.com/1.1/statuses/home_timeline.json'
auth = OAuth1("YOUR_APP_KEY", "YOUR_APP_SECRET", "USER_OAUTH_TOKEN", "USER_OAUTH_TOKEN_SECRET")
r = requests.get(url, auth=auth)
print(r.text)20.13 PreparedRequest
题目 1: 什么是 PreparedRequest,它与 Request 对象有什么区别?为什么在某些情况下需要使用 PreparedRequest? PreparedRequest 是在发送请求之前将请求的所有组件(如请求头、请求体等)进行处理并准备好发送的请求对象。与 Request 类相比,PreparedRequest 适用于需要多次发送、修改或者调度的请求,因为它能将请求封装为一个独立的对象。需要使用 PreparedRequest 的情况通常是为了能在发送前修改请求或进行一些额外的处理(比如使用队列)。 题目 2: 请简述下面的代码流程,并说明如何通过 PreparedRequest 向请求中添加查询参数。
from requests import Request, Session
url = 'https://httpbin.org/get'
params = {'key1': 'value1', 'key2': 'value2'}
headers = {'User-Agent': 'my-app/1.0'}
s = Session()
req = Request('GET', url, params=params, headers=headers)
prepped = s.prepare_request(req)
r = s.send(prepped)
print(r.url)代码流程:
- 创建 
Session对象。 - 使用 
Request构造请求对象,指定请求方法、URL、查询参数和请求头。 - 通过 
Session.prepare_request(req)将Request对象转化为PreparedRequest。 - 使用 
Session.send(prepped)发送准备好的请求,并输出请求的完整 URL。 查询参数通过params参数传入Request对象,PreparedRequest会自动将其附加到请求 URL 中。 题目 3: 你需要发送一个包含Authorization头和 JSON 格式数据的POST请求,使用PreparedRequest来准备请求并发送。请写出完整代码。 
from requests import Request, Session
import json
url = 'https://api.example.com/data'
headers = {
    'Authorization': 'Bearer YOUR_TOKEN',
    'Content-Type': 'application/json'
}
data = {'key': 'value'}
# 创建 Session 对象
s = Session()
# 构建 Request 对象
req = Request('POST', url, json=data, headers=headers)
# 准备请求
prepped = s.prepare_request(req)
# 发送请求
r = s.send(prepped)
# 输出响应内容
print(r.status_code)
print(r.text)20.14 SSL 证书验证
题目 1: 你正在访问一个 HTTPS 网站(例如 https://example.com)。如果该网站的 SSL 证书无效,使用 Requests 请求时,会遇到什么错误?并解释如何使用 verify 参数来处理这种情况。 如果 SSL 证书无效,Requests 会抛出 requests.exceptions.SSLError 错误。可以通过传入正确的证书文件路径或设置 verify=False 来避免此错误。
requests.get('https://example.com', verify=True)  # 默认验证,证书无效时会报错题目 2: 你访问一个 HTTPS 网站时,证书验证失败,并且你希望忽略证书验证。在 Requests 请求中,应该如何设置 verify 参数?请写出示例代码。 要忽略证书验证,可以将 verify 参数设置为 False。这样,Requests 将不会检查 SSL 证书是否有效。
requests.get('https://example.com', verify=False)  # 忽略证书验证题目 3: 你有一个 CA 证书文件 my_cert.pem,想要验证访问的 HTTPS 网站的 SSL 证书。在 Requests 请求中,如何使用这个证书文件进行验证?请写出示例代码。 使用 verify='/path/to/certfile' 来指定自己的证书文件进行验证。
requests.get('https://example.com', verify='/path/to/my_cert.pem')  # 使用自定义证书20.15 证书
题目 1: 默认情况下,Requests 如何处理 SSL 证书验证?如果证书验证失败,会发生什么?
a) 会忽略证书验证
b) 会抛出 SSLError
c) 会自动重试请求
d) 会直接跳过请求 答案:
b) 会抛出 SSLError
题目 2: 如果你想在请求中禁用 SSL 证书验证,应该将 verify 参数设置为哪一值?
a) verify=True
b) verify=False
c) verify=1
d) verify=disabled 答案:
b) verify=False
题目 3: 当使用客户端证书进行请求时,如何传递证书路径和私钥路径?
a) cert=('/path/client.cert', '/path/client.key')
b) cert=('/path/client.cert')
c) cert=('/path/client.cert',)
d) cert=('client.cert', 'client.key') 答案:
a) cert=('/path/client.cert', '/path/client.key')

