Python编程:requests 库中的session
在 Python 的 requests 库中,Session 对象是一个非常重要的概念,它允许你在多个请求之间保持某些参数和状态。
Session 的基本概念
Session 对象能够:
-
在多个请求之间保持 cookies
-
保持连接池,提高性能
-
保持某些请求参数(如 headers、auth 等)
使用 Session 的优势
-
性能提升:重用底层 TCP 连接,减少连接建立的开销
-
保持状态:自动处理 cookies,无需手动管理
-
统一配置:可以为所有请求设置默认参数
基本用法
import requests
# 创建一个 Session 对象
s = requests.Session()
# 设置 Session 级别的参数
s.headers.update({'User-Agent': 'MyApp/1.0'})
# 使用 Session 发起请求
response = s.get('https://httpbin.org/get')
# 关闭 Session (通常不需要手动关闭,除非明确需要)
s.close()
常用功能
1. 保持 Cookies
s = requests.Session()
s.get('https://httpbin.org/cookies/set/sessioncookie/123456789')
r = s.get('https://httpbin.org/cookies')
print(r.text) # 会显示之前设置的 cookie
2. 设置默认参数
s = requests.Session()
s.auth = ('user', 'pass')
s.headers.update({'x-test': 'true'})
# 这些参数会自动应用到所有请求
r = s.get('https://httpbin.org/headers', headers={'x-test2': 'true'})
3. 连接池管理
Session 会自动管理连接池,默认情况下会重用连接。
上下文管理器用法
with requests.Session() as s:
s.get('https://httpbin.org/cookies/set/sessioncookie/123456789')
# 离开 with 块后 Session 会自动关闭
Session.request() 方法
requests 库的核心请求处理逻辑集中在 sessions.py 的 Session.request() 方法中。下面将 逐层深入分析 该方法的实现细节,从参数处理到最终发送请求的全流程。
1. 方法签名
def request(self, method, url, params=None, data=None, headers=None, cookies=None,
files=None, auth=None, timeout=None, allow_redirects=True, proxies=None,
hooks=None, stream=None, verify=None, cert=None, json=None):
-
核心参数:
-
method: HTTP 方法(GET/POST等) -
url: 请求地址 -
params: URL 查询参数(自动编码) -
data: 表单数据(字典或字节) -
json: JSON 请求体(自动序列化) -
headers: 自定义请求头 -
timeout: 超时时间(秒) -
proxies: 代理配置
-
2. 执行流程分解
步骤 1:合并配置
# 合并会话级配置和本次请求的局部配置 headers = merge_setting(headers, self.headers) proxies = merge_setting(proxies, self.proxies)
-
会话级配置(如
self.headers)会被本次请求的headers参数覆盖。
步骤 2:构造 Request 对象
req = Request(
method=method.upper(),
url=url,
headers=headers,
files=files,
data=data or {},
json=json,
params=params or {}
)
-
Request类(定义在models.py)封装原始请求信息。
步骤 3:预处理请求
prep = self.prepare_request(req)
-
prepare_request()关键操作:-
参数编码:
if params: # 编码 URL 查询参数 url = requote_uri(url + '?' + urlencode(params)) -
数据序列化:
if json is not None: # 自动序列化 JSON body = json.dumps(json) headers['Content-Type'] = 'application/json' -
文件上传处理:
if files: # 生成 multipart/form-data body, content_type = encode_multipart_formdata(files) headers['Content-Type'] = content_type
-
步骤 4:选择适配器
adapter = self.get_adapter(url=url)
-
适配器选择逻辑:
-
根据 URL 的协议(
http://或https://)选择对应的HTTPAdapter。 -
默认使用
urllib3作为底层实现。
-
步骤 5:发送请求
resp = adapter.send(
request=prep,
stream=stream,
timeout=timeout,
verify=verify,
cert=cert,
proxies=proxies
)
-
adapter.send()关键操作:-
连接池管理:
conn = self.poolmanager.connection_from_url(url) # 从池中获取连接
-
发送 HTTP 请求:
urllib3_response = conn.urlopen( method=request.method, url=url, body=request.body, headers=request.headers, timeout=timeout ) -
处理重定向(若
allow_redirects=True):while 'location' in response.headers: next_url = response.headers['location'] response = adapter.send(next_url) # 递归发送新请求
-
步骤 6:构建 Response 对象
response = self.build_response(prep, resp)
-
build_response()关键操作:response = Response() response.status_code = urllib3_response.status response.headers = CaseInsensitiveDict(urllib3_response.headers) response.raw = urllib3_response # 原始 urllib3 响应 response.request = prep # 关联原始请求
3. 关键子方法解析
3.1 merge_setting()(配置合并)
-
优先级:局部参数 > 会话级配置 > 全局默认值。
-
示例:
session = Session() session.headers.update({'User-Agent': 'MyApp/1.0'}) # 本次请求使用特殊 UA session.get(url, headers={'User-Agent': 'Crawler'})
3.2 prepare_request()(请求预处理)
-
核心任务:
-
序列化 JSON 数据
-
编码 URL 参数
-
生成 multipart 文件上传体
-
-
源码位置:
sessions.py的prepare_request()方法。
3.3 get_adapter()(适配器选择)
-
默认映射:
self.mount('http://', HTTPAdapter()) self.mount('https://', HTTPAdapter()) -
扩展点:可通过
session.mount()注册自定义适配器。
4. 请求生命周期钩子(Hooks)
requests 支持在请求处理过程中插入钩子函数:
def log_response(resp, *args, **kwargs):
print(f"Response: {resp.status_code}")
session = Session()
session.hooks['response'] = [log_response]
session.get('https://httpbin.org/get')
-
支持的钩子类型:
-
request: 请求发出前 -
response: 收到响应后
-
5. 超时与重试机制
5.1 超时控制
-
参数格式:
timeout=5 # 连接+读取总超时 timeout=(3, 5) # 连接超时 3s,读取超时 5s
-
底层实现:通过
urllib3的timeout参数传递。
5.2 自动重试
需自定义适配器实现:
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
retry_strategy = Retry(
total=3, backoff_factor=1, status_forcelist=[500, 502]
)
adapter = HTTPAdapter(max_retries=retry_strategy)
session.mount("https://", adapter)
6. 总结:request() 方法执行流程图

| 步骤 | 对应代码/模块 | 关键操作 |
|---|---|---|
| 合并配置 | merge_setting() | 合并会话级配置(如 self.headers)和本次请求参数 |
| 构造Request对象 | models.Request | 封装 method/url/headers/data 等原始信息 |
| 预处理请求 | prepare_request() | 编码 URL 参数、序列化 JSON、生成 multipart 文件体 |
| 选择适配器 | get_adapter() | 根据 URL 协议选择 HTTP/HTTPS 适配器(默认 urllib3) |
| 发送请求 | adapter.send() | 通过连接池发送请求,处理超时和代理 |
| 处理重定向 | resolve_redirects() | 自动跟进 30x 跳转(若 allow_redirects=True) |
| 构建Response | build_response() | 将 urllib3 响应转换为 requests.Response 对象 |
| 返回结果 | - | 返回最终响应(可能经过多次重定向) |
通过逐层分析,我们可以看到 requests 如何通过 清晰的模块划分 和 灵活的配置合并 实现简洁而强大的 HTTP 客户端功能。
更多推荐
所有评论(0)