欢迎光临
我们一直在努力

爬虫中的Requests库完全指南:从GET/POST到会话管理

学爬虫不学Requests,就像学做菜不学用刀——切不动,撕不烂,只能干瞪眼。

一、为什么Requests是Python爬虫的第一课?

在Python的HTTP请求库中,Requests是一个绕不开的名字。它被开发者誉为“HTTP for Humans”——为人类设计的HTTP库 。相比Python自带的urllib,Requests的API设计极其简洁,几行代码就能完成复杂的请求操作 。

Requests的优势速览

特性Requestsurllib(内置)
代码简洁度 ⭐⭐⭐⭐⭐ ⭐⭐
会话管理 自动处理Cookie 需手动操作
JSON解析 内置支持 需额外处理
文件上传 一行代码搞定 复杂且易错
异常处理 清晰明确 繁琐混乱

一句话总结:用Requests,你关注的是“我要请求什么”;用urllib,你纠结的是“怎么把这个请求发出去” 。

二、快速上手:第一个Requests程序

2.1 安装

pip install requests

2.2 三行代码感受Requests的魅力

import requests

# 发送GET请求
response = requests.get('https://www.baidu.com')
# 打印响应状态码和内容前100个字符
print(f"状态码: {response.status_code}")
print(f"响应内容: {response.text[:100]}")

是不是感觉比urllib简单太多了?

三、GET请求全解析

GET请求用于从服务器获取资源,是最常见的HTTP方法。

3.1 基础GET请求

import requests

# 最简单的GET请求
response = requests.get('https://api.github.com/events')
print(response.status_code) # 200表示成功
print(response.text) # 打印响应内容

3.2 带参数的GET请求

很多时候,我们需要在URL后面带上查询参数,比如?page=2&limit=20。用Requests,你不需要手动拼接URL :

import requests

# 参数用字典表示
params = {
'page': 2,
'limit': 20,
'keyword': 'python爬虫'
}

# 自动拼接为:https://api.example.com/search?page=2&limit=20&keyword=python爬虫
response = requests.get('https://api.example.com/search', params=params)

# 查看最终请求的URL
print(response.url) # 自动进行了URL编码
print(response.text)

小技巧:params参数会自动处理中文字符的URL编码,不用担心乱码问题 。

3.3 自定义请求头

很多网站会检查请求头中的User-Agent来识别是不是爬虫。我们可以通过headers参数伪装成浏览器 :

