Requests高级使用指南:状态保持、会话管理与异常处理

在现代网络爬虫和API交互中,简单的GET/POST请求往往不能满足需求。本文将深入探讨Python requests库的高级特性,包括状态保持、会话管理以及常见异常处理,帮助你更好地模拟浏览器行为,完成复杂的网页采集任务。

1. HTTP状态保持与Cookie管理

1.1 为什么需要Cookie

HTTP协议是无状态的,这意味着服务器不会记住之前的请求信息。Cookie的引入解决了这个问题,它允许服务器在客户端存储少量信息,并在后续请求中携带这些信息。

Cookie的主要用途

  • 用户身份验证(如登录状态保持)

  • 个性化设置存储

  • 会话跟踪

  • 行为分析

1.2 在Requests中使用Cookie

Requests提供了两种使用Cookie的方式:

方式1:通过headers添加Cookie
import requests

url = 'https://example.com/protected-page'
headers = {
    'Cookie': 'session_id=12345; user_token=abcde',
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36'
}

response = requests.get(url, headers=headers)
print(response.text)
方式2:通过cookies参数添加(推荐)
import requests

url = 'https://example.com/protected-page'
cookies = {
    'session_id': '12345',
    'user_token': 'abcde'
}

response = requests.get(url, cookies=cookies)
print(response.text)

推荐使用第二种方式,因为:

  1. 字典格式更易维护和修改

  2. 可以避免Cookie字符串格式错误

  3. 方便动态更新Cookie值

2. 会话维持(Session)

2.1 Session的工作原理

Session通过在多个请求间保持某些参数(如Cookie)来实现状态保持。这在需要登录后才能访问的网站中特别有用。

2.2 使用Session对象

import requests

# 创建Session对象
session = requests.Session()

# 第一次请求:登录并设置Cookie
login_url = 'https://example.com/login'
login_data = {'username': 'admin', 'password': '123456'}
session.post(login_url, data=login_data)

# 第二次请求:访问受保护页面,自动携带Cookie
protected_url = 'https://example.com/dashboard'
response = session.get(protected_url)

print(response.text)

关键点

  • Session会自动处理服务器设置的Cookie

  • 后续请求无需手动添加Cookie

  • 适合需要多次交互的场景(如表单提交、验证码处理)

2.3 实际案例:带验证码的登录

import requests
import time

def get_timestamp():
    """获取当前毫秒级时间戳"""
    return str(int(time.time() * 1000))

# 创建Session
session = requests.Session()
headers = {'User-Agent': 'Mozilla/5.0'}

# 1. 获取验证码图片
timestamp = get_timestamp()
captcha_url = f'https://example.com/captcha?t={timestamp}'
captcha_response = session.get(captcha_url, headers=headers)

# 保存验证码图片
with open('captcha.jpg', 'wb') as f:
    f.write(captcha_response.content)

# 2. 用户输入验证码
captcha_code = input('请输入验证码: ')

# 3. 提交登录请求
login_url = 'https://example.com/login'
login_data = {
    'username': 'admin',
    'password': '123456',
    'captcha': captcha_code
}
login_response = session.post(login_url, data=login_data, headers=headers)

print('登录结果:', login_response.json())

3. 常见异常处理

3.1 网页乱码问题

response = requests.get('https://example.com')
# 自动检测编码
response.encoding = response.apparent_encoding
print(response.text)

3.2 请求头参数错误

常见错误:请求头中包含非法字符(如多余空格)

# 错误示例(User-Agent前有空格)
headers = {
    'User-Agent': ' Mozilla/5.0'  # 注意开头的空格
}

# 正确写法
headers = {
    'User-Agent': 'Mozilla/5.0'  # 无多余空格
}

3.3 请求超时处理

try:
    response = requests.get('https://example.com', timeout=5)
    print(response.text)
except requests.exceptions.Timeout:
    print("请求超时,请检查网络连接或增加超时时间")
except requests.exceptions.RequestException as e:
    print(f"请求发生错误: {e}")

 

3.4 连接拒绝错误

try:
    response = requests.get('http://invalid-url:9999')
except requests.exceptions.ConnectionError:
    print("无法连接到服务器,可能是URL错误或服务器未运行")

 

4. 综合实战:模拟百度翻译API

import requests

def baidu_translate(query, from_lang='zh', to_lang='en'):
    url = 'https://fanyi.baidu.com/v2transapi'
    
    headers = {
        'Host': 'fanyi.baidu.com',
        'Origin': 'https://fanyi.baidu.com',
        'Referer': 'https://fanyi.baidu.com/',
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36',
    }
    
    data = {
        'from': from_lang,
        'to': to_lang,
        'query': query,
        'transtype': 'realtime',
        'simple_means_flag': '3',
        'sign': '232427.485594',  # 这个值通常需要动态生成
        'token': '5e393efd8ddbab20a2afa0cfe318606c'  # 需要从页面获取
    }
    
    # 实际使用中需要从浏览器获取有效的Cookie
    cookies = {
        'BAIDUID': 'XXXXXXXXXXXX:FG=1',
        'BDUSS': 'XXXXXXXXXXXX',
        # 其他必要的Cookie项
    }
    
    try:
        response = requests.post(url, headers=headers, data=data, cookies=cookies)
        response.raise_for_status()  # 检查请求是否成功
        return response.json()
    except requests.exceptions.RequestException as e:
        print(f"翻译请求失败: {e}")
        return None

# 使用示例
result = baidu_translate('你好')
if result:
    print('翻译结果:', result['trans_result']['data'][0]['dst'])

注意:实际使用时,需要从浏览器获取有效的token和sign值,以及完整的Cookie。

5. 最佳实践与安全建议

  1. Cookie安全:不要将含有敏感信息的Cookie提交到版本控制系统

  2. 请求频率:合理设置请求间隔,避免被封禁

  3. 错误处理:对所有网络请求添加异常处理

  4. 超时设置:为所有请求设置合理的超时时间

  5. Session复用:对于同一站点的多次请求,尽量复用Session对象

  6. 编码处理:始终检查并正确设置响应编码

 

你可能感兴趣的:(爬虫知识点,python,网络爬虫,爬虫,selenium,课程设计,数据分析)