现代 Web 爬虫技术:Session + Cookie 认证的模拟登录

1. 前言

刚开始学爬虫的你,肯定遇到过这种尴尬:
公开页面随便抓,一点问题没有;可一旦要访问自己的订单、收藏夹、会员区,要么直接给你 401 Unauthorized,要么返回一大片“请先登录”的跳转提示。

这时很多人会慌了。其实,Session + Cookie 认证作为最古老、也最普及的登录方案之一,反而是新手最容易上手、最稳妥的突破口。

本文会带着你,用一个真实的示例网站,从原理到代码,手把手完成一次完整的模拟登录。文末还会给出生产项目中常用的最佳实践和避坑清单,让你以后遇到类似场景都心中有数。


2. 技术准备

先搭好运行环境,依赖都不复杂。

2.1 环境要求

  • Python 3.8+(建议 3.10,requests 兼容性更顺手)
  • 一个现代浏览器(Chrome、Edge 都行,用于开发者工具调试)
  • 你不需要手动下载 Chromedriver,后面 webdriver-manager 会自动处理

2.2 安装依赖

pip install requests selenium webdriver-manager beautifulsoup4

beautifulsoup4 只是为了后面直观地验证登录结果,如果不看页面内容也可以不装。


3. 分析目标网站

这次我们用的练手站是 崔庆才老师的模拟登录演示站点

https://login2.scrape.center/

它没有验证码,也没有复杂的 JS 加密,但完全复刻了真实 Session + Cookie 登录的全部流程,特别适合入门。

3.1 站点行为速览

  • 传统 MVC 架构,页面由后端直接渲染
  • 纯 Session + Cookie 认证,不涉及 OAuth/JWT 等现代方案
  • 登录成功后会 302 重定向到首页 https://login2.scrape.center/,展示电影列表

3.2 拆解登录流程(用 DevTools 看门道)

做爬虫最忌讳的是一上来就写代码。先打开 Chrome 的开发者工具(F12 → Network),我们一步步把整个登录过程看清楚:

  1. 勾选 Preserve log(重要!否则重定向日志会丢失)
  2. 手动输入账号密码 admin / admin,点登录
  3. 把 Network 面板中的请求类型过滤为 Doc,只看文档请求

你会看到三段关键请求,刚好对应一次完整的登录认证链:

步骤方法URL作用
1POST/login提交用户名密码,后端验证身份
2302/验证通过后,后端强制跳转到首页
3GET/重定向后请求首页,必须带上后端给的 Session Cookie 才能正常渲染

点开第 1 个 POST 请求的 Response Headers,你会看到一行非常重要的响应头:

Set-Cookie: sessionid=abc123xyz; Path=/; HttpOnly

这就是后端发下来的“门禁卡”——sessionid。之后浏览器每次请求同一个域名,都会自动把它挂在 Cookie 里带过去。

核心要点:Session + Cookie 模式下,后端只会在登录成功时通过 Set-Cookie 下发一次标识;后续通信全靠浏览器乖乖带上这个 Cookie。爬虫要做的就是模仿浏览器,把这个“认证凭据”保存好,并在后续请求中原样回传。


4. 三种模拟登录实现方式

从新手最容易踩的坑,到推荐的生产级方案,我们逐一展示。

很多初学者会这么干:先发一个 POST 请求,从响应里抠出 Set-Cookie,再手动塞给后面的 GET 请求。虽然也能跑通,但每一个请求都像新打开的浏览器窗口,Cookie 管理起来既麻烦又容易出错。

import requests
from bs4 import BeautifulSoup

LOGIN_URL = "https://login2.scrape.center/login"
INDEX_URL = "https://login2.scrape.center/"
USERNAME = "admin"
PASSWORD = "admin"

# 1. 发送登录请求,禁止自动重定向(否则拿不到 Set-Cookie 响应)
login_resp = requests.post(
    LOGIN_URL,
    data={"username": USERNAME, "password": PASSWORD},
    allow_redirects=False
)

# 2. 手动提取 Cookie
cookies = login_resp.cookies

# 3. 再用这些 Cookie 去请求首页
index_resp = requests.get(INDEX_URL, cookies=cookies)

# 验证登录是否成功
soup = BeautifulSoup(index_resp.text, "html.parser")
print(soup.find("h2", class_="mb-3"))  # 正常应输出:<h2>欢迎回来,admin</h2>

这种方式最大的问题不是“能不能跑”,而是“维护成本高”——Cookie 到期了要手动更新,每次请求都要显式传递,一旦请求链路变长,代码会乱成一团。

4.2 标准推荐版:使用 requests.Session(✅ 必学)

requests 库里自带的 Session 对象,就像一个持久化的浏览器会话。它会自动帮你跟踪所有 Cookie、请求头、连接池等信息。你只需登录一次,后续的所有请求都能直接用这个“会话”一路畅通。

import requests
from bs4 import BeautifulSoup

LOGIN_URL = "https://login2.scrape.center/login"
INDEX_URL = "https://login2.scrape.center/"
USERNAME = "admin"
PASSWORD = "admin"

# 1. 创建一个持久会话
session = requests.Session()

# 2. 为整个会话设置一个通用的 User-Agent(避免底层默认 UA)
session.headers.update({
    "User-Agent": (
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
        "AppleWebKit/537.36 (KHTML, like Gecko) "
        "Chrome/128.0.0.0 Safari/537.36"
    )
})

# 3. 用 Session 发送 POST 请求(不需要禁止重定向,Session 会自动处理)
login_resp = session.post(
    LOGIN_URL,
    data={"username": USERNAME, "password": PASSWORD}
)
print("登录后首页状态码:", login_resp.status_code)  # 正常为 200

