Requests库爬虫进阶:手把手教你处理登录态与会话保持(Session & Cookies实战)

当你需要爬取用户中心、订单列表等需要登录才能访问的页面时,简单的请求已经无法满足需求。这时,会话保持和登录态管理就成了爬虫开发中的关键技能。本文将深入探讨如何使用Requests库的Session对象来自动管理Cookies,实现跨请求的会话保持。

1. 为什么需要会话保持

想象一下这样的场景:你手动登录一个网站后,可以自由浏览个人主页、查看订单、修改资料。但当你用爬虫模拟登录后,却发现后续请求总是返回未登录状态。这就是典型的会话保持问题。

传统做法是手动管理Cookies:

import requests

# 第一次请求获取Cookies
login_response = requests.post(login_url, data=credentials)
cookies = login_response.cookies

# 后续请求手动传递Cookies
profile_response = requests.get(profile_url, cookies=cookies)

这种方法虽然可行,但存在几个明显问题:

  • 需要手动提取和传递Cookies
  • 无法自动处理Cookies更新
  • 代码冗余且容易出错

Session对象正是为解决这些问题而设计的。它会在同一个会话中自动处理Cookies的存储和传递,就像浏览器一样工作。

2. Session对象的核心优势

使用Session对象与直接传递Cookies字典的主要区别:

特性 Session对象 手动传递Cookies
Cookies自动管理 ✅ 自动存储和发送 ❌ 需要手动处理
连接池复用 ✅ 提升性能 ❌ 每次新建连接
持久性参数 ✅ 可设置默认headers ❌ 每次需单独设置
Cookies更新 ✅ 自动处理 ❌ 需手动更新

一个基础Session使用示例:

with requests.Session() as session:
    # 设置公共headers
    session.headers.update({
        'User-Agent': 'Mozilla/5.0',
        'Referer': 'https://example.com'
    })
    
    # 登录请求(自动保存Cookies)
    session.post(login_url, data=credentials)
    
    # 后续请求自动携带Cookies
    profile = session.get(profile_url).json()

3. 实战:从浏览器提取Cookies

有时我们需要从已登录的浏览器会话中提取Cookies,用于爬虫初始化。以下是具体步骤:

  1. 在Chrome中打开开发者工具(F12)
  2. 访问目标网站并登录
  3. 切换到"Application"标签
  4. 在左侧选择"Cookies"下的网站域名
  5. 右键点击Cookies选择"Copy as Node.js fetch"

获取到的Cookies可以这样转换为Python字典:

def parse_browser_cookies(cookie_str):
    cookies = {}
    for item in cookie_str.split(';'):
        key, value = item.strip().split('=', 1)
        cookies[key] = value
    return cookies

# 示例使用
browser_cookies = "name=value; path=/; domain=.example.com"
session.cookies.update(parse_browser_cookies(browser_cookies))

注意:浏览器Cookies通常有过期时间,直接使用可能面临会话过期问题。建议结合登录流程使用。

4. 高级会话管理技巧

4.1 Cookies持久化存储

为了避免每次重启爬虫都需要重新登录,我们可以将Cookies持久化到文件:

import pickle
import os

def save_cookies(session, filename):
    with open(filename, 'wb') as f:
        pickle.dump(session.cookies, f)

def load_cookies(session, filename):
    if os.path.exists(filename):
        with open(filename, 'rb') as f:
            session.cookies.update(pickle.load(f))

# 使用示例
session = requests.Session()
load_cookies(session, 'cookies.pkl')

try:
    session.post(login_url, data=credentials)
    save_cookies(session, 'cookies.pkl')
except Exception as e:
    print(f"登录失败: {e}")

4.2 处理动态Cookies

某些网站会在每次请求时更新Cookies,这时需要实时获取最新Cookies:

response = session.get(api_url)
updated_cookies = response.cookies

# 获取特定Cookie值
session_id = session.cookies.get('sessionid')

# 检查登录状态
if 'auth_token' not in session.cookies:
    print("会话已过期,需要重新登录")

4.3 多账号会话隔离

当需要管理多个账号时,可以为每个账号创建独立的Session:

class AccountSession:
    def __init__(self, username, password):
        self.session = requests.Session()
        self.credentials = {'username': username, 'password': password}
        
    def login(self):
        self.session.post(login_url, data=self.credentials)
        
    def get_profile(self):
        return self.session.get(profile_url).json()

# 使用示例
account1 = AccountSession('user1', 'pass1')
account2 = AccountSession('user2', 'pass2')

5. 常见问题与解决方案

5.1 会话过期处理

实现自动检测会话状态并在过期时重新登录:

def safe_request(session, url, max_retry=3):
    for _ in range(max_retry):
        try:
            response = session.get(url)
            if 'login' in response.url:  # 被重定向到登录页
                session.post(login_url, data=credentials)
                continue
            return response
        except requests.RequestException as e:
            print(f"请求失败: {e}")
    return None

5.2 验证码处理

当登录需要验证码时,可以这样处理:

  1. 首次请求获取验证码图片
  2. 人工识别或使用OCR识别
  3. 提交验证码
# 获取验证码
captcha_response = session.get(captcha_url)
with open('captcha.jpg', 'wb') as f:
    f.write(captcha_response.content)

# 人工输入验证码(或调用OCR服务)
captcha_code = input("请输入验证码: ")

# 提交登录请求
login_data = {
    **credentials,
    'captcha': captcha_code
}
session.post(login_url, data=login_data)

5.3 请求频率控制

避免因请求过快被封禁:

import time
from random import uniform

def throttled_request(session, url, delay=(1, 3)):
    time.sleep(uniform(*delay))  # 随机延迟
    return session.get(url)

在实际项目中,我发现最稳定的做法是模拟真实用户行为:在关键操作间加入随机延迟,避免规律性请求。同时,合理设置User-Agent和Referer等头部信息,能让爬虫行为更接近正常浏览器访问。

Logo

码道开发者社区,聚焦华为云码道 CodeArts 代码智能体,沉淀 Agent、Skill、鸿蒙开发实战内容,供开发者查阅资料、交流技术、分享工程实践

更多推荐