处理Cookie和Session:让Python爬虫保持连贯的"身份"

简介: 处理Cookie和Session:让Python爬虫保持连贯的"身份"
  1. 理解Cookie和Session的基本原理
    在深入代码实现之前,我们需要先理解Cookie和Session的基本概念及其在HTTP协议中的工作原理。
    1.1 什么是Cookie?
    Cookie是服务器发送到用户浏览器并保存在本地的一小段数据,浏览器会存储这些数据并在后续向同一服务器发起的请求中携带它们。Cookie主要用于:
    ● 会话管理:用户登录状态、购物车内容、游戏分数等
    ● 个性化:用户偏好、主题设置
    ● 追踪:记录和分析用户行为
    1.2 什么是Session?
    Session是服务器端的一种机制,用于存储特定用户会话所需的信息。Session通常依赖于Cookie来存储一个唯一标识符(Session ID),通过这个ID服务器可以识别用户并检索对应的会话数据。
    1.3 Cookie与Session的协作流程
  2. 客户端向服务器发送请求
  3. 服务器创建Session并生成唯一Session ID
  4. 服务器通过Set-Cookie头将Session ID发送给客户端
  5. 客户端保存Session ID,并在后续请求中通过Cookie头发送回服务器
  6. 服务器根据Session ID识别用户并检索对应的会话信息
  7. 使用Requests库处理Cookie
    Python的Requests库提供了简单而强大的接口来处理HTTP请求和Cookie。下面我们通过实际代码演示如何管理Cookie。
    2.1 基本Cookie处理
    import requests

创建一个会话对象

session = requests.Session()

首次请求,获取初始Cookie

response = session.get('https://httpbin.org/cookies/set/sessioncookie/123456789')
print("首次请求后的Cookies:", session.cookies.get_dict())

后续请求会自动携带Cookie

response = session.get('https://httpbin.org/cookies')
print("服务器接收到的Cookies:", response.json())

手动添加Cookie

session.cookies.update({'custom_cookie': 'value'})
response = session.get('https://httpbin.org/cookies')
print("添加自定义Cookie后的结果:", response.json())
2.2 模拟登录并保持状态
import requests
from urllib.parse import urlencode

创建会话保持登录状态

session = requests.Session()

模拟登录数据(实际应用中需要根据目标网站调整)

login_data = {
'username': 'your_username',
'password': 'your_password',
'remember_me': 'on'
}

设置请求头,模拟浏览器行为

headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
'Referer': 'https://example.com/login',
'Content-Type': 'application/x-www-form-urlencoded'
}

try:

# 发送登录请求
login_url = 'https://example.com/login'
response = session.post(login_url, data=urlencode(login_data), headers=headers)

# 检查登录是否成功
if response.status_code == 200:
    print("登录成功!")
    print("会话Cookies:", session.cookies.get_dict())

    # 访问需要登录的页面
    profile_response = session.get('https://example.com/dashboard')
    print("访问仪表板状态:", profile_response.status_code)

    # 可以继续访问其他需要认证的页面...
else:
    print("登录失败,状态码:", response.status_code)

except requests.exceptions.RequestException as e:
print("请求异常:", e)

  1. 高级Session管理技巧
    在实际爬虫项目中,我们可能需要更精细地控制Session和Cookie的行为。
    3.1 自定义Cookie持久化
    import requests
    import pickle
    import os
    from http.cookiejar import LWPCookieJar

class PersistentSession:
def init(self, cookie_file='cookies.txt'):
self.cookie_file = cookie_file
self.session = requests.Session()

    # 使用LWPCookieJar实现Cookie持久化
    self.session.cookies = LWPCookieJar(cookie_file)

    # 如果存在已保存的Cookie,加载它
    if os.path.exists(cookie_file):
        try:
            self.session.cookies.load(ignore_discard=True)
            print("已加载保存的Cookie")
        except Exception as e:
            print("加载Cookie失败:", e)

def save_cookies(self):
    """保存Cookie到文件"""
    try:
        self.session.cookies.save(ignore_discard=True)
        print("Cookie已保存")
    except Exception as e:
        print("保存Cookie失败:", e)