# 4. 继续使用同一个 Session 请求首页(Cookie 自动携带)
index_resp = session.get(INDEX_URL)
soup = BeautifulSoup(index_resp.text, "html.parser")
print(soup.find("h2", class_="mb-3"))

为什么推荐这种方式?

  • 代码简洁,不需要手动管理 Cookie
  • 请求间的状态自动维护,不容易遗漏
  • 可以轻松添加自定义请求头、代理等配置,对整个会话生效

绝大多数中小网站、内部管理后台的登录,用 requests.Session 就能搞定。

有些网站登录时会遇到图形验证码、滑块验证、指纹检测或复杂的 JS 加密。这种情况下,直接用 requests 伪造登录请求非常困难,甚至不可能。

这时你可以采用一种“混合引擎”的思路:

  1. 先用 Selenium 打开真实浏览器,模拟用户操作 完成登录
  2. 登录后直接把浏览器里的 Cookie 导出来
  3. 把 Cookie 喂给 requests.Session,后续爬取全交给轻量级的 HTTP 请求

这样既能绕过复杂的人机验证,又能享受 requests 的高速抓取。

import time
import requests
from bs4 import BeautifulSoup
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from webdriver_manager.chrome import ChromeDriverManager

LOGIN_URL = "https://login2.scrape.center/login"
INDEX_URL = "https://login2.scrape.center/"
USERNAME = "admin"
PASSWORD = "admin"

# ========== 第一步:Selenium 登录并导出 Cookie ==========
driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()))
driver.maximize_window()

try:
    driver.get(LOGIN_URL)
    time.sleep(1)  # 等待页面完全加载

    # 模拟输入与点击
    driver.find_element(By.CSS_SELECTOR, 'input[name="username"]').send_keys(USERNAME)
    driver.find_element(By.CSS_SELECTOR, 'input[name="password"]').send_keys(PASSWORD)
    driver.find_element(By.CSS_SELECTOR, 'button[type="submit"]').click()
    time.sleep(2)  # 等待跳转完成

    if driver.current_url == INDEX_URL:
        print("Selenium 模拟登录成功!")
        selenium_cookies = driver.get_cookies()
    else:
        print("Selenium 模拟登录失败!")
        selenium_cookies = []
finally:
    driver.quit()

# ========== 第二步:将 Cookie 倒入 Requests Session ==========
if selenium_cookies:
    session = requests.Session()
    session.headers.update({
        "User-Agent": (
            "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
            "AppleWebKit/537.36 (KHTML, like Gecko) "
            "Chrome/128.0.0.0 Safari/537.36"
        )
    })

    # 逐个注入 Cookie
    for cookie in selenium_cookies:
        session.cookies.set(
            name=cookie["name"],
            value=cookie["value"],
            domain=cookie.get("domain", ""),
            path=cookie.get("path", "/")
        )

    # 验证 + 抓取首页前 3 个电影标题
    index_resp = session.get(INDEX_URL)
    soup = BeautifulSoup(index_resp.text, "html.parser")
    print("首页前 3 个电影:")
    for i, movie in enumerate(soup.find_all("h5", class_="card-title"), 1):
        print(f"{i}. {movie.text.strip()}")

适用场景:登录阶段需要处理复杂的人机验证,但登录后页面大多是静态结构或简单的异步加载。
性能优势:Selenium 只负责最麻烦的登录环节,大量抓取仍然用 requests,速度远快于全程操控浏览器。


5. 避坑指南 & 生产级最佳实践

即使示例网站没有任何反爬,真实的网站也不会这么“温柔”。以下几条经验能让你少走很多弯路。

  1. 持久化存储
    把通过登录拿到的 Cookie 序列化成 JSON 文件,或存入数据库。下次启动爬虫时,先尝试加载这些 Cookie,若未过期就直接使用,避免频繁登录。
  2. Cookie 池
    如果采集量较大,可以提前准备多个账号,每个账号一套有效 Cookie,抓取时随机轮换。既降低了单账号被封的风险,又提高了整体的稳定性。
  3. 主动检测有效性
    很多站点的 Session 有固定有效期(例如 24 小时)。在每次批量抓取前,可以先请求一个只有登录后才能访问的接口;如果返回 401,就自动触发重登录流程。

5.2 反爬对抗的必备细节

  • User‑Agent 一定要换
    python-requests/x.x.x 这样的默认 UA 几乎是“自报家门”,必须改成真实浏览器的值。
  • Referer 别忘带
    如果业务逻辑依赖请求来源,比如从列表页跳转到详情页,记得把请求头的 Referer 设置成列表页的 URL。
  • 随机延迟
    在连续的请求之间加入 time.sleep(random.uniform(1, 3)),模拟真人浏览节奏。突兀的“无间断”访问很容易触发频率限制。
  • 控制抓取速度和总量
    哪怕加了延迟,也尽量避免短时间内请求几十万条数据。既减轻服务器压力,也降低自己被封 IP 的风险。

6. 总结

Session + Cookie 认证虽然技术“古老”,但胜在稳定、调试方便、适用面广,至今仍是大量网站的首选登录方式。

对于新手而言,学习顺序建议:

  1. 先掌握 requests.Session,它能解决身边 80% 的登录场景;
  2. 当遇到验证码、复杂 JS 时,再引入 Selenium 取 Cookie + Requests 爬取 的组合拳。

只要把请求链路的“认证凭证”这条线理清,大部分“需要登录”的网站都难不倒你。


扩展阅读(敬请期待):

  • OAuth 2.0 认证的模拟登录
  • JWT 认证的爬虫处理
  • WebAssembly 网站的爬取策略