云计算百科
云计算领域专业知识百科平台

Day 07 · Cookie 与 Session:处理登录状态

「AI Python 系列」第 03 栏 · Python 爬虫实战 全栏 15 篇 · 零成本跟完 🍃 作者:梅雅达编程笔记 首发:CSDN


摘要: 有些数据必须登录才能看到,爬虫怎么绕过这一步?先搞清楚Cookie、Session、Token到底是什么——它们就是网站的"身份证系统"。本篇教你两种方法:一是用requests.Session模拟登录后自动携带Cookie,二是从浏览器直接复制Cookie省掉登录步骤。案例演示登录一个公开测试站点,抓取登录后的个人主页数据。合规提醒:只爬自己有权限看的数据。


前面学的都是抓公开数据。但有些网站的内容,不登录根本看不到。

比如你的个人订单、收藏列表、私信——这些都需要"证明你是谁"才能访问。

爬虫怎么解决这个问题?先搞清楚网站的登录机制。


一、Cookie、Session、Token 是什么

这三个词经常混着用,但其实说的是不同的东西。

Cookie

Cookie 是服务器存在你浏览器里的一小段数据。

你登录成功后,服务器会在响应头里加上:

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

浏览器收到后,会把这个 Cookie 存下来。之后你每次请求这个网站,浏览器都会自动带上:

Cookie: session_id=abc123xyz

服务器看到你的 Cookie,就知道你是谁。

Session

Session 是服务器端的概念。

你登录成功后,服务器在内存(或数据库)里存一个 Session 对象,里面放着你的用户信息。然后给你返回一个 Session ID(通常就是 Cookie 里的那个 session_id)。

之后你每次请求带上这个 ID,服务器就能查到对应的 Session,知道你是谁。

Token(JWT)

Token 是另一种方案,现在用得越来越多。

登录成功后,服务器返回一个加密的字符串(Token),里面包含了你的用户信息。浏览器把它存在 localStorage 或 Cookie 里。

之后每次请求,在 Header 里带上:

Authorization: Bearer eyJhbGciOiJIUzI1NiIs…

服务器收到 Token,解密验证,就知道你是谁。不需要在服务器端存 Session。

三者的关系

方式存在哪谁维护状态特点
Cookie 浏览器 服务器(Session) 传统方案,自动携带
Session 服务器 服务器 需要服务器存储
Token 浏览器 客户端携带 无状态,服务器不用存

对爬虫来说,不管网站用哪种方案,核心都是:登录后拿到凭证,后续请求带上凭证。


二、方法一:用 requests.Session 模拟登录

requests.Session 会自动帮你管理 Cookie。你登录一次,后续的请求会自动带上登录状态。

