news 2026/10/15 12:56:10

Python requests库:HTTP请求的终极指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Python requests库:HTTP请求的终极指南

1. 为什么每个Python开发者都需要掌握requests

十年前我刚入行时,用Python发送HTTP请求还得忍受urllib2的折磨。直到2012年requests库横空出世,这个仅用pip install requests就能获得的第三方库,彻底改变了Python开发者处理网络请求的方式。如今在PyPI的下载量统计中,requests常年稳居前三,GitHub星标数超过48k,这些数据足以证明它的江湖地位。

requests的核心价值在于:用人类可读的语法完成复杂的HTTP操作。比如获取一个JSON接口的数据,原生urllib需要十多行代码处理连接、异常和编码,而requests只需要:

import requests resp = requests.get('https://api.example.com/data') print(resp.json())

这个设计哲学贯穿整个库——每个API调用都像在说人话。requests.get()对应HTTP GET方法,resp.json()自动解析JSON响应,连超时设置都是直观的timeout=3.0。这种极简主义让新手能快速上手,也让老手能专注于业务逻辑而非协议细节。

2. 核心功能全景解析

2.1 七大HTTP方法全覆盖

requests支持所有主流HTTP方法,每种都有对应的快捷函数:

requests.get(url) # GET requests.post(url) # POST requests.put(url) # PUT requests.delete(url) # DELETE requests.head(url) # HEAD requests.options(url)# OPTIONS requests.patch(url) # PATCH

以POST请求为例,发送表单数据和JSON数据是两种最常见场景。表单提交时,使用data参数自动编码为application/x-www-form-urlencoded:

payload = {'key1': 'value1', 'key2': 'value2'} r = requests.post("https://httpbin.org/post", data=payload)

而发送JSON数据时,既可以直接传递字典给json参数(推荐),也可以手动序列化:

# 方式1:自动序列化 r = requests.post(url, json={'key':'value'}) # 方式2:手动序列化 import json r = requests.post(url, data=json.dumps({'key':'value'}), headers={'Content-Type': 'application/json'})

关键区别:data参数发送原始字节流,需要手动处理编码和头信息;json参数自动处理序列化和Content-Type头

2.2 请求参数的高级控制

实际项目中,我们经常需要精细控制请求行为。requests通过统一的requests.request()方法暴露所有可配置项:

