深入讲解服务器如何检测爬虫、如何通过 Session 维持登录状态、以及三种携带 Cookie 访问受保护页面的实战方法。
目录
- 服务器如何侦测爬虫
- 登录态问题的本质:Cookie 与 Session
- 方案一:用 requests.Session 模拟完整登录流程
- 方案二:直接携带已知 Cookie 发起请求
- 方案三:从登录响应中提取 Cookie 再复用
- 三种方案横向对比
①服务器如何侦测爬虫
网站的反爬策略通常是多维度叠加的,单一手段很难奏效。常见的侦测维度包括:
频率维度
IP 访问频率
短时间内同一 IP 发出大量请求,触发限速或封禁
身份维度
请求头检查
User-Agent、Referer、Accept-Language 等字段缺失或异常
状态维度
Cookie / Session
无有效登录态直接访问需鉴权页面
网络维度
IP 来源分析
数据中心 IP、同一 ASN 下大量请求,与真实用户分布不符
应对策略是对应的:随机 User-Agent 对抗身份检测,代理池对抗 IP 频率限制,而本文聚焦的 Session/Cookie 管理,则是解决登录态问题的核心手段。
②登录态问题的本质
HTTP 是无状态协议,服务器本身不记得你是谁。"登录后才能访问"的实现方式是:用户输入用户名密码 → 服务器验证后下发一个 Cookie(或通过 Session 机制在服务端记录状态)→ 后续每次请求携带这个 Cookie,服务器就认为你已登录。
POST 用户名+密码
→
服务器验证
→
下发 Cookie / Session ID
→
后续请求携带 Cookie
→
访问受保护页面
爬虫要访问需要登录的页面,就必须复现这一流程------要么先 POST 登录再带着拿到的 Cookie 继续请求,要么直接把从浏览器复制来的 Cookie 塞进请求头里。
③方案一:requests.Session 模拟完整登录
requests.Session 是 requests 库提供的会话对象。它最重要的特性是:自动保存并在后续请求中携带服务器下发的 Cookie,完全模拟浏览器的行为。
import requests
def main():
url = "http://example.com/login"
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36"
}
data = {"uname": "admin", "passwd": "admin"}
# 1. 实例化 Session,它会自动管理 Cookie
session = requests.Session()
# 2. POST 登录,Session 内部自动保存响应中的 Cookie
session.post(url, headers=headers, data=data)
# 3. 后续用同一 Session 直接 GET 任意需登录页面
# Cookie 会被自动附加,无需手动处理
res = session.get(url, headers=headers)
print(res.content.decode("utf-8"))
if __name__ == "__main__":
main()
如何知道 POST 需要哪些字段?打开浏览器开发者工具 → Network 面板 → 找到登录请求 → 查看 Payload(表单数据)。字段名(如 uname、passwd)必须与网站表单完全一致。
④方案二:直接携带已知 Cookie
如果你已经通过浏览器登录,可以从开发者工具中复制 Cookie,直接塞进请求里,省去模拟登录的步骤。有两种写法:
写法 A:通过 cookies 参数传入字典
import requests
url = "http://example.com/protected"
headers = {"User-Agent": "Mozilla/5.0 ..."}
# 将 Cookie 整理成字典,键值对就是 name=value
cookie_dict = {"uname": "admin", "session_id": "abc123"}
resp = requests.get(url, headers=headers, cookies=cookie_dict)
print(resp.content.decode("utf-8"))
写法 B:直接在 headers 中拼入 Cookie 字符串
headers = {
"User-Agent": "Mozilla/5.0 ...",
"Cookie": "uname=admin; session_id=abc123" # 从浏览器直接复制
}
resp = requests.get(url, headers=headers)
print(resp.content.decode("utf-8"))
Cookie 有时效性,从浏览器复制的 Cookie 过期后会失效,届时需要重新登录并更新。对于需要长期运行的爬虫,推荐方案一(Session 自动登录),无需手动维护。
⑤方案三:从响应中提取 Cookie 再复用
有时需要在程序中动态获取 Cookie 并传递给其他函数或保存到文件中。requests 提供了便捷的工具方法来解析响应中的 Cookie:
import requests
url = "http://example.com/login"
headers = {"User-Agent": "Mozilla/5.0 ..."}
data = {"uname": "admin", "passwd": "admin"}
resp = requests.post(url, headers=headers, data=data)
# resp.cookies 是 RequestsCookieJar 对象,类似字典但功能更丰富
print(resp.cookies)
# 转换为普通字典,方便序列化或传参
cookies = requests.utils.dict_from_cookiejar(resp.cookies)
print(cookies) # 输出: {'uname': 'admin', 'session_id': 'xyz789', ...}
# 复用:将提取的 cookies 传给下一个请求
res = requests.get(url, headers=headers, cookies=cookies)
print(res.content.decode("utf-8"))
反向操作同样可用:requests.utils.cookiejar_from_dict(cookie_dict) 可将普通字典转换回 CookieJar 对象,适合从本地文件加载已保存的 Cookie。
⑥三种方案横向对比
方案一 推荐
Session 自动管理
程序自动登录、自动维持 Cookie,适合长期运行的爬虫,无需人工干预。
方案二
手动携带 Cookie
从浏览器复制 Cookie 直接使用,快速验证,适合一次性脚本,Cookie 过期需手动更新。
方案三
动态提取并复用
适合需要将 Cookie 在多模块间传递、持久化存储(如写入 JSON 文件)的场景。
✓实践建议
在实际项目中,三种方案往往组合使用:用 Session 完成自动登录(方案一),必要时将 Cookie 提取出来持久化(方案三),对于登录特别复杂(如二次验证、滑块验证码)的网站,则退而求其次,手动从浏览器复制 Cookie(方案二)。
无论哪种方式,都要记住:Cookie 是身份凭证,请仅在有授权的目标网站上使用爬虫,并遵守网站的 robots.txt 协议。后续文章将介绍如何用 BeautifulSoup 解析登录后拿到的 HTML 内容,提取结构化数据。