← 返回网络爬虫目录
← 返回学习笔记首页
Requests库详解
网络爬虫专题 · 掌握爬虫核心HTTP请求库
专题: Python网络爬虫系统学习
关键词: Python, 网络爬虫, Requests, HTTP请求, Session, 请求头, GET, POST, 异常处理
一、Requests库概述
Requests是Python生态中最流行的HTTP请求库,由Kenneth Reitz开发,以其简洁优雅的API设计闻名。它的设计哲学是"HTTP for Humans"(为人类设计的HTTP库),旨在让HTTP请求变得直观自然,无需手动处理URL编码、连接管理、cookie持久化等底层细节。
安装方式非常简单,通过pip即可完成:
pip install requests
与Python标准库中的urllib相比,Requests具有显著优势。urllib虽然功能齐全,但API设计较为底层,发送一个简单的GET请求需要手动处理urlopen、read、decode等多个步骤,而POST请求的参数编码、异常处理等更是需要大量样板代码。Requests将这些复杂性封装在简洁的API背后,一行代码即可完成一个完整的HTTP请求。
"Requests is an elegant and simple HTTP library for Python, built for human beings." -- Kenneth Reitz
Requests基于urllib3开发,在其基础上提供了更高层次的抽象。它默认支持Keep-Alive连接池、自动解压gzip/deflate响应内容、自动处理Cookie持久化、支持文件上传、自动检测响应编码等特性。这些功能在爬虫开发中几乎是必备的,而Requests让它们开箱即用。
二、基本请求方法
Requests为每种HTTP方法都提供了对应的便捷函数,让发送请求变得异常简单。
GET请求
GET是最常用的HTTP方法,用于从服务器获取资源。使用Requests发送GET请求只需调用requests.get()方法:
import requests
response = requests.get('https://api.github.com/events')
print(response.status_code) # 200
print(response.text) # 响应文本内容
POST请求
POST用于向服务器提交数据,如表单提交、API调用等:
import requests
payload = {'key1': 'value1', 'key2': 'value2'}
response = requests.post('https://httpbin.org/post', data=payload)
print(response.json()) # 解析JSON响应
其他HTTP方法
Requests同样支持其他HTTP方法,API风格保持一致:
import requests
response = requests.put('https://httpbin.org/put', data={'key': 'value'})
response = requests.delete('https://httpbin.org/delete')
response = requests.head('https://httpbin.org/get')
response = requests.options('https://httpbin.org/get')
响应对象详解
每次请求都会返回一个Response对象,它包含了服务器返回的所有信息。以下是Response对象最常用的属性和方法:
status_code -- HTTP状态码,如200表示成功,404表示未找到
text -- 服务器响应的文本内容(字符串形式),Requests会自动根据header中的编码或内容自动推测编码
content -- 服务器响应的二进制内容(bytes形式),适合下载图片、文件等
json() -- 将JSON格式的响应内容解析为Python字典或列表,如果响应不是合法JSON会抛出异常
headers -- 响应头的字典形式,不区分大小写,如response.headers['Content-Type']
encoding -- 响应内容的编码格式,可以手动设置如response.encoding = 'utf-8'
url -- 最终的请求URL(可能经过重定向后的最终地址)
elapsed -- 从发送请求到收到响应所经过的时间,是一个timedelta对象,可用于性能监控
提示: 在处理中文网页时,如果text属性出现乱码,通常是因为Requests自动检测的编码不正确。此时可以通过设置response.encoding = 'utf-8' 或 response.encoding = 'gbk' 来手动修正编码。
状态码检查是请求处理中非常关键的一环。Requests提供了raise_for_status()方法,如果响应状态码是4xx或5xx,它会抛出一个HTTPError异常,方便进行统一的错误处理。
response = requests.get('https://httpbin.org/status/404')
try:
response.raise_for_status()
except requests.exceptions.HTTPError as e:
print(f"HTTP错误: {e}")
三、请求参数与配置
Requests提供了丰富的参数用于定制请求行为,覆盖了爬虫开发中的各种场景。
URL查询参数 (params)
使用params参数可以方便地拼接URL查询字符串,Requests会自动进行URL编码:
import requests
params = {
'q': 'python requests',
'page': 1,
'per_page': 20
}
response = requests.get('https://api.github.com/search/repositories', params=params)
print(response.url) # https://api.github.com/search/repositories?q=python+requests&page=1&per_page=20
表单数据 (data) 与JSON数据 (json)
在发送POST请求时,data参数用于提交表单格式的数据,json参数用于提交JSON格式的数据:
import requests
# Form表单数据(Content-Type: application/x-www-form-urlencoded)
form_data = {'username': 'admin', 'password': '123456'}
response = requests.post('https://httpbin.org/post', data=form_data)
# JSON数据(Content-Type: application/json)
json_data = {'name': 'John', 'age': 30}
response = requests.post('https://httpbin.org/post', json=json_data)
自定义请求头 (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.9,en;q=0.8',
'Referer': 'https://www.google.com/'
}
response = requests.get('https://httpbin.org/headers', headers=headers)
其他重要参数
cookies -- 发送自定义Cookie,可传入字典或RequestsCookieJar对象
files -- 文件上传,如files = {'file': open('report.xls', 'rb')}
timeout -- 超时设置,单位秒。可以设置为单个值(连接和读取都适用)或元组(connect_timeout, read_timeout)
allow_redirects -- 是否允许自动跟随重定向,默认True。设置为False可禁止重定向
proxies -- 代理设置,支持HTTP、HTTPS、SOCKS代理
# 超时设置
response = requests.get('https://httpbin.org/delay/5', timeout=(3, 10))
# 代理设置
proxies = {
'http': 'http://127.0.0.1:7890',
'https': 'http://127.0.0.1:7890'
}
response = requests.get('https://httpbin.org/ip', proxies=proxies)
四、Session会话管理
在爬虫开发中,经常需要保持登录状态或共享配置,这时就应该使用requests.Session()。Session对象在同一个会话实例发起的多次请求之间会自动保持Cookie,并且可以设置会话级别的默认参数。
import requests
# 创建Session对象
session = requests.Session()
# 设置会话级别的请求头和Cookie
session.headers.update({
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
})
session.cookies.update({'session_id': 'abc123'})
# 后续所有请求都会自动携带上述headers和cookies
response1 = session.get('https://httpbin.org/cookies')
response2 = session.get('https://httpbin.org/headers')
Session最强大的特性是自动管理Cookie。当你先登录然后访问需要认证的页面时,Session会自动携带登录后设置的Cookie:
import requests
session = requests.Session()
# 第一步:登录
login_data = {'username': 'user', 'password': 'pass'}
session.post('https://example.com/login', data=login_data)
# 第二步:访问需要登录的页面(cookie自动携带)
response = session.get('https://example.com/dashboard')
# 此时已自动携带登录成功后服务器设置的Cookie
Session还支持作为上下文管理器使用,确保请求完成后正确释放资源:
import requests
with requests.Session() as session:
session.headers.update({'User-Agent': 'Custom'})
response = session.get('https://httpbin.org/headers')
print(response.text)
# 会话自动关闭
使用Session的另一个重要优势是连接池复用。Session内部维护了一个urllib3连接池,在向同一主机发送多次请求时,可以复用底层的TCP连接,显著提高请求效率。对于需要大量请求的爬虫任务,使用Session比每次新建连接能提升数倍的性能。
五、请求头伪装
网站通常通过分析请求头来识别爬虫流量,因此合理设置请求头是爬虫开发的核心技能之一。
关键请求头字段
User-Agent -- 声明客户端类型,最常被检查的请求头。浏览器User-Agent包含操作系统、浏览器版本等信息
Referer -- 来源页面URL,用于防盗链和来源验证,表示当前请求是从哪个页面发起的
Accept-Language -- 浏览器接受的语言,中文浏览器通常为zh-CN,zh;q=0.9
Accept-Encoding -- 支持的压缩格式,如gzip, deflate, br
Cookie -- 认证和会话标识,对登录验证至关重要
User-Agent随机切换
单一User-Agent容易被网站识别和封禁,使用fake_useragent库可以方便地随机切换User-Agent:
from fake_useragent import UserAgent
import requests
ua = UserAgent()
headers = {'User-Agent': ua.random} # 每次随机生成一个User-Agent
response = requests.get('https://httpbin.org/headers', headers=headers)
print(response.text)
从浏览器复制请求头
最可靠的伪裝方法是直接从浏览器开发者工具中复制真实的请求头。在Chrome中按F12打开开发者工具,切换到Network标签页,找到目标请求,右键选择"Copy as cURL"或手动复制关键请求头字段。然后将这些请求头原样设置在Requests中,这样服务器几乎无法区分请求是来自爬虫还是真实浏览器。
import requests
# 从浏览器完整复制的请求头
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/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.9,en;q=0.8',
'Accept-Encoding': 'gzip, deflate, br',
'Referer': 'https://www.example.com/',
'Connection': 'keep-alive',
'Upgrade-Insecure-Requests': '1',
'Sec-Fetch-Dest': 'document',
'Sec-Fetch-Mode': 'navigate',
'Sec-Fetch-Site': 'same-origin',
'Sec-Fetch-User': '?1',
}
response = requests.get('https://example.com/target-page', headers=headers)
六、异常处理
网络请求充满了不确定性,完善的异常处理机制是稳健爬虫的基石。Requests定义了一套层次分明的异常体系,所有异常都继承自requests.RequestException。
异常类型
ConnectionError -- DNS解析失败、连接被拒绝、网络不可达等网络层面的错误
HTTPError -- HTTP返回了错误状态码(4xx或5xx),配合raise_for_status()使用
Timeout -- 请求超时,包括连接超时和读取超时
TooManyRedirects -- 重定向次数超过默认上限(默认30次)
RequestException -- 所有异常的基类,捕获它可以处理所有请求相关异常
import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
import time
def fetch_with_retry(url, max_retries=3, backoff_factor=0.5):
session = requests.Session()
# 配置重试策略
retry_strategy = Retry(
total=max_retries, # 总重试次数
backoff_factor=backoff_factor, # 退避因子(等待时间递增)
status_forcelist=[500, 502, 503, 504], # 需要重试的状态码
allowed_methods=['GET', 'POST'] # 允许重试的HTTP方法
)
adapter = HTTPAdapter(max_retries=retry_strategy)
session.mount('http://', adapter)
session.mount('https://', adapter)
try:
response = session.get(url, timeout=10)
response.raise_for_status()
return response
except requests.exceptions.ConnectionError as e:
print(f"连接错误: {e}")
except requests.exceptions.Timeout as e:
print(f"请求超时: {e}")
except requests.exceptions.HTTPError as e:
print(f"HTTP错误: {e}")
except requests.exceptions.RequestException as e:
print(f"请求失败: {e}")
finally:
session.close()
最佳实践: 在爬虫中使用指数退避重试策略。每次重试的等待时间按照backoff_factor * (2 ** (重试次数-1))递增,避免在服务器压力大时集中重试造成更大的负担。推荐将重试配置为3次,退避因子0.5,这样重试间隔分别为0.5秒、1秒、2秒。
七、高级用法
除了基础功能,Requests还提供了一些高级特性,可以应对更复杂的爬虫需求。
流式请求与大文件下载
当需要下载大文件时,使用stream=True可以避免将整个响应内容加载到内存中:
import requests
url = 'https://example.com/large-file.zip'
response = requests.get(url, stream=True)
response.raise_for_status()
with open('large-file.zip', 'wb') as f:
for chunk in response.iter_content(chunk_size=8192):
if chunk: # 过滤keep-alive的空chunk
f.write(chunk)
流式请求的核心优势在于:无论文件多大,内存占用始终保持稳定。每次只处理一个chunk的数据,非常适合下载大文件或处理大型响应流。
自定义SSL证书验证
某些网站使用自签名证书或证书配置有误,导致SSL验证失败。可以通过设置verify参数来控制证书验证行为:
import requests
# 跳过SSL验证(不推荐,存在安全风险)
response = requests.get('https://self-signed.badssl.com', verify=False)
# 使用自定义CA证书
response = requests.get('https://example.com', verify='/path/to/custom/cert.pem')
# 抑制SSL警告
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
hooks钩子函数
Requests支持钩子机制,可以在请求处理的特定阶段执行自定义函数:
import requests
def print_url(response, *args, **kwargs):
print(f"请求URL: {response.url}")
def print_elapsed(response, *args, **kwargs):
print(f"请求耗时: {response.elapsed.total_seconds():.2f}秒")
# 注册钩子,可以在请求的各个阶段调用
hooks = {'response': [print_url, print_elapsed]}
response = requests.get('https://httpbin.org/get', hooks=hooks)
钩子函数在处理批量请求时非常实用,可以用来统一记录日志、统计请求耗时、自动处理重定向、或者在收到特定状态码时触发告警。
连接池管理
Session对象维护了一个连接池,通过HTTPAdapter可以调整其行为:
from requests.adapters import HTTPAdapter
session = requests.Session()
# pool_connections:缓存连接数,pool_maxsize:每个主机的最大连接数
adapter = HTTPAdapter(pool_connections=100, pool_maxsize=100)
session.mount('http://', adapter)
session.mount('https://', adapter)
合理配置连接池参数可以显著提升爬虫的并发请求能力。pool_connections决定缓存多少个不同的主机连接,pool_maxsize决定单个主机最多允许的并发连接数。对于需要高并发抓取的场景,适当增大这两个参数可以有效减少TCP握手开销。
八、核心要点总结
简洁优先: Requests的设计哲学是"HTTP for Humans",让HTTP请求代码简洁直观,一行代码完成一个完整请求
Session复用: 使用Session对象保持Cookie和连接池,避免重复登录和TCP握手,显著提升爬虫效率
请求头伪裝: 合理设置User-Agent、Referer等请求头是反爬虫对抗的基础,配合fake_useragent实现随机切换
异常处理: 全面捕获ConnectionError、Timeout、HTTPError等异常,结合指数退避重试机制确保爬虫稳健运行
流式下载: 大文件下载使用stream=True和iter_content()分块写入,避免内存溢出
时间设置: 始终设置timeout参数,避免爬虫因某个请求卡死而无限等待
代理支持: proxies参数支持HTTP/HTTPS/SOCKS代理,是实现IP轮转绕过封禁的基础
连接池优化: 通过HTTPAdapter调整pool_connections和pool_maxsize参数,适应高并发爬虫场景
九、进一步思考
Requests库虽然强大,但它提供的是同步阻塞式的HTTP请求。在面对大规模爬虫任务时,IO等待时间占据了整个爬虫运行时间的大部分。可以考虑以下优化方向:
首先,可以使用grequests库,它结合了Requests和gevent,通过协程实现异步并发请求,在等待IO时可以切换执行其他任务。其次,aiohttp是基于asyncio的异步HTTP库,提供了更底层的控制和更高的并发性能。对于企业级爬虫框架,Scrapy内置了Twisted异步引擎和中间件系统,支持自动限速、去重、Pipeline等高级功能。
在实际项目中,可以将Requests用于快速原型开发和中小规模爬虫,将Scrapy用于大规模分布式爬虫系统。理解Requests的核心原理,也是深入学习其他HTTP客户端库和爬虫框架的基础。