def clear_cookies(self):
    """清除Cookie"""
    self.session.cookies.clear()
    if os.path.exists(self.cookie_file):
        os.remove(self.cookie_file)
    print("Cookie已清除")

def make_request(self, url, method='GET', **kwargs):
    """发送请求并自动处理Cookie"""
    response = self.session.request(method, url, **kwargs)
    # 每次请求后保存Cookie
    self.save_cookies()
    return response

使用示例

if name == "main":
persistent_session = PersistentSession()

# 发送请求(会自动处理Cookie持久化)
response = persistent_session.make_request('https://httpbin.org/cookies/set/test/value123')
print("响应:", response.json())

# 后续请求会保持状态
response2 = persistent_session.make_request('https://httpbin.org/cookies')
print("后续请求:", response2.json())

3.2 处理复杂的登录场景
import requests
import re
from bs4 import BeautifulSoup

def handle_csrf_login(login_url, username, password):
"""
处理带有CSRF令牌的登录表单
"""
session = requests.Session()

# 首先获取登录页面,提取CSRF令牌
response = session.get(login_url)
soup = BeautifulSoup(response.text, 'html.parser')

# 查找CSRF令牌(根据实际网站调整选择器)
csrf_token = None
token_input = soup.find('input', {'name': 'csrf_token'})
if token_input:
    csrf_token = token_input.get('value')

# 准备登录数据
login_data = {
    'username': username,
    'password': password,
}

if csrf_token:
    login_data['csrf_token'] = csrf_token

# 设置请求头
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
    'Referer': login_url,
    'Content-Type': 'application/x-www-form-urlencoded'
}

# 发送登录请求
response = session.post(login_url, data=login_data, headers=headers)

# 检查登录是否成功(根据实际网站调整验证逻辑)
if "dashboard" in response.url or "欢迎" in response.text:
    print("登录成功!")
    return session
else:
    print("登录失败")
    return None

使用示例

session = handle_csrf_login('https://example.com/login', 'your_username', 'your_password')

if session:

response = session.get('https://example.com/protected-page')

print("受保护页面:", response.status_code)

  1. 处理常见Cookie相关问题
    在实际爬虫开发中,我们会遇到各种Cookie相关的问题,下面提供一些解决方案。
    4.1 处理Cookie过期
    import requests
    import time

def auto_refresh_session(base_url, login_func, refresh_interval=1800):
"""
自动刷新会话的装饰器
:param base_url: 基础URL
:param login_func: 登录函数
:param refresh_interval: 刷新间隔(秒)
"""
def decorator(func):
def wrapper(args, *kwargs):

        # 获取或创建会话
        session = kwargs.get('session')
        if not session or not hasattr(session, 'last_login'):
            session = login_func()
            session.last_login = time.time()
            kwargs['session'] = session

        # 检查是否需要刷新会话
        current_time = time.time()
        if current_time - session.last_login > refresh_interval:
            print("会话已过期,重新登录...")
            session = login_func()
            session.last_login = current_time
            kwargs['session'] = session

        # 执行原始函数
        return func(*args, **kwargs)
    return wrapper
return decorator

使用示例

def example_login():
"""示例登录函数"""
session = requests.Session()

# 这里执行实际的登录操作
print("执行登录操作")
return session

@auto_refresh_session('https://example.com', example_login, refresh_interval=1800)
def fetch_protected_data(session=None):
"""获取需要认证的数据"""
response = session.get('https://example.com/protected-data')
return response.json()
4.2 处理多域名Cookie
import requests
from http.cookiejar import CookieJar

class MultiDomainSession:
def init(self):
self.sessions = {} # 域名到会话的映射
self.main_session = requests.Session()

def get_session_for_domain(self, domain):
    """获取特定域名的会话"""
    if domain not in self.sessions:
        self.sessions[domain] = requests.Session()
    return self.sessions[domain]

