kp-006
requests 与会话管理
前置知识
本文基于模型知识整理,建议核对官方文档(见 参考资料)。
一句话定义
requests 是 Python 事实标准的 HTTP 客户端;Session 对象在其上提供连接复用与 Cookie 自动携带,是正式采集脚本的标准容器。
为什么重要
裸 requests.get() 每次都是独立请求:不记 Cookie、不复用连接。一旦目标需要「先访问首页拿凭证再进列表页」,裸调用必然失败。会话思维是 kp-010(翻页)、kp-013(登录后采集)的共同前提。
前置知识
kp-002 的报文模型与状态码;kp-005 的环境。
核心概念
- Session:跨请求保持 Cookie 与连接池的对象。
- headers:UA、Referer、Accept-Language 是最常补的三件套。
- timeout:
(连接超时, 读取超时)二元组;不设则可能永久挂起。 - params / data / json:分别构造 URL 查询串、表单体、JSON 体。
- resp.encoding:文本解码依据,乱码时手动指定。
- proxies / verify:代理配置与证书校验开关。
原理与机制
Session 的价值 = 连接池复用(同一主机 TCP/TLS 握手一次)+ Cookie 罐自动「存取回传」。等效于浏览器「访问一次后所有请求自动带会话」的行为。
标准骨架(直接可复用):
import requests, time
HEADERS = {"User-Agent": "Mozilla/5.0 (Macintosh) learn-crawler/1.0"}
def fetch(session: requests.Session, url: str, **kw):
for attempt in range(3): # 有限重试
try:
r = session.get(url, headers=HEADERS, timeout=(5, 20), **kw)
r.raise_for_status() # 4xx/5xx 抛异常
return r
except requests.RequestException as e:
wait = 2 ** attempt # 指数退避: 1s/2s/4s
print(f"[retry {attempt}] {url} -> {e}, sleep {wait}s")
time.sleep(wait)
raise RuntimeError(f"failed after retries: {url}")
with requests.Session() as s:
r = fetch(s, "https://books.toscrape.com/")
r.encoding = "utf-8"
print(len(r.text))
登录态维持的最小示例(练习站 quotes.toscrape.com):
s = requests.Session()
s.post("https://quotes.toscrape.com/login",
data={"username": "demo", "password": "demo"}, timeout=(5, 20))
r = s.get("https://quotes.toscrape.com/", timeout=(5, 20))
# 登录后页面可见 premium 内容,Cookie 已由 Session 自动携带
实例或案例
采集脚本出现「本地能跑、挂机几小时后卡死」:根因几乎总是未设 timeout——某次连接半开导致永久阻塞。给所有请求统一加 (5, 20) 超时 + 有限重试,问题消失。timeout 是采集脚本的第一安全带。
常见误区
- 误区一:不设 timeout。 requests 默认永不超时,生产事故高发第一号。
- 误区二:每次
requests.get()开新请求。 目标站依赖 Cookie 防重复时会被直接拦;也浪费握手开销。 - 误区三:异常静默吞掉。
except: pass会让 403 静默变成空数据,污染下游分析;至少记日志(见 kp-023)。
自测题
- Session 相比裸 get 的两大收益?
答:连接池复用降低握手开销;Cookie 自动维持会话(登录态、防重凭证)。
timeout=(5, 20)两个数字分别限制什么?
答:建立 TCP 连接的耗时上限 5 秒;从收到连接到读完响应体的耗时上限 20 秒。
- 为什么用
raise_for_status()而不是只看状态码?
答:把 4xx/5xx 变成异常进入统一重试/日志通道,避免「返回错误页仍被当成功解析」。
与其他知识点的关系
kp-007 在本篇返回的 HTML 上做解析;kp-017 把这里的退避重试升级为系统化限速;kp-014 教你从抓包里找到该带哪些头。
延伸阅读
requests 官方文档「Advanced Usage — Session Objects」一节。