import requests

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,*/*;q=0.8',
'Accept-Language': 'zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3',
'Referer': 'https://www.google.com', # 告诉服务器从哪个页面跳转过来
}

response = requests.get('https://www.zhihu.com/explore', headers=headers)
print(response.status_code)

四、POST请求全解析

POST请求用于向服务器提交数据,常用于登录、注册、表单提交等场景 。

4.1 提交表单数据(Form Data)

传统的HTML表单提交,数据格式是application/x-www-form-urlencoded。使用data参数 :

import requests

# 登录参数
login_data = {
'username': 'your_username',
'password': 'your_password',
'remember': '1'
}

response = requests.post('https://httpbin.org/post', data=login_data)
print(response.json()) # httpbin.org会返回我们发送的数据

4.2 提交JSON数据(推荐)

现在大多数API都使用JSON格式进行交互。使用json参数,Requests会自动设置正确的Content-Type并将字典转为JSON字符串 :

import requests

# JSON格式的数据
json_data = {
'title': 'Python Requests教程',
'content': '这是一篇关于Requests库的详细教程',
'tags': ['python', '爬虫', 'http'],
'published': True
}

response = requests.post('https://api.example.com/posts', json=json_data)

if response.status_code == 201: # 201表示创建成功
print("文章创建成功:", response.json())

重点对比:

  • data=dict:发送表单数据(Content-Type: application/x-www-form-urlencoded)
  • json=dict:发送JSON数据(Content-Type: application/json)

4.3 综合案例:模拟登录知乎

import requests

def login_zhihu(username, password):
"""
模拟知乎登录(示例代码,实际知乎登录更复杂)
"""

# 登录URL
login_url = 'https://www.zhihu.com/api/v3/oauth/sign_in'

# 构建请求头
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
'Referer': 'https://www.zhihu.com/signin',
'x-requested-with': 'fetch',
}

# 构建登录数据
login_data = {
'username': username,
'password': password,
'remember_me': 'true',
}

try:
# 发送POST请求
response = requests.post(login_url, headers=headers, json=login_data)
response.raise_for_status() # 检查请求是否成功

# 解析返回的JSON数据
result = response.json()
print("登录成功!")
return result
except requests.exceptions.RequestException as e:
print(f"登录失败: {e}")
return None

# 使用示例(请替换为真实账号)
# result = login_zhihu('your_email', 'your_password')

五、会话管理:Session对象

前面我们学到的都是单次请求。但在实际爬虫中,我们经常需要保持状态——比如登录后继续访问其他页面。这时候就需要Session对象了 。

5.1 为什么要用Session?

假设你要模拟用户操作:

  • 访问登录页(GET)
  • 提交登录表单(POST)
  • 访问个人中心(GET)
  • 如果每次都用requests.get()或requests.post(),服务器会把三次请求当成三个独立的、无关的访问。因为每次请求都是新建的连接,之前的Cookie信息丢失了 。

    Session的解决方案:使用requests.Session()创建一个会话对象,它会自动保持Cookie、复用TCP连接,让服务器认为这是同一个用户在操作 。

    5.2 Session基础用法

    import requests

    # 创建一个会话对象
    session = requests.Session()

    # 设置全局请求头(所有通过该session发出的请求都会带上)
    session.headers.update({
    'User-Agent': 'Mozilla/5.0',
    'Accept-Language': 'zh-CN,zh;q=0.9'
    })

    # 第1步:访问登录页(可能会获取一些初始Cookie)
    session.get('https://httpbin.org/cookies/set/sessionid/123456')

    # 第2步:提交登录(自动携带上一步获取的Cookie)
    login_response = session.post('https://httpbin.org/post',
    data={'username': 'test'})

    # 第3步:访问个人中心(依然携带之前的Cookie)
    profile_response = session.get('https://httpbin.org/cookies')

    print(profile_response.text) # 可以看到服务器接收到了之前设置的Cookie

    5.3 Session的核心优势

    特性普通请求Session会话
    Cookie持久化 每次请求需手动处理 自动存储和发送
    TCP连接复用 每次新建连接 连接池复用
    全局配置 每次都要设置 一次设置,全局生效
    性能 高(尤其多次请求同一域名)

    5.4 实战:使用Session完成登录-访问全流程

    import requests
    from bs4 import BeautifulSoup

    class ForumCrawler:
    """论坛爬虫示例 – 使用Session保持登录状态"""

    def __init__(self):
    self.session = requests.Session()
    self.session.headers.update({
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
    })
    self.base_url = 'https://example-forum.com' # 替换为目标网站

    def get_csrf_token(self):
    """访问登录页,获取CSRF Token"""
    try:
    response = self.session.get(f'{self.base_url}/login')
    soup = BeautifulSoup(response.text, 'html.parser')
    # 从页面中提取CSRF Token
    token = soup.find('input', {'name': 'csrf_token'}).get('value')
    return token
    except Exception as e:
    print(f"获取CSRF Token失败: {e}")
    return None

    def login(self, username, password):
    """执行登录"""
    # 先获取CSRF Token
    csrf_token = self.get_csrf_token()
    if not csrf_token:
    return False

    # 构建登录数据
    login_data = {
    'username': username,
    'password': password,
    'csrf_token': csrf_token,
    'remember': 'on'
    }

    try:
    # 发送登录请求
    response = self.session.post(
    f'{self.base_url}/login',
    data=login_data,
    allow_redirects=True # 允许重定向
    )

    # 判断登录是否成功(根据页面特征判断)
    if '欢迎回来' in response.text or '个人中心' in response.text:
    print("登录成功!")
    return True
    else:
    print("登录失败,请检查账号密码")
    return False

    except requests.exceptions.RequestException as e:
    print(f"登录请求异常: {e}")
    return False

    def get_profile(self):
    """获取个人资料页"""
    try:
    response = self.session.get(f'{self.base_url}/profile')
    if response.status_code == 200:
    print("成功访问个人资料页")
    return response.text
    else:
    print(f"访问失败,状态码: {response.status_code}")
    return None
    except Exception as e:
    print(f"获取个人资料异常: {e}")
    return None

    def close(self):
    """关闭会话"""
    self.session.close()
    print("会话已关闭")

    # 使用示例
    crawler = ForumCrawler()
    if crawler.login('test_user', 'password123'):
    profile_html = crawler.get_profile()
    # 处理个人资料页面…
    crawler.close()

    5.5 Session的高级用法

    5.5.1 设置超时

    import requests
    from requests.adapters import HTTPAdapter

    session = requests.Session()

    # 为所有请求设置超时(连接超时3.05秒,读取超时27秒)
    session.timeout = (3.05, 27) # (连接超时, 读取超时)

    # 或者为特定域名设置适配器
    adapter = HTTPAdapter(
    max_retries=3, # 最大重试次数
    pool_connections=10, # 连接池大小
    pool_maxsize=10
    )
    session.mount('https://', adapter)
    session.mount('http://', adapter)

    5.5.2 使用代理

    在爬虫中,经常需要使用代理来避免IP被封 :

    import requests

    session = requests.Session()

    # 设置代理
    proxies = {
    'http': 'http://127.0.0.1:7890', # HTTP代理
    'https': 'http://127.0.0.1:7890' # HTTPS代理
    }
    session.proxies.update(proxies)

    # 需要认证的代理
    proxy_auth = {
    'http': 'http://username:password@proxy-server.com:8080',
    'https': 'https://username:password@proxy-server.com:8080'
    }
    session.proxies.update(proxy_auth)

    5.5.3 Cookie的持久化

    有时我们需要保存登录状态,下次程序启动时恢复 :

    import requests
    import pickle

    # 保存会话
    def save_session(session, filename='session.cookie'):
    with open(filename, 'wb') as f:
    pickle.dump(session.cookies, f)

    # 加载会话
    def load_session(session, filename='session.cookie'):
    try:
    with open(filename, 'rb') as f:
    session.cookies.update(pickle.load(f))
    return True
    except FileNotFoundError:
    return False

    # 使用示例
    session = requests.Session()

    # 尝试加载之前的登录状态
    if load_session(session):
    print("已恢复之前的登录状态")
    # 可以直接访问需要登录的页面
    response = session.get('https://example.com/profile')
    else:
    print("未找到保存的会话,需要重新登录")
    # 执行登录流程…
    session.post('https://example.com/login', data={'user':'xxx'})
    # 保存登录状态
    save_session(session)

    六、处理响应内容

    6.1 响应对象的基本属性

    import requests

    response = requests.get('https://api.github.com/events')

    # 状态码
    print(response.status_code) # 200

    # 响应头
    print(response.headers) # 字典形式
    print(response.headers['Content-Type'])

    # 响应内容 – 文本形式
    print(response.text)

    # 响应内容 – 二进制形式(用于图片、文件等)
    print(response.content)

    # 响应内容 – JSON形式
    print(response.json()) # 自动解析为Python字典/列表

    # 编码
    print(response.encoding) # 可能为 'utf-8'
    response.encoding = 'utf-8' # 可以手动设置编码

    6.2 状态码检查

    import requests

    response = requests.get('https://api.github.com/user')

    # 方法1:手动检查
    if response.status_code == 200:
    print("请求成功")
    elif response.status_code == 404:
    print("资源不存在")
    elif response.status_code == 500:
    print("服务器错误")

    # 方法2:使用raise_for_status(推荐)
    try:
    response.raise_for_status() # 状态码不是200时抛出异常
    data = response.json()
    print("请求成功:", data)
    except requests.exceptions.HTTPError as e:
    print(f"HTTP错误: {e}")

    七、异常处理

    网络请求总是充满不确定性,良好的异常处理能让爬虫更健壮 :

    import requests
    from requests.exceptions import RequestException, Timeout, ConnectionError, HTTPError

    def safe_request(url, method='GET', **kwargs):
    """
    安全的请求函数,统一处理各种异常
    """

    try:
    if method.upper() == 'GET':
    response = requests.get(url, timeout=10, **kwargs)
    elif method.upper() == 'POST':
    response = requests.post(url, timeout=10, **kwargs)
    else:
    raise ValueError(f"不支持的请求方法: {method}")

    # 检查HTTP状态码
    response.raise_for_status()
    return response

    except Timeout:
    print(f"请求超时: {url}")
    except ConnectionError:
    print(f"连接错误: {url}")
    except HTTPError as e:
    print(f"HTTP错误 {e.response.status_code}: {url}")
    except RequestException as e:
    print(f"请求异常: {e}")

    return None

    # 使用示例
    response = safe_request('https://httpbin.org/delay/5', timeout=3)
    if response:
    print("请求成功")

    八、性能优化与最佳实践

    8.1 使用Session提高性能

    当你需要多次请求同一域名时,务必使用Session。它通过连接池复用TCP连接,可以大幅提升性能 :

    import requests
    import time

    # 不使用Session – 每次新建连接
    def without_session():
    start = time.time()
    for i in range(10):
    requests.get('https://httpbin.org/get')
    return time.time() start

    # 使用Session – 复用连接
    def with_session():
    session = requests.Session()
    start = time.time()
    for i in range(10):
    session.get('https://httpbin.org/get')
    session.close()
    return time.time() start

    print(f"无Session耗时: {without_session():.2f}秒")
    print(f"使用Session耗时: {with_session():.2f}秒")
    # 实测Session版本可能快50%以上

    8.2 设置合理的超时

    永远不要不设置超时!没有超时的请求可能永远卡住 :

    # 好的做法
    response = requests.get('https://example.com', timeout=5)

    # 更好的做法:分别设置连接超时和读取超时
    response = requests.get('https://example.com', timeout=(3.05, 10))

    8.3 限制重定向

    # 禁止重定向
    response = requests.get('https://github.com/', allow_redirects=False)

    # 获取重定向历史
    response = requests.get('https://github.com/')
    for resp in response.history:
    print(f"重定向: {resp.status_code} -> {resp.url}")

    8.4 流式下载大文件

    import requests

    # 流式下载大文件,避免内存暴涨
    response = requests.get('https://example.com/large-file.zip', stream=True)
    with open('large-file.zip', 'wb') as f:
    for chunk in response.iter_content(chunk_size=8192):
    f.write(chunk)

    九、实战综合案例:带登录的爬虫

    下面是一个完整的爬虫示例,综合运用了本文介绍的所有知识点:

    import requests
    from requests.exceptions import RequestException
    import time
    import json

    class DoubanSpider:
    """
    豆瓣电影爬虫示例 – 展示Requests库的完整用法
    """

    def __init__(self):
    self.session = requests.Session()
    self.session.headers.update({
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
    'Accept': 'application/json',
    'Accept-Language': 'zh-CN,zh;q=0.9',
    })
    # 设置连接池
    adapter = requests.adapters.HTTPAdapter(
    pool_connections=10,
    pool_maxsize=20,
    max_retries=3
    )
    self.session.mount('http://', adapter)
    self.session.mount('https://', adapter)

    def get_movie_top250(self, start=0):
    """
    获取豆瓣电影Top250
    """

    url = 'https://movie.douban.com/j/search_subjects'
    params = {
    'type': 'movie',
    'tag': '热门',
    'sort': 'recommend',
    'page_limit': 20,
    'page_start': start
    }

    try:
    response = self.session.get(
    url,
    params=params,
    timeout=(3, 5),
    headers={'Referer': 'https://movie.douban.com/'}
    )
    response.raise_for_status()

    data = response.json()
    return data.get('subjects', [])

    except RequestException as e:
    print(f"获取电影列表失败: {e}")
    return []

    def crawl_top250(self):
    """
    爬取所有Top250电影
    """

    all_movies = []
    for start in range(0, 250, 20):
    print(f"正在爬取第{start}{start+20}部…")
    movies = self.get_movie_top250(start)
    all_movies.extend(movies)

    # 礼貌延迟,避免被封
    time.sleep(2)

    if len(movies) < 20: # 没有更多数据了
    break

    return all_movies

    def close(self):
    """关闭会话"""
    self.session.close()
    print("爬虫结束,会话已关闭")

    # 使用示例
    if __name__ == '__main__':
    spider = DoubanSpider()
    try:
    movies = spider.crawl_top250()
    print(f"共爬取到{len(movies)}部电影")
    # 保存到文件
    with open('movies.json', 'w', encoding='utf-8') as f:
    json.dump(movies, f, ensure_ascii=False, indent=2)
    finally:
    spider.close()

    十、总结

    经过本文的学习,我们全面掌握了Requests库的核心用法:

    知识点核心内容
    GET请求 获取资源,通过params传参
    POST请求 提交数据,data传表单,json传JSON
    请求头 通过headers参数伪装浏览器
    Session 保持会话状态,自动管理Cookie,复用连接
    超时 必须设置,避免永久等待
    异常处理 捕获各类网络异常,提高健壮性
    代理 突破IP限制,避免被封

    最后几点建议

  • 能用Session就别用单次请求 – 性能更好,代码更简洁
  • 超时一定要设置 – 5秒是个不错的默认值
  • 伪装要全面 – User-Agent、Referer、Cookie都要考虑
  • 礼貌爬取 – 设置延迟,遵守robots.txt
  • 异常处理要到位 – 网络请求不可靠,做好重试和容错
  • Requests库就像爬虫世界的一把瑞士军刀——简单、实用、功能强大。掌握它,你的爬虫之路就成功了一半!

    赞(0)
    未经允许不得转载:171主机测评 » 爬虫中的Requests库完全指南:从GET/POST到会话管理
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址