def request(self, url, method='GET', **kwargs):
    """发送请求,自动选择正确的会话"""
    from urllib.parse import urlparse

    # 解析URL获取域名
    domain = urlparse(url).netloc

    # 获取对应域名的会话
    session = self.get_session_for_domain(domain)

    # 发送请求
    response = session.request(method, url, **kwargs)
    return response

使用示例

multi_session = MultiDomainSession()

这些请求会使用独立的Cookie存储

response1 = multi_session.request('https://api.example.com/data')
response2 = multi_session.request('https://auth.another-domain.com/login')

  1. 实际案例:爬取需要登录的网站
    下面是一个完整的示例,演示如何爬取需要登录的网站并保持会话状态。
    import requests
    from bs4 import BeautifulSoup
    import time
    import random

代理配置信息

proxyHost = "www.16yun.cn"
proxyPort = "5445"
proxyUser = "16QMSOML"
proxyPass = "280651"

class AuthenticatedScraper:
def init(self, login_url, credentials, use_proxy=True):
self.login_url = login_url
self.credentials = credentials
self.session = requests.Session()
self.is_logged_in = False
self.use_proxy = use_proxy

    # 设置通用请求头
    self.headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
        'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
        'Accept-Language': 'zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3',
        'Connection': 'keep-alive',
        'Upgrade-Insecure-Requests': '1',
    }

    # 设置代理
    self.proxies = self._get_proxies() if use_proxy else None

def _get_proxies(self):
    """获取代理配置"""
    proxyAuth = f"http://{proxyUser}:{proxyPass}@{proxyHost}:{proxyPort}"
    return {
        'http': proxyAuth,
        'https': proxyAuth,
    }

def _get_request_kwargs(self):
    """获取请求参数"""
    kwargs = {
        'headers': self.headers,
        'timeout': 30
    }
    if self.use_proxy:
        kwargs['proxies'] = self.proxies
    return kwargs

def login(self):
    """执行登录操作"""
    try:
        # 首先获取登录页面,提取必要的表单数据
        response = self.session.get(
            self.login_url, 
            **self._get_request_kwargs()
        )
        soup = BeautifulSoup(response.text, 'html.parser')

        # 提取CSRF令牌(根据实际网站调整)
        form = soup.find('form', {'id': 'login-form'})
        if form:
            csrf_input = form.find('input', {'name': 'csrf_token'})
            if csrf_input:
                self.credentials['csrf_token'] = csrf_input.get('value')

        # 发送登录请求
        login_response = self.session.post(
            self.login_url,
            data=self.credentials,
            **self._get_request_kwargs()
        )

        # 检查登录是否成功(根据实际网站调整)
        if login_response.status_code == 200:
            self.is_logged_in = True
            print("登录成功!")
            return True
        else:
            print("登录失败,状态码:", login_response.status_code)
            return False

    except Exception as e:
        print("登录过程中发生错误:", e)
        return False

def scrape_protected_page(self, url, max_retries=3):
    """爬取需要认证的页面"""
    if not self.is_logged_in:
        if not self.login():
            print("无法登录,停止爬取")
            return None

    for attempt in range(max_retries):
        try:
            # 添加随机延迟,避免被检测为爬虫
            if attempt > 0:
                time.sleep(random.uniform(1, 3))

            # 发送请求
            response = self.session.get(
                url, 
                **self._get_request_kwargs()
            )

            # 检查是否仍然处于登录状态
            if "login" in response.url or "请登录" in response.text:
                print("会话可能已过期,尝试重新登录...")
                self.is_logged_in = False
                if self.login():
                    continue  # 重新尝试请求
                else:
                    return None

            # 解析页面内容
            soup = BeautifulSoup(response.text, 'html.parser')
            return soup

        except requests.exceptions.RequestException as e:
            print(f"请求失败 (尝试 {attempt+1}/{max_retries}):", e)
            time.sleep(2)  # 等待后重试

    print(f"在{max_retries}次尝试后仍失败")
    return None

使用示例

if name == "main":

# 配置登录信息(需要根据目标网站调整)
credentials = {
    'username': 'your_username',
    'password': 'your_password'
}

# 创建爬虫实例,启用代理
scraper = AuthenticatedScraper('https://example.com/login', credentials, use_proxy=True)