requests.request( method='GET', url='http://example.com', params={'key':'value'}, # URL查询参数 data={'form':'data'}, # 表单数据 json={'json':'data'}, # JSON数据 headers={'X-Header':'value'}, # 自定义头 cookies={'name':'value'}, # Cookie files={'file': open('report.xls', 'rb')}, # 文件上传 auth=('user', 'pass'), # 基础认证 timeout=3.14, # 超时秒数 allow_redirects=False, # 禁用重定向 proxies={'http': 'http://proxy:port'}, # 代理设置 verify='/path/to/cert.pem' # SSL证书验证 )

几个特别实用的参数:

  • timeout:强烈建议始终设置,避免请求挂起阻塞程序。可以传入元组分别指定连接和读取超时:(3.05, 27)
  • allow_redirects:默认True自动跟随重定向,调试时设为False可查看原始响应
  • verify:设为False可跳过SSL验证(仅测试环境使用)

2.3 响应对象的深度挖掘

每个请求返回的Response对象都是信息宝库。除了最常用的resp.status_code和resp.text,这些属性也值得关注:

r = requests.get('https://api.github.com/events') r.encoding # 当前响应编码,如'utf-8' r.content # 原始字节数据(用于非文本内容) r.json() # 自动解析JSON(需响应头正确) r.raw # 原始socket响应(用于流式下载) r.headers # 响应头字典(不区分大小写) r.cookies # 获取的CookieJar对象 r.history # 重定向历史列表 r.url # 最终请求URL(考虑重定向后) r.elapsed # 请求耗时(timedelta对象)

处理二进制内容(如图片下载)的正确姿势:

r = requests.get('https://example.com/image.jpg', stream=True) with open('local.jpg', 'wb') as f: for chunk in r.iter_content(chunk_size=8192): if chunk: # 过滤keep-alive空块 f.write(chunk)

设置stream=True避免立即加载大文件到内存,iter_content()则实现分块写入。

3. 实战技巧与性能优化

3.1 会话保持与连接池

每次requests.get()都新建连接显然低效。使用Session对象可以:

  • 自动保持Cookie(无需手动处理)
  • 复用TCP连接(显著提升性能)
  • 统一配置默认参数
s = requests.Session() s.headers.update({'X-Test': 'true'}) # 会话级头信息 s.auth = ('user', 'pass') # 统一认证 # 所有会话内请求自动携带上述配置 r1 = s.get('https://httpbin.org/cookies') r2 = s.get('https://httpbin.org/headers')

连接池大小通过adapters配置。默认每个主机保持最多2个连接,可通过以下方式调整:

from requests.adapters import HTTPAdapter s = requests.Session() adapter = HTTPAdapter(pool_connections=10, pool_maxsize=100) s.mount('http://', adapter) s.mount('https://', adapter)

3.2 超时与重试机制

生产环境必须考虑网络不可靠性。推荐使用urllib3.util.Retry结合会话:

from urllib3.util import Retry from requests.adapters import HTTPAdapter retry_strategy = Retry( total=3, backoff_factor=1, status_forcelist=[408, 429, 500, 502, 503, 504] ) s = requests.Session() adapter = HTTPAdapter(max_retries=retry_strategy) s.mount("https://", adapter) s.mount("http://", adapter) try: response = s.get("https://example.com", timeout=5) except requests.exceptions.RequestException as e: print(f"请求最终失败: {e}")

这个配置会在以下情况自动重试:

  • 连接/读取超时
  • 指定状态码(如500错误)
  • 最多重试3次,每次间隔按指数退避(1s, 2s, 4s)

3.3 文件上传与流式请求

多文件上传是常见需求,requests支持同时传文件和附加字段:

files = { 'document': ('report.pdf', open('report.pdf', 'rb'), 'application/pdf'), 'image': ('photo.jpg', open('photo.jpg', 'rb'), 'image/jpeg'), 'meta': ('metadata', json.dumps({'author': 'John'}), 'application/json') } r = requests.post('https://httpbin.org/post', files=files)

对于大文件上传,应该使用流式处理避免内存爆炸:

def generate_large_file(): for _ in range(1000000): yield b"some binary data\n" requests.post('https://example.com/upload', data=generate_large_file())

4. 安全防护与异常处理

4.1 证书验证与HTTPS最佳实践

虽然测试时可以用verify=False跳过SSL验证,但生产环境必须确保安全:

# 推荐做法:指定CA证书包路径 requests.get('https://example.com', verify='/path/to/cert.pem') # 或者使用系统默认证书 requests.get('https://example.com', verify=True) # 默认值

客户端证书认证场景:

requests.get('https://example.com', cert=('/path/client.cert', '/path/client.key'))

4.2 异常处理金字塔

requests的异常体系非常完善,应该分层捕获:

try: r = requests.get('https://example.com', timeout=5) r.raise_for_status() # 检查HTTP错误码 except requests.exceptions.Timeout: print("请求超时") except requests.exceptions.SSLError: print("SSL证书错误") except requests.exceptions.RequestException as e: print(f"请求失败: {e}") else: print("请求成功")

特别提醒:永远不要裸奔try-except!以下写法会默默吞掉所有错误:

# 错误示范! try: r = requests.get(url) except: # 捕获所有异常包括KeyboardInterrupt pass

4.3 防范常见安全风险

  1. 注入攻击防护:

    # 危险:直接拼接参数 requests.get(f"https://api.com/search?q={user_input}") # 安全:使用params自动编码 requests.get("https://api.com/search", params={'q': user_input})
  2. 敏感信息泄露:

    # 错误:在日志打印完整响应 print(response.text) # 可能包含敏感数据 # 正确:只记录必要元数据 logger.info(f"Request to {response.url} took {response.elapsed}")
  3. 速率限制处理:

    if response.status_code == 429: retry_after = int(response.headers.get('Retry-After', 60)) time.sleep(retry_after)

5. 调试技巧与高级用法

5.1 请求调试与流量分析

查看实际发出的请求信息对调试至关重要:

# 打印请求头、体等详细信息 print(r.request.headers) print(r.request.body) # 使用hooks记录时间点 def record_timing(response, *args, **kwargs): response.metrics = {'start': kwargs['start'], 'end': time.time()} return response r = requests.get('https://example.com', hooks={'response': record_timing}, start=time.time())

对于复杂场景,建议配合mitmproxy等工具分析实际网络流量。

5.2 自定义适配器与中间件

requests的架构允许深度定制。例如实现一个记录所有请求的适配器:

from requests.adapters import HTTPAdapter class LoggingAdapter(HTTPAdapter): def send(self, request, **kwargs): print(f"Sending {request.method} to {request.url}") response = super().send(request, **kwargs) print(f"Got {response.status_code} from {response.url}") return response s = requests.Session() s.mount('https://', LoggingAdapter()) s.get('https://example.com')

5.3 异步请求方案

虽然requests本身是同步的,但可以结合线程池实现并发:

from concurrent.futures import ThreadPoolExecutor urls = ['https://example.com/1', 'https://example.com/2'] with ThreadPoolExecutor(max_workers=5) as executor: futures = [executor.submit(requests.get, url) for url in urls] results = [f.result().text for f in futures]

对于现代异步框架,推荐使用aiohttp或httpx等原生异步库。

6. 性能对比与生态工具

6.1 主流HTTP库基准测试

在Python生态中,除了requests还有多个HTTP客户端选择。以下是简单对比:

特性requestsurllib3httpxaiohttp
API友好度★★★★★★★☆★★★★☆★★★☆
同步支持✓✓✓✗
异步支持✗✗✓✓
HTTP/2支持✗✗✓✓
连接池✓✓✓✓
安装体积(MB)1.10.62.33.1

requests依然是同步场景下的最佳选择,除非你需要HTTP/2或原生异步支持。

6.2 常用配套工具推荐

  1. requests-cache:为requests添加缓存支持

    import requests_cache requests_cache.install_cache('demo_cache') # 后续请求自动缓存
  2. requests-html:内置HTML解析的增强版

    from requests_html import HTMLSession session = HTMLSession() r = session.get('https://example.com') print(r.html.find('title', first=True).text)
  3. requests-toolbelt:提供多部分编码、流式上传等高级功能

    from requests_toolbelt.multipart.encoder import MultipartEncoder m = MultipartEncoder({'field': 'value', 'file': ('f.txt', open('f.txt', 'rb'))}) requests.post('http://example.com', data=m, headers={'Content-Type': m.content_type})

7. 真实项目经验总结

在电商爬虫项目中,我们每天要处理数百万次API请求。经过多次优化,最终稳定运行的配置如下:

class ApiClient: def __init__(self): self.session = requests.Session() # 连接池配置 adapter = HTTPAdapter( pool_connections=20, pool_maxsize=100, max_retries=Retry( total=3, backoff_factor=0.5, status_forcelist=[500, 502, 503, 504] ) ) self.session.mount('http://', adapter) self.session.mount('https://', adapter) # 默认头信息 self.session.headers.update({ 'User-Agent': 'Mozilla/5.0', 'Accept-Encoding': 'gzip, deflate' }) def request(self, method, url, **kwargs): # 强制超时设置 kwargs.setdefault('timeout', (3.05, 30)) try: resp = self.session.request(method, url, **kwargs) resp.raise_for_status() return resp except requests.exceptions.RequestException as e: logger.error(f"Request failed: {e}") raise

几个关键优化点:

  1. 全局Session减少TCP握手开销
  2. 合理的连接池大小(根据服务器限制调整)
  3. 必须设置超时避免僵尸请求
  4. 统一异常处理和日志记录
  5. 自动重试应对临时故障

在长期实践中,我们发现90%的请求问题源于:

  • 未设置超时导致线程阻塞
  • 未处理重定向丢失Cookies
  • 未考虑代理环境差异
  • 响应编码猜测错误(特别是非UTF-8页面)

requests的Response对象有个不太为人知的特性:自动处理编码的逻辑在resp.apparent_encoding属性中实现。当常规的resp.encoding失效时(比如服务器返回错误的Content-Type),可以这样兜底:

if not resp.encoding or 'ascii' in resp.encoding.lower(): resp.encoding = resp.apparent_encoding
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/15 12:55:16

应用密码学与网络安全期末复习:密钥交换、TLS握手与高频考点解析

简介:这份资源是西安电子科技大学计算机科学与技术专业网络方向「应用密码学与网络安全」期末考试的复习要点整理,面向正在备考该课程的学生,尤其适合需要快速梳理考点、把握题型分布的学习者。内容紧扣PPT授课范围,覆盖选择题与大…

作者头像 李华
网站建设 2026/10/15 12:54:27

ST7529 8080并口LCD驱动实战:时序、初始化与调试

简介:这是一份 BTG-255128B 点阵液晶显示模组的完整配套驱动工程,驱动 IC 为 ST7529,支持 255128 分辨率,内置升压电路,面向嵌入式开发、LCM 模组调试及点阵屏驱动初学者。程序由作者 Huang Xiaolong 编写(…

作者头像 李华
网站建设 2026/10/15 12:54:10

Flood Fill与最短路模型:从漫水到BFS的进阶指南

写这玩意儿之前,我其实犹豫了一下。网络上把Flood Fill(漫水法)单独拎出来讲的教程已经多到烂大街,讲最短路模型的更是堆成山。但把这两者放在一起,当成一个“组合技”来拆解的,还真不多见。不少朋友学算法…

作者头像 李华
网站建设 2026/10/15 12:53:33

电力系统暂态稳定性分析与Matlab仿真实践

1. 项目背景与核心问题电力系统暂态稳定性分析是保障电网安全运行的关键技术环节。当系统遭受大扰动(如短路故障)时,发电机转子角度会出现剧烈摆动,这种动态过程如果失控将导致大面积停电事故。我在某区域电网调度中心工作期间&am…

作者头像 李华
网站建设 2026/10/15 12:52:56

Sketch设计系统入门:Symbol与响应式约束实战指南

1. 项目概述:为什么“初识Sketch”这个标题值得花一整篇干货来拆解?Sketch不是Photoshop,也不是Figma,更不是某个过气设计工具的翻版——它是一套为数字界面而生的、高度垂直的矢量设计工作流。我第一次在某高校UI实验室看到导师用…

作者头像 李华