流程

  • 用 Session 发送登录请求(POST)
  • 服务器返回 Cookie,Session 自动保存
  • 后续用同一个 Session 发请求,自动带上 Cookie
  • 代码

    import requests

    # 创建 Session
    session = requests.Session()

    # 第一步:登录
    login_url = "https://gitee.com/api/v5/login"
    login_data = {
    "username": "your_username",
    "password": "your_password"
    }

    response = session.post(login_url, data=login_data)

    if response.status_code == 200:
    print("登录成功")
    print("当前 Cookie:", session.cookies.get_dict())
    else:
    print(f"登录失败:{response.status_code}")
    exit()

    # 第二步:用登录后的 Session 访问需要权限的页面
    profile_url = "https://gitee.com/api/v5/user"
    response = session.get(profile_url)

    if response.status_code == 200:
    data = response.json()
    print(f"用户名:{data.get('username')}")
    print(f"邮箱:{data.get('email')}")
    print(f"注册时间:{data.get('created_at')}")
    else:
    print(f"获取失败:{response.status_code}")

    关键点

    • requests.Session() 会自动处理 Cookie,登录后不用再手动传
    • 有些网站登录时需要 CSRF Token,要先 GET 登录页拿到 Token,再 POST 登录
    • 登录接口不一定是 POST 到 /login,要看网站实际怎么设计的

    三、方法二:从浏览器复制 Cookie

    如果登录流程很复杂(要验证码、要扫码、要二次验证),用代码模拟登录太麻烦。

    更简单的办法:在浏览器里手动登录,然后把 Cookie 复制出来,直接用。

    步骤

  • 在浏览器里正常登录网站
  • 打开 F12 → Network Tab
  • 随便点一个请求,找到 Request Headers 里的 Cookie 字段
  • 复制整个 Cookie 值
  • 代码

    import requests

    # 从浏览器复制的 Cookie
    cookie_str = "session_id=abc123xyz; user_token=def456uvw; …"

    # 解析成字典
    cookies = {}
    for item in cookie_str.split("; "):
    if "=" in item:
    key, value = item.split("=", 1)
    cookies[key] = value

    # 发请求时带上
    headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
    }

    response = requests.get(
    "https://gitee.com/api/v5/user",
    headers=headers,
    cookies=cookies
    )

    print(response.json())

    更优雅的方式

    用 requests.utils.cookiejar_from_dict 或者直接设置 Headers:

    headers = {
    "User-Agent": "Mozilla/5.0",
    "Cookie": "session_id=abc123xyz; user_token=def456uvw"
    }

    response = requests.get("https://gitee.com/api/v5/user", headers=headers)

    直接把 Cookie 字符串放进 Headers 里,简单粗暴。

    注意事项

    • Cookie 有有效期,过期了要重新复制
    • 不要在公开场合分享你的 Cookie,它能让别人冒充你
    • 如果你的网站用 Token(放在 Authorization Header 里),直接复制 Token 就行

    四、实战:Gitee(码云)API Token 认证

    国内推荐使用 Gitee(码云) 来练习 Token 认证——GitHub 国内访问不稳定,而 Gitee 完全兼容、速度快。

    目标网站:Gitee(码云)—— 国内代码托管平台,类似 GitHub API 文档:https://gitee.com/api/v5


    4.1 如何获取 Gitee 私人令牌(Token)

    Gitee 的 Token 叫做私人令牌,获取方式如下:

    第一步:登录 Gitee

    打开浏览器访问 https://gitee.com,用你的账号登录。

    第二步:进入设置页面

    点击右上角的头像 → 下拉菜单中选择 设置。

    第三步:打开私人令牌设置

    在左侧菜单栏中找到 安全设置 → 点击 私人令牌。

    或者直接访问:https://gitee.com/profile/personal_access_tokens

    第四步:生成新令牌

    • 点击右上角的 生成新令牌 按钮
    • 填写表单:
      • 令牌描述:随便写,用于区分用途,如 爬虫测试
      • 权限范围:勾选 user_info(读取用户基本信息即可)
    • 点击 提交(可能需要输入密码验证)

    第五步:复制并保存 Token

    • 生成后会显示一串字符,格式类似:

      xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

    • 立即复制保存! 这个页面关闭之后就再也看不到了,只能重新生成。

    第六步:替换代码中的 Token

    在代码中找到这一行:

    token = "your_gitee_personal_access_token_here"

    替换为你刚复制的真实 Token:

    token = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"


    ⚠️ 安全提醒

    注意事项说明
    不要上传到 Git Token 相当于密码,写了 Token 的代码千万不要 git commit
    不要分享给他人 别人拿到你的 Token 就能冒充你操作 Gitee
    泄露及时删除 如果不小心泄露了,在「私人令牌」页面点「删除」即可失效
    设置合适的权限 只勾选你需要的权限,不要全选

    4.2 完整代码:两步走演示 Token 认证

    整个过程分两步,帮助理解 Token 的作用:

    第一步:不带 Token 访问(被拒绝)

    先不带任何 Token 请求用户信息接口,看看会发生什么:

    import requests

    headers_base = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"
    }

    response = requests.get(
    "https://gitee.com/api/v5/user",
    headers=headers_base,
    timeout=10
    )

    data = response.json()
    print(f"HTTP 状态码:{response.status_code}")
    print(f"响应内容:{response.text[:100]}")

    # Gitee 的未授权特征:返回 JSON 中 code 字段为 40001
    if data.get("code") == 40001:
    print("符合预期:未携带 Token,服务器拒绝访问")
    print("说明:Gitee 用业务码 40001 表示「登录失效,无权访问该资源」")

    预期输出:

    HTTP 状态码:200
    响应内容:{"message":"登录失效,无权访问该资源","code":40001}
    符合预期:未携带 Token,服务器拒绝访问
    说明:Gitee 用业务码 40001 表示「登录失效,无权访问该资源」

    注意:Gitee 的 HTTP 状态码是 200,错误信息放在 JSON 的 code 字段里,这是很多国内 API 的做法。

    第二步:携带 Token 访问(认证成功)

    现在带上我们刚才获取的 Token,再请求同一个接口:

    import requests

    # ========== 填写你的 Token ==========
    token = "your_gitee_personal_access_token_here"
    # ==================================

    headers_base = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"
    }

    response = requests.get(
    "https://gitee.com/api/v5/user",
    params={"access_token": token}, # Gitee 通过 access_token 参数传 Token
    headers=headers_base,
    timeout=10
    )

    data = response.json()
    print(f"HTTP 状态码:{response.status_code}")

    if response.status_code == 200 and "login" in data:
    print("认证成功!")
    print(f"用户名:{data.get('login', 'N/A')}")
    print(f"昵称:{data.get('name', 'N/A')}")
    print(f"邮箱:{data.get('email', 'N/A')}")
    print(f"仓库数:{data.get('public_repo_count', 'N/A')}")
    elif data.get("code") == 40001:
    print("Token 无效或为占位符(返回 40001 未授权)")
    print("请前往 https://gitee.com/profile/personal_access_tokens 生成真实 Token")
    else:
    print(f"响应内容:{response.text[:200]}")

    预期输出(认证成功时):

    HTTP 状态码:200
    认证成功!
    用户名:meiyada
    昵称:梅雅达编程笔记
    邮箱:meiyada@gitee.com
    仓库数:15

    预期输出(Token 为占位符时):

    HTTP 状态码:200
    Token 无效或为占位符(返回 40001 未授权)
    请前往 https://gitee.com/profile/personal_access_tokens 生成真实 Token


    4.3 核心知识点总结

    1. 不带 Token → 服务器返回业务错误码 40001,拒绝访问
    2. 带有效 Token → 服务器返回用户数据(包含 login 等字段)
    3. Gitee 将 Token 放在 URL 参数 access_token 中传递
    4. 注意:不同 API 的认证方式和错误码格式可能不同

    4.4 Gitee 传递 Token 的两种方式

    Gitee 支持两种方式传递 Token,任选其一即可:

    方式 A:URL 参数(推荐,简单)

    response = requests.get(
    "https://gitee.com/api/v5/user",
    params={"access_token": token}
    )

    方式 B:请求头 Authorization(更标准)

    headers = {
    "Authorization": f"Bearer {token}"
    }
    response = requests.get(
    "https://gitee.com/api/v5/user",
    headers=headers
    )

    两种方式效果完全相同,看个人习惯。大多数国外 API(如 GitHub)只支持方式 B。


    五、处理 Token 类型的认证

    现在很多网站用 JWT Token。登录成功后返回一个 Token,后续请求要在 Header 里带上。

    通用模式

    import requests

    # 登录拿 Token
    login_response = requests.post("https://gitee.com/api/v5/login", json={
    "username": "your_username",
    "password": "your_password"
    })

    token = login_response.json().get("access_token")

    # 后续请求带上 Token
    headers = {
    "Authorization": f"Bearer {token}",
    "Content-Type": "application/json"
    }

    response = requests.get("https://gitee.com/api/v5/user/repos", headers=headers)
    print(response.json())

    Token 过期怎么办

    Token 一般有有效期(比如 2 小时)。过期了服务器会返回 401。

    def request_with_refresh(url, headers, token, refresh_token):
    response = requests.get(url, headers=headers)

    if response.status_code == 401:
    # Token 过期,用 refresh_token 换新的
    refresh_response = requests.post("https://gitee.com/api/v5/oauth/token", json={
    "refresh_token": refresh_token
    })
    new_token = refresh_response.json().get("access_token")
    headers["Authorization"] = f"Bearer {new_token}"

    # 重试
    response = requests.get(url, headers=headers)

    return response


    六、合规提醒

    ⚠️ 重要原则:

  • 只爬自己有权限看的数据:登录你自己的账号,抓你自己的数据,没问题。但不能用爬虫抓别人的隐私数据。

  • 不要分享或泄露 Cookie/Token:这些东西相当于你的登录凭证,别人拿到了就能冒充你。

  • 注意网站的使用条款:有些网站明确禁止自动化访问,即使是登录后的数据。

  • 不要高频请求:登录状态下更要注意频率,别触发风控。


  • 完整代码请评论区留言领取

    📊 本篇成本透明栏

    项目数值
    API 调用次数 少量登录请求
    消耗 Token 0
    成本 ¥0

    练手改造题

    改造 1(基础): 在你常用的某个网站登录,用 F12 找到登录接口的 URL、请求方法和参数。然后尝试用 requests.Session 模拟登录。

    改造 2(进阶): 找一个支持 API Token 的网站(比如 GitHub、Notion、Trello),生成一个 Token,写代码抓取你的个人数据。


    下期预告

    Day 08 · 反爬对策:Headers + 限速 + 代理

    网站怎么判断你是爬虫的?怎么伪装得更像真人?Day 08 讲 User-Agent 伪装、请求限速、免费代理 IP 池的使用,以及验证码识别的几种思路。

    📚 资源与工具

    • requests Session 文档: https://docs.python-requests.org/zh_CN/latest/user/advanced.html#session-objects
    • HTTP Cookie 详解: https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Cookies
    • 本专栏配套代码: CSDN 下载区(每篇更新)
    • 梅雅达编程笔记: 专注 Python + AI 实战教程,提供数据采集与自动化定制服务

    往期回顾

    Day 01 · 爬虫能干啥不能干啥

    Day 02 · 环境搭建与第一个爬虫

    Day 03 · 列表页抓取:批量拿数据

    Day 04 · 详情页 + 翻页:从一条到一百条

    Day 05 · Ajax 请求拦截:抓看不到的数据

    Day 06 · 浏览器自动化:DrissionPage 实战


    专栏推荐

    • 「AI Python 系列」第 03 栏 · Python 爬虫实战(连载中)
    • 「AI Python 系列」第 02 栏 · AI+数据可视化(连载中)
    • 「AI Python 系列」第 01 栏 · AI+自动化办公(连载中)

    资源领取

    • 关注作者获取本栏完整代码和数据集

    原创声明:本文为梅雅达编程笔记原创作品,未经允许不得转载。

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » Day 07 · Cookie 与 Session:处理登录状态
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!