# 登录并爬取受保护页面
protected_content = scraper.scrape_protected_page('https://example.com/dashboard')

if protected_content:
    # 提取需要的数据
    print("成功获取受保护内容")
    # 例如:提取用户信息
    user_info = protected_content.find('div', {'class': 'user-info'})
    if user_info:
        print("用户信息:", user_info.text.strip())
else:
    print("获取内容失败")
  1. 最佳实践与注意事项
  2. 遵守法律法规和Robots协议:在爬取任何网站前,确保你的行为符合当地法律法规和网站的robots.txt规定。
  3. 尊重网站资源:合理设置请求间隔,避免给目标网站造成过大负担。
  4. 错误处理:完善的错误处理机制是健壮爬虫的关键,包括网络异常、认证过期等情况。
  5. Cookie安全性:不要将包含敏感信息的Cookie分享或存储在不安全的地方。
  6. 定期更新策略:网站经常会更改其认证机制,需要定期更新你的爬虫代码。
  7. 使用代理轮换:对于大规模爬取,考虑使用代理池来避免IP被封锁。
  8. 模拟人类行为:添加随机延迟、模拟鼠标移动等行为可以降低被检测为爬虫的概率。
相关文章
|
1月前
|
数据采集 Web App开发 数据安全/隐私保护
实战:Python爬虫如何模拟登录与维持会话状态
实战:Python爬虫如何模拟登录与维持会话状态
|
2月前
|
数据采集 Web App开发 自然语言处理
新闻热点一目了然:Python爬虫数据可视化
新闻热点一目了然:Python爬虫数据可视化
|
3月前
|
数据采集 数据挖掘 测试技术
Go与Python爬虫实战对比:从开发效率到性能瓶颈的深度解析
本文对比了Python与Go在爬虫开发中的特点。Python凭借Scrapy等框架在开发效率和易用性上占优,适合快速开发与中小型项目;而Go凭借高并发和高性能优势,适用于大规模、长期运行的爬虫服务。文章通过代码示例和性能测试,分析了两者在并发能力、错误处理、部署维护等方面的差异,并探讨了未来融合发展的趋势。
317 0
|
1月前
|
数据采集 监控 数据库
Python异步编程实战:爬虫案例
🌟 蒋星熠Jaxonic,代码为舟的星际旅人。从回调地狱到async/await协程天堂,亲历Python异步编程演进。分享高性能爬虫、数据库异步操作、限流监控等实战经验,助你驾驭并发,在二进制星河中谱写极客诗篇。
Python异步编程实战:爬虫案例
|
2月前
|
数据采集 存储 XML
Python爬虫技术:从基础到实战的完整教程
最后强调: 父母法律法规限制下进行网络抓取活动; 不得侵犯他人版权隐私利益; 同时也要注意个人安全防止泄露敏感信息.
670 19
|
1月前
|
数据采集 存储 JSON
Python爬虫常见陷阱:Ajax动态生成内容的URL去重与数据拼接
Python爬虫常见陷阱:Ajax动态生成内容的URL去重与数据拼接
|
1月前
|
数据采集 存储 JavaScript
解析Python爬虫中的Cookies和Session管理
Cookies与Session是Python爬虫中实现状态保持的核心。Cookies由服务器发送、客户端存储,用于标识用户;Session则通过唯一ID在服务端记录会话信息。二者协同实现登录模拟与数据持久化。
|
2月前
|
数据采集 Web App开发 前端开发
处理动态Token:Python爬虫应对AJAX授权请求的策略
处理动态Token:Python爬虫应对AJAX授权请求的策略
|
2月前
|
数据采集 网络协议 API
协程+连接池:高并发Python爬虫的底层优化逻辑
协程+连接池:高并发Python爬虫的底层优化逻辑
|
3月前
|
数据采集 存储 JSON
地区电影市场分析:用Python爬虫抓取猫眼/灯塔专业版各地区票房
地区电影市场分析:用Python爬虫抓取猫眼/灯塔专业版各地区票房

推荐镜像

更多
下一篇
oss云网关配置