Cookie 管理与模拟登录
一、概述:为什么需要理解 Cookie 与模拟登录
1.1 问题的起点
在爬虫开发中,大量有价值的数据隐藏在登录墙之后:用户个人信息、订单记录、好友动态、会员专属内容……要获取这些数据,爬虫必须具备"证明自己身份"的能力。这就是 Cookie 管理与模拟登录 要解决的核心问题。
HTTP 协议本身是无状态的——服务器不会记住"上一个请求是谁发的"。Cookie 和 Session 正是为了解决这个问题而生的:Cookie 在客户端存储身份标识,Session 在服务器端维护会话状态,两者配合,让无状态的 HTTP 能够承载有状态的登录流程。
1.2 本章覆盖范围
本章从原理到实战,系统讲解以下几个层面的内容:
- 原理层:Cookie 与 Session 的完整工作机制
- 工具层:
requests.Session的自动 Cookie 管理、持久化与恢复 - 策略层:表单登录、Cookie 注入、OAuth/JWT 令牌三种主流模拟登录策略
- 工程层:Cookie 池的设计与实现(含 Redis 存储方案)
- 安全层:常见陷阱排查与安全提醒
1.3 技术栈与版本要求
本章所有代码示例均基于 Python 3.10+,依赖库如下:
| 库 | 版本要求 | 用途 |
|---|---|---|
requests | >= 2.31 | HTTP 请求与 Session 管理 |
lxml | >= 5.0 | HTML 解析提取 CSRF Token |
redis | >= 5.0 | Cookie 池存储后端 |
flask | >= 3.0 | Cookie 池 API 接口 |
selenium | >= 4.15 | 浏览器自动化备选方案 |
pip install requests>=2.31 lxml>=5.0 redis>=5.0 flask>=3.0二、Cookie 与 Session 机制原理
2.1 一张图理解完整流程
在深入代码之前,先通过一张时序图建立全局认知。下图展示了从用户首次访问到登录成功,再到后续请求携带 Cookie 验证身份的完整链路:
2.2 Cookie 的属性与安全约束
理解 Cookie 的每个属性,对于正确模拟 Cookie 和排查问题至关重要:
| 属性 | 说明 | 典型值 | 爬虫注意事项 |
|---|---|---|---|
| Name/Value | Cookie 的键值对 | session_id=abc123 | 核心关注点,Value 是身份凭证 |
| Domain | 作用域名 | .github.com | 子域名 Cookie 可能不共享 |
| Path | 作用路径 | / | /admin 路径的 Cookie 不会发到 /api |
| Max-Age | 有效期(秒) | 1209600(2周) | 正值=持久 Cookie,负值=会话 Cookie |
| Expires | 过期绝对时间 | Wed, 21 Oct 2026 07:28:00 GMT | 与 Max-Age 同时存在时 Max-Age 优先 |
| HttpOnly | 禁止 JS 读取 | true | 爬虫不受影响——此限制仅针对浏览器 JS,HTTP 请求头仍可携带 |
| Secure | 仅 HTTPS 传输 | true | 爬虫需使用 HTTPS 请求 |
| SameSite | 跨站发送策略 | Strict / Lax / None | 跨站请求时需关注 |
2.3 Session 与 Token 的对比
认证机制的选型决定了爬虫的登录策略。以下是三种主流机制的核心区别:
| 特性 | Cookie + Session | JWT Token | OAuth 2.0 |
|---|---|---|---|
| 存储位置 | Session 在服务端,Session ID 在 Cookie | Token 在客户端 | Token 在客户端 |
| 服务器状态 | 有状态(需存储 Session) | 无状态 | 无状态(资源服务器) |
| 爬虫策略 | 模拟登录获取 Cookie | 获取 Token 放入 Authorization 头 | 模拟授权流程获取 Token |
| 典型场景 | 传统 Web 网站(如 GitHub) | API 服务、SPA 应用 | 第三方登录 |
三、requests.Session:自动管理 Cookie
3.1 为什么使用 Session
requests.Session 是 requests 库中最强大的特性之一,它解决了 Cookie 管理的核心痛点:
- 自动保存:每次请求后,响应中的
Set-Cookie自动存入 Session - 自动携带:后续请求自动带上所有已保存的 Cookie
- 连接复用:底层 TCP 连接复用,减少握手开销
- 全局配置:统一的 headers、proxies、auth 等配置,无需每次传入
# Python 3.10+
import requests
# 不使用 Session —— 每次请求独立,Cookie 不会保留
r1 = requests.get("https://httpbin.org/cookies/set/foo/bar")
r2 = requests.get("https://httpbin.org/cookies")
print(r2.json()) # {"cookies": {}} —— Cookie 丢失!
# 使用 Session —— 自动管理 Cookie
session = requests.Session()
r1 = session.get("https://httpbin.org/cookies/set/foo/bar")
r2 = session.get("https://httpbin.org/cookies")
print(r2.json()) # {"cookies": {"foo": "bar"}} —— Cookie 保留!3.2 Cookie 的持久化与恢复
长时间运行的爬虫需要将 Cookie 持久化,避免每次启动都重新登录。以下是生产环境可用的方案:
# Python 3.10+
import json
import os
from pathlib import Path
import requests
import logging
logger = logging.getLogger(__name__)
class CookiePersistence:
"""Cookie 持久化管理 —— 支持保存到文件、从文件恢复、自动校验"""
def __init__(self, session: requests.Session, cookie_file: str = "cookies.json"):
self.session = session
self.cookie_file = Path(cookie_file)
def save(self) -> None:
"""将 Session 中的 Cookie 保存为 JSON 文件"""
cookies: list[dict[str, str]] = []
for cookie in self.session.cookies:
cookies.append({
"name": cookie.name,
"value": cookie.value,
"domain": cookie.domain,
"path": cookie.path,
})
self.cookie_file.write_text(json.dumps(cookies, indent=2, ensure_ascii=False))
logger.info(f"Cookie 已保存到 {self.cookie_file}({len(cookies)} 条)")
def load(self) -> bool:
"""从 JSON 文件恢复 Cookie 到 Session"""
if not self.cookie_file.exists():
logger.warning(f"Cookie 文件不存在: {self.cookie_file}")
return False
cookies: list[dict] = json.loads(self.cookie_file.read_text())
for cookie in cookies:
self.session.cookies.set(
cookie["name"],
cookie["value"],
domain=cookie.get("domain"),
path=cookie.get("path"),
)
logger.info(f"已从 {self.cookie_file} 恢复 {len(cookies)} 条 Cookie")
return True
def is_valid(self, check_url: str) -> bool:
"""向 check_url 发送请求,通过响应判断 Cookie 是否有效"""
try:
resp = self.session.get(check_url, allow_redirects=False, timeout=10)
# 有效的 Cookie 不应被重定向到登录页
return resp.status_code == 200 and "login" not in resp.url.lower()
except requests.RequestException:
return FalseCookie 文件包含登录凭证,应妥善保管:不要提交到 Git 仓库(添加到 .gitignore),不要分享给他人,生产环境建议加密存储。
四、模拟登录策略
4.1 策略一:表单登录(分析 + 构造 POST)
这是最经典、最通用的模拟登录方式。核心思路是分析登录接口,构造请求参数,使用 Session 提交。
以下代码基于 Python 3.10+ 语法(类型注解、dict 泛型等),请确保运行环境满足要求。
通用表单登录流程:
# Python 3.10+
import requests
from lxml import etree
import logging
logger = logging.getLogger(__name__)
class FormLoginClient:
"""通用表单登录客户端"""
def __init__(self, login_page_url: str, login_action_url: str):
self.session = requests.Session()
self.login_page_url = login_page_url
self.login_action_url = login_action_url
self._setup_headers()
def _setup_headers(self) -> None:
self.session.headers.update({
"User-Agent": (
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/120.0.0.0 Safari/537.36"
),
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
})
def _extract_csrf_token(self, html: str, token_field_name: str = "authenticity_token") -> str | None:
"""
从登录页面 HTML 中提取 CSRF Token。
使用 XPath 为主,正则表达式为备选方案。
"""
# 策略1:XPath 解析
selector = etree.HTML(html)
tokens = selector.xpath(f'//input[@name="{token_field_name}"]/@value')
if tokens:
return str(tokens[0])
# 策略2:正则表达式兜底
import re
pattern = rf'name="{token_field_name}"\s+value="([^"]+)"'
match = re.search(pattern, html)
if match:
return match.group(1)
return None
def login(self, username: str, password: str,
extra_fields: dict[str, str] | None = None) -> bool:
"""
执行表单登录。
Args:
username: 用户名/邮箱
password: 密码
extra_fields: 额外的表单字段(如 commit、utf8 等固定值)
Returns:
bool: 登录是否成功
"""
# 步骤1:访问登录页面,获取初始 Cookie 和 CSRF Token
logger.info("正在访问登录页面...")
response = self.session.get(self.login_page_url)
csrf_token = self._extract_csrf_token(response.text)
if csrf_token is None:
logger.error("无法提取 CSRF Token,请检查页面结构")
return False
logger.info(f"CSRF Token 获取成功: {csrf_token[:20]}...")
# 步骤2:构造登录表单
form_data: dict[str, str] = {
"login": username,
"password": password,
"authenticity_token": csrf_token,
}
if extra_fields:
form_data.update(extra_fields)
# 步骤3:提交登录请求
logger.info("正在提交登录表单...")
response = self.session.post(
self.login_action_url,
data=form_data,
allow_redirects=True,
)
# 步骤4:验证登录结果
return self._verify_login(response)
def _verify_login(self, response: requests.Response) -> bool:
"""通过多种方式验证登录是否成功"""
# 方式1:检查特定 Cookie 是否出现
if "logged_in" in self.session.cookies:
return True
# 方式2:检查页面内容中的登录标识
if "Sign out" in response.text or "logout" in response.text.lower():
return True
return False
def fetch_protected(self, url: str) -> str | None:
"""获取需要登录才能访问的页面"""
resp = self.session.get(url)
return resp.text if resp.status_code == 200 else None以 GitHub 为例的实战调用:
# Python 3.10+
client = FormLoginClient(
login_page_url="https://github.com/login",
login_action_url="https://github.com/session",
)
success = client.login(
username="your_email@example.com",
password="your_password",
extra_fields={"commit": "Sign in", "utf8": "✓"},
)
if success:
print("登录成功!")
# 爬取登录后才能访问的个人设置页
profile_html = client.fetch_protected("https://github.com/settings/profile")
else:
print("登录失败,请检查用户名/密码或分析登录接口变化")4.2 策略二:Cookie 注入(从浏览器复制)
当目标网站的反爬机制较强(如 JS 加密参数、复杂验证码),或者登录次数很少时,直接从浏览器复制已登录的 Cookie 是最快的方式。
操作步骤:
- 在浏览器中手动登录目标网站
- 打开开发者工具(F12),进入 Application > Storage > Cookies
- 复制所需的 Cookie 键值对
- 注入到爬虫的 Session 中
# Python 3.10+
import requests
def parse_cookie_string(cookie_str: str) -> dict[str, str]:
"""
将浏览器复制的 Cookie 字符串解析为字典。
输入示例: "name1=value1; name2=value2; name3=value3"
"""
cookies: dict[str, str] = {}
for item in cookie_str.split(";"):
item = item.strip()
if "=" in item:
key, _, value = item.partition("=")
cookies[key.strip()] = value.strip()
return cookies
# 从浏览器复制的 Cookie 字符串
cookie_string = "logged_in=yes; dotcom_user=zhang; user_session=xyz789"
session = requests.Session()
session.headers.update({
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
})
# 方式1:通过 cookies 参数传递
cookies_dict = parse_cookie_string(cookie_string)
resp = session.get("https://github.com/settings/profile", cookies=cookies_dict)
# 方式2:直接注入到 Session(推荐,后续请求自动携带)
session.cookies.update(cookies_dict)
resp = session.get("https://github.com/settings/profile")
print(f"状态码: {resp.status_code},页面长度: {len(resp.text)}")- 浏览器复制的 Cookie 会过期,需要定期更新
- 某些 Cookie 可能绑定 IP 或 User-Agent,复制时需一并模拟
- 不适用于大规模、长时间运行的采集任务
4.3 策略三:OAuth / JWT 令牌方式
越来越多的现代网站采用 Token 认证(尤其是 API 服务)。相比 Cookie,Token 方式通常更稳定、更易维护。
# Python 3.10+
import requests
# === JWT Token 认证 ===
session = requests.Session()
session.headers.update({
"Authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"User-Agent": "Mozilla/5.0 ...",
})
# 直接请求 API,无需 Cookie
resp = session.get("https://api.example.com/user/profile")
print(resp.json())
# === GitHub Personal Access Token 认证 ===
# 在 GitHub Settings > Developer settings > Personal access tokens 创建
session = requests.Session()
session.headers.update({
"Authorization": "token ghp_xxxxxxxxxxxxxxxxxxxx",
"Accept": "application/vnd.github+json",
})
resp = session.get("https://api.github.com/user")
print(resp.json())三种策略的适用场景对比:
| 策略 | 难度 | 稳定性 | 自动化程度 | 适用场景 |
|---|---|---|---|---|
| 表单登录 | 中 | 中 | 高 | 常规网站,需分析接口 |
| Cookie 注入 | 低 | 低 | 低 | 临时采集、反爬较强的网站 |
| Token 认证 | 低 | 高 | 高 | API 服务、有 Token 获取渠道 |
五、验证码 + 登录组合处理
验证码是模拟登录中最常见的障碍。根据验证码类型,选择不同的处理策略:
| 验证码类型 | 难度 | 推荐方案 | 工具 |
|---|---|---|---|
| 简单图形验证码 | 低 | OCR 识别 | ddddocr、pytesseract |
| 复杂图形验证码 | 中 | 打码平台 | 超级鹰、云打码 |
| 滑动/点选验证码 | 高 | 浏览器自动化 | Selenium / Playwright |
| 短信验证码 | 中 | 接码平台 | 各接码平台 |
使用 Selenium 处理验证码的混合方案:
# Python 3.10+
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import requests
def login_with_selenium_and_export_cookies(
login_url: str, username: str, password: str
) -> dict[str, str]:
"""
使用 Selenium 完成登录(包括验证码处理),然后导出 Cookie 供 requests 使用。
典型应用场景:requests 无法处理的验证码,由 Selenium 人工或半自动处理。
"""
options = webdriver.ChromeOptions()
options.add_argument("--disable-blink-features=AutomationControlled")
driver = webdriver.Chrome(options=options)
wait = WebDriverWait(driver, 15)
try:
driver.get(login_url)
# 填写表单
username_input = wait.until(EC.presence_of_element_located((By.NAME, "username")))
username_input.send_keys(username)
driver.find_element(By.NAME, "password").send_keys(password)
driver.find_element(By.CSS_SELECTOR, "button[type='submit']").click()
# 如果有验证码,手动处理
input("请在浏览器中完成验证码,然后按 Enter 继续...")
# 导出 Cookie
return {c["name"]: c["value"] for c in driver.get_cookies()}
finally:
driver.quit()
# 使用 Selenium 登录,导出 Cookie 后切换到 requests
cookies = login_with_selenium_and_export_cookies(
"https://example.com/login", "username", "password"
)
session = requests.Session()
session.cookies.update(cookies)
# 后续全部使用 requests 高效爬取
resp = session.get("https://example.com/dashboard")六、Cookie 池的设计与实现
6.1 为什么要建 Cookie 池
单账号 Cookie 存在三个致命弱点:有效期短(过期后爬虫中断)、频率限制(单账号请求量有上限)、封禁风险(一经封禁全盘皆输)。Cookie 池通过多账号轮换,将这三个风险分散到多个账号上,是规模化爬虫的基础设施。
6.2 架构设计
Cookie 池由五大核心模块组成,各模块职责清晰、松耦合:
各模块职责:
| 模块 | 职责 | 关键设计 |
|---|---|---|
| 存储模块 | Cookie 持久化 | Redis Hash,Key=cookies:{website},Field=账号名,Value=JSON |
| 获取模块 | 模拟登录获取 Cookie | 可扩展的登录器架构,新增网站只需实现 BaseLoginer 子类 |
| 检测模块 | 验证 Cookie 有效性 | 请求验证 URL,根据响应码/内容判断 |
| 接口模块 | 对外提供 REST API | GET /get/<website> 随机返回一个有效 Cookie |
| 调度模块 | 协调定时任务 | 获取间隔 1 小时,检测间隔 10 分钟 |
6.3 Redis 存储方案
选择 Redis 的理由:Hash 结构天然适合"网站-账号"的二级映射;支持 TTL 过期自动清理;高并发下性能优异。
# Python 3.10+
import redis
import json
import random
import time
import logging
logger = logging.getLogger(__name__)
class CookieStore:
"""
Cookie 存储管理 —— 基于 Redis Hash。
数据结构:
Key: cookies:{website}
Field: {username}
Value: {"cookies": {...}, "status": "valid/invalid", "updated": 1700000000}
"""
def __init__(self, host: str = "localhost", port: int = 6379,
db: int = 0, password: str | None = None):
self.redis = redis.StrictRedis(
host=host, port=port, db=db, password=password,
decode_responses=True,
)
logger.info(f"Redis 连接成功: {host}:{port}")
def _key(self, website: str) -> str:
return f"cookies:{website}"
def set(self, website: str, username: str, cookies: dict, status: str = "valid") -> None:
"""存储 Cookie"""
value = json.dumps({
"cookies": cookies,
"status": status,
"updated": int(time.time()),
}, ensure_ascii=False)
self.redis.hset(self._key(website), username, value)
logger.info(f"Cookie 已存储: {website}:{username} ({status})")
def get_random(self, website: str) -> dict | None:
"""随机获取一个有效 Cookie"""
all_data = self.redis.hgetall(self._key(website))
valid_accounts = [
(username, json.loads(data))
for username, data in all_data.items()
if json.loads(data).get("status") == "valid"
]
if not valid_accounts:
logger.warning(f"{website} 无可用 Cookie")
return None
username, data = random.choice(valid_accounts)
logger.info(f"随机获取: {website}:{username}")
return data.get("cookies")
def set_status(self, website: str, username: str, status: str) -> None:
"""更新 Cookie 状态"""
data = self.get(website, username)
if data:
self.set(website, username, data["cookies"], status)
def get(self, website: str, username: str) -> dict | None:
"""获取指定账号的 Cookie"""
value = self.redis.hget(self._key(website), username)
return json.loads(value) if value else None
def delete(self, website: str, username: str) -> None:
"""删除指定账号的 Cookie"""
self.redis.hdel(self._key(website), username)
def count(self, website: str, status: str | None = None) -> int:
"""统计 Cookie 数量"""
all_data = self.redis.hgetall(self._key(website))
if status is None:
return len(all_data)
return sum(1 for v in all_data.values() if json.loads(v).get("status") == status)
def get_all(self, website: str, status: str | None = None) -> dict[str, dict]:
"""获取指定网站的所有 Cookie"""
all_data = self.redis.hgetall(self._key(website))
result = {u: json.loads(v) for u, v in all_data.items()}
if status:
return {u: d for u, d in result.items() if d.get("status") == status}
return result6.4 定时检测与自动刷新
Cookie 的有效期是有限的(通常数小时到数周不等),必须定时检测并自动刷新。检测器通过请求一个"验证 URL"(如个人设置页面)来判断 Cookie 是否仍然有效:
# Python 3.10+
import requests
from abc import ABC, abstractmethod
class BaseChecker(ABC):
"""Cookie 检测器基类"""
def __init__(self, website: str):
self.website = website
@abstractmethod
def check(self, cookies: dict) -> bool:
"""检测 Cookie 是否有效,返回 True/False"""
...
class GithubChecker(BaseChecker):
"""GitHub Cookie 检测器 —— 请求个人设置页验证"""
def __init__(self):
super().__init__("github")
self.check_url = "https://github.com/settings/profile"
def check(self, cookies: dict) -> bool:
try:
resp = requests.get(
self.check_url,
cookies=cookies,
allow_redirects=False, # 不跟随重定向,通过状态码判断
headers={"User-Agent": "Mozilla/5.0 ..."},
timeout=10,
)
# 200 = 有效,302 = 被重定向到登录页 = 失效
return resp.status_code == 200
except requests.RequestException:
return False
# 检测器注册表(可扩展更多网站)
CHECKER_MAP: dict[str, type[BaseChecker]] = {
"github": GithubChecker,
}调度器将 Cookie 获取和检测串联为定时任务,形成闭环:获取 -> 存储 -> 检测 -> 失效 -> 重新获取。
七、常见陷阱与解决方案
以下表格汇总了 Cookie 管理与模拟登录开发中最常见的陷阱:
| 陷阱 | 典型现象 | 根因分析 | 解决方案 |
|---|---|---|---|
| Cookie 过期 | 运行一段时间后突然返回 401/302 | Cookie 有效期结束 | 实现定时检测 + 自动刷新机制 |
| CSRF Token 缺失 | 登录接口返回 403 Forbidden | 未携带 CSRF 防护令牌 | 先 GET 登录页面,从 HTML 中提取 Token |
| 多步登录流程 | 登录后仍无法访问目标页面 | 有重定向链或中间验证步骤 | 跟踪完整请求链,设置 allow_redirects=True |
| 验证码失效 | 识别出的验证码提交后提示错误 | 验证码与 Session 绑定,每次刷新页面后旧验证码失效 | 确保验证码图片和登录请求使用同一个 Session |
| 请求头异常 | 返回 403/404,但浏览器可以 | User-Agent、Referer 等被识别为爬虫 | 完整复制浏览器请求头,特别注意 Referer 和 Origin |
| IP 频率限制 | 请求返回 429 Too Many Requests | 单 IP 短时间内请求过多 | 使用代理 IP 池 + 随机延时 |
| JS 动态加密 | 抓包参数与实际提交参数不一致 | 密码等字段在提交前被 JS 加密 | 分析加密逻辑(逆向 JS)或使用 Selenium 绕过 |
| SameSite 限制 | 跨站请求不携带 Cookie | SameSite=Strict 禁止跨站发送 | 使用同站请求或设置 SameSite=None(需配合 Secure) |
八、最佳实践
8.1 代码规范
| 实践 | 推荐做法 | 不推荐做法 | 原因 |
|---|---|---|---|
| Cookie 管理 | 使用 requests.Session | 手动拼接 Cookie 字符串 | 自动管理,减少遗漏和错误 |
| 登录验证 | 检查关键元素 + Cookie + URL | 仅检查 HTTP 状态码 | 某些网站登录失败也返回 200 |
| CSRF Token | 每次登录前动态获取 | 硬编码 Token 值 | Token 会动态变化 |
| Cookie 存储 | 加密存储到文件或 Redis | 明文存储 | 防止凭证泄露 |
| 异常处理 | 捕获异常并实现重试逻辑 | 直接崩溃 | 提高程序健壮性 |
| 请求间隔 | 随机延时 1-3 秒 | 无间隔连续请求 | 模拟人类行为,降低封禁风险 |
| 日志记录 | 记录关键步骤和异常 | 无日志 | 便于排查问题 |
8.2 安全提醒
- 绝对不要将登录凭证(用户名/密码/Cookie/Token)分享给他人或提交到公开仓库
- 在
.gitignore中添加cookies.json、accounts.json、*.pem等敏感文件 - 遵守目标网站的**服务条款(ToS)**和 robots.txt 协议
- 控制请求频率,避免对目标网站造成不必要的负担
- 仅爬取你有权访问的数据,尊重数据所有权和隐私
- 生产环境使用环境变量或密钥管理服务(如 Vault)存储敏感配置
九、术语表
| 术语 | 英文 | 解释 |
|---|---|---|
| Cookie | HTTP Cookie | 服务器发送到客户端的小型数据片段,用于状态管理 |
| Session | Session | 服务器端存储的用户会话信息 |
| Session ID | Session Identifier | 唯一标识用户会话的字符串 |
| CSRF | Cross-Site Request Forgery | 跨站请求伪造,一种 Web 攻击方式 |
| CSRF Token | CSRF Token | 防御 CSRF 攻击的随机令牌,嵌入在表单中 |
| JWT | JSON Web Token | 一种无状态的身份认证令牌格式,由 Header、Payload、Signature 三部分组成 |
| OAuth 2.0 | Open Authorization 2.0 | 开放授权协议,用于第三方应用授权 |
| HttpOnly | HttpOnly | Cookie 属性,禁止 JavaScript 访问,但 HTTP 请求头仍可携带 |
| Secure | Secure | Cookie 属性,仅通过 HTTPS 传输 |
| SameSite | SameSite | Cookie 属性,控制跨站请求时是否发送 |
| Cookie 池 | Cookie Pool | 预先获取并集中管理的多个 Cookie 集合,通过 API 分发 |
| 调度器 | Scheduler | 定时执行 Cookie 获取和检测任务的协调模块 |
| 登录器 | Loginer | 负责模拟登录并获取 Cookie 的模块 |
| 检测器 | Checker | 负责验证 Cookie 有效性的模块 |
| 持久 Cookie | Persistent Cookie | 设置了 Max-Age 或 Expires 的 Cookie,关闭浏览器后仍存在 |
| 会话 Cookie | Session Cookie | 未设置过期时间的 Cookie,关闭浏览器后消失 |
| PAT | Personal Access Token | GitHub 等平台的个人访问令牌,用于 API 认证 |
| 2FA | Two-Factor Authentication | 双因素认证,额外的安全验证层 |
十、延伸阅读
站内链接
- Requests 模块完全指南 -- requests 库完整教程,含 Session 详解
- Selenium 自动化深度指南 -- 浏览器自动化方案,处理复杂验证码
- HTTP 基本原理 -- HTTP 协议深入理解
外部链接
- RFC 6265 - HTTP State Management Mechanism -- Cookie 官方技术规范
- RFC 7519 - JSON Web Token -- JWT 规范
- JWT.io -- JWT 在线调试工具
- MDN - HTTP Cookies -- Cookie 权威文档
- requests 官方文档 - Session -- Session 详细说明
- Redis 官方文档 -- Redis 使用指南
- GitHub REST API 文档 -- GitHub API 官方文档
十一、小结
本章从原理到工程实践,系统讲解了 Cookie 管理与模拟登录的完整知识体系:
- 理解原理:Cookie 在客户端存储身份标识,Session 在服务器端维护会话状态,两者配合让无状态的 HTTP 承载有状态的登录流程
- 掌握工具:
requests.Session自动管理 Cookie 的保存、携带和持久化,是模拟登录的核心工具 - 选择策略:表单登录(通用)、Cookie 注入(临时)、Token 认证(API 服务)三种策略各有适用场景
- 应对验证码:根据验证码类型选择 OCR、打码平台或浏览器自动化方案
- 构建基础设施:Cookie 池通过"获取-存储-检测-分发-淘汰"的闭环,实现多账号 Cookie 的自动化管理,是规模化爬虫的基石
核心思想:分析思路比代码实现更重要。只要正确理解了目标网站的认证机制,获取并维护好登录状态,模拟登录就能稳定运行。
版本差异(爬虫技术栈 → 当前版本)
| 库 | 本文编写时 | 当前稳定版 |
|---|---|---|
requests | 2.28/2.31 | 2.32.x |
Scrapy | 1.x/2.0 | 2.11.x(API 稳定) |
httpx | 0.24 | 0.28.x |
Playwright | 1.3x | 1.6x(Python 版) |
lxml/BeautifulSoup | 旧版 | 保持稳定 |
| Python | 3.8-3.12 | 3.14(推荐) |
本文讲解的爬虫原理(HTTP、解析、反爬、存储)与核心 API 在最新版本中成立;注意 Python 3.9 及以下已 EOL,新项目使用 3.13/3.14。