前言
在 Python 爬虫技术体系中,网络请求模块是实现数据采集的核心入口,而requests库凭借简洁的调用语法、完善的功能封装、优秀的兼容性,成为目前工业界与学习场景中使用率最高的 HTTP 请求库。相较于 Python 标准库内置的urllib系列模块,requests大幅简化了 HTTP 请求的编写逻辑,屏蔽了底层网络交互的复杂细节,支持常规请求、会话保持、文件上传、代理配置、HTTPS 证书处理等全场景功能,能够覆盖绝大多数中小型爬虫、接口测试、数据采集等业务需求。
熟练掌握requests库的基础语法、对象属性、调用逻辑与异常处理,是开展 GET/POST 请求、请求伪装、网页解析等后续爬虫开发工作的必要前提。本文围绕requests库展开全维度实战讲解,从库的安装导入、核心请求对象、常用属性方法,到基础请求案例、异常捕获、基础调试技巧逐一拆解,结合可直接运行的代码示例与底层原理分析,帮助开发者建立完整的requests使用知识体系。
文中涉及的工具、库文档官方链接汇总如下:
- requests 官方文档:https://docs.python-requests.org/
- requests PyPI 主页:https://pypi.org/project/requests/
- HTTP 状态码参考文档:https://httpstatuses.com/
- 在线测试接口平台:https://httpbin.org/
一、requests 库安装与基础导入
1.1 库安装操作
requests属于 Python 第三方开源库,并未随 Python 解释器内置,需要借助pip包管理工具完成安装。结合上一章节配置的国内镜像源,可有效提升安装速度与成功率,全平台通用安装指令如下:
shell
# 常规安装命令,使用已配置的全局镜像源 pip install requests # 如需指定版本安装,示例如下 pip install requests==2.31.0 # 临时指定清华镜像源安装(网络异常时使用) pip install requests -i https://pypi.tuna.tsinghua.edu.cn/simple/安装完成后,可通过pip show requests指令查看库的安装路径、版本号、依赖关系等信息,确认安装状态。若终端提示权限不足,Windows 系统可切换至管理员身份运行命令行,macOS 与 Linux 系统可在指令前追加sudo获取系统权限。
1.2 模块导入规范
在 Python 代码文件中,使用import关键字导入requests模块,这是调用其所有功能的前置操作。标准导入写法如下:
python
运行
# 标准导入方式,项目通用写法 import requests导入完成后,即可通过requests.方法名的形式调用库内封装的各类请求方法、工具函数。若项目中存在多处高频调用,也可结合别名简化书写,语法为import requests as 别名,示例:
python
运行
# 设置别名sp,简化代码书写 import requests as sp行业内默认优先使用原生名称导入,别名方式仅在多模块名称冲突、代码极简编写场景下使用。
二、requests 核心架构与响应对象解析
使用requests发起网络请求后,程序会接收服务器返回的数据流,并自动封装为Response 响应对象。该对象承载了本次网络交互的全部数据,包括响应状态码、网页源码、请求头、响应头、Cookie、编码格式等核心信息。理解 Response 对象的属性与方法,是解析网页数据、判断请求状态的关键。
2.1 核心属性分类与功能说明
下文将 Response 对象常用属性进行分类整理,并结合功能、使用场景、返回数据类型做出说明,同时配套基础代码演示。
表格
| 属性名称 | 数据类型 | 功能描述 | 适用场景 |
|---|---|---|---|
| status_code | 整型 | HTTP 响应状态码,用于判断请求结果 | 校验请求是否成功、识别服务器异常 |
| text | 字符串 | 自动解码后的网页文本内容,即网页源码 | 解析静态网页、提取文本类数据 |
| content | 字节流 | 原始二进制响应数据,未经过解码 | 下载图片、视频、文件、二进制资源 |
| headers | 字典 | 服务器返回的响应头信息 | 分析服务器配置、获取响应字段 |
| request.headers | 字典 | 本次请求携带的请求头信息 | 校验请求伪装、排查请求参数异常 |
| cookies | RequestsCookieJar 对象 | 服务器下发的 Cookie 集合 | 会话保持、登录态维持、身份校验 |
| url | 字符串 | 最终请求的完整 URL 地址(含重定向后地址) | 追踪页面跳转、校验目标地址 |
| encoding | 字符串 | 响应内容的编码格式 | 手动修正编码、解决网页乱码问题 |
| elapsed | 时间对象 | 单次请求的耗时时长 | 接口性能测试、爬虫速度优化 |
2.2 基础示例:发起请求并打印响应属性
以下代码为标准的基础请求模板,调用requests.get()方法向测试地址发起请求,并依次打印上述核心属性,完整演示 Response 对象的调用方式:
python
运行
import requests # 定义目标请求地址,httpbin为专业HTTP测试接口 url = "https://httpbin.org/" # 发起GET请求,接收返回的Response对象 resp = requests.get(url) # 依次打印核心属性 print("HTTP状态码:", resp.status_code) print("最终请求URL:", resp.url) print("请求耗时:", resp.elapsed) print("网页编码格式:", resp.encoding) print("===== 响应头信息 =====") print(resp.headers) print("===== 原始二进制数据长度 =====") print(len(resp.content))代码原理详解
requests.get(url):调用requests库内置的 GET 请求方法,程序基于底层 TCP/IP 协议与目标服务器建立连接,发送 HTTP 请求报文,等待服务器返回数据后,将所有数据封装为Response对象并赋值给变量resp。resp.status_code:读取 HTTP 协议规定的状态码,遵循统一标准,200 系列代表请求成功,400 系列代表客户端错误,500 系列代表服务器错误。resp.text与resp.content:二者是爬虫中使用频率最高的两个属性。text会根据encoding属性自动对二进制数据进行字符解码,输出人类可直接阅读的文本;content保留原始字节流,不做任何编码转换,二进制类资源必须使用该属性读取。resp.encoding:requests会自动从响应头、网页源码中推测编码格式,当自动推测出现偏差时,会直接引发中文乱码,也是后续编码处理章节的核心知识点。
2.3 状态码详解与请求结果判断逻辑
HTTP 状态码是网络请求的 “结果标识”,爬虫程序需要根据状态码自动判断请求是否正常,进而执行后续逻辑。结合爬虫开发场景,对高频状态码划分并说明:
- 2xx 成功类状态码
- 200 OK:请求成功,服务器正常返回数据,是爬虫最期望的返回结果;
- 201 Created:请求成功且服务器创建了新资源,多用于接口提交场景。
- 3xx 重定向类状态码
- 301/302:页面永久 / 临时跳转,
requests默认自动跟随重定向,最终resp.url会显示跳转后的地址;
- 301/302:页面永久 / 临时跳转,
- 4xx 客户端错误类状态码
- 404 Not Found:目标网页不存在,URL 地址错误或页面已删除;
- 403 Forbidden:服务器拒绝访问,大概率触发基础反爬机制;
- 400 Bad Request:请求参数格式错误;
- 5xx 服务器错误类状态码
- 500 Internal Server Error:服务器内部代码报错;
- 502 Bad Gateway、503 Service Unavailable:服务器网关异常、服务宕机或过载。
在实际爬虫开发中,通常以状态码等于 200作为请求成功的判断依据,代码判断模板如下:
python
运行
import requests url = "https://httpbin.org/get" resp = requests.get(url) # 条件判断请求是否成功 if resp.status_code == 200: print("请求成功,开始解析数据") print(resp.text) else: print(f"请求失败,状态码:{resp.status_code}")requests库还提供了内置判定方法resp.ok,该方法会自动判断状态码是否属于 200~299 区间,返回布尔值,可简化判断逻辑:
python
运行
if resp.ok: print("请求正常") else: print("请求异常")三、基础 GET 请求全场景实战
GET 请求是 HTTP 协议中最基础的请求方式,主要用于从服务器获取数据,不会向服务器提交额外数据。日常访问网页、查询公开接口、浏览静态页面,本质都是发送 GET 请求。requests.get()是实现 GET 请求的核心方法,本节结合无参数 GET、带 URL 参数 GET、长链接 GET 等场景逐一实战。
3.1 无参数 GET 请求(基础网页访问)
无参数 GET 请求即直接访问目标 URL,不拼接任何查询参数,适用于访问首页、静态详情页等场景,也是入门最基础的用法。
实战代码
python
运行
import requests # 目标网址:百度首页 target_url = "https://www.baidu.com" # 发起GET请求 response = requests.get(target_url) # 输出核心信息 print("状态码:", response.status_code) # 输出网页源码前500个字符,避免内容过长 print("网页源码片段:", response.text[:500])原理解析
- 程序根据传入的 URL 解析域名与端口,通过 DNS 解析获取服务器 IP 地址,建立 TCP 连接后,按照 HTTP 协议标准构造 GET 请求报文并发送。
- 服务器接收请求后,检索对应页面资源,将网页源码、样式文件、脚本文件等整合为响应数据返回客户端。
response.text[:500]对返回的长文本进行切片截取,仅展示前 500 字符,是调试阶段常用的优化写法。- 该示例中未设置请求头,
requests会使用默认的客户端标识,部分网站会识别默认标识并拦截请求,这也是后续请求伪装章节需要解决的问题。
3.2 带查询参数的 GET 请求
在实际场景中,搜索页面、分页页面、筛选页面的 URL 都会携带查询参数,格式通常为url?键1=值1&键2=值2。例如搜索关键词、切换页码、筛选分类等操作,都会在 URL 末尾拼接参数。
requests.get()方法提供了params参数,专门用于拼接 URL 查询参数,无需开发者手动拼接字符串,有效规避拼接错误、特殊字符转义等问题。
3.2.1 字典传参标准写法
将所有查询参数以字典形式组织,传入params形参,requests会自动完成 URL 拼接、特殊字符编码转义。
实战代码
python
运行
import requests # 基础URL,不包含参数 base_url = "https://httpbin.org/get" # 定义查询参数字典 params_data = { "username": "spider001", "page": 2, "keyword": "Python爬虫" } # 传入params参数,发起带参GET请求 resp = requests.get(base_url, params=params_data) # 打印最终拼接完成的URL print("拼接后的完整URL:", resp.url) # 打印接口返回数据 print("接口响应内容:", resp.text)原理解析
- 字典
params_data内的键值对,对应 URL 中的查询字段与字段值,requests会自动将字典转换为username=spider001&page=2&keyword=Python爬虫格式,并拼接在基础 URL 之后。 - 针对中文、空格、特殊符号等内容,库会自动执行 URL 编码,无需开发者手动调用编码函数,大幅降低编码错误概率。
- 最终
resp.url可以清晰看到拼接后的完整地址,用于校验参数是否传递成功。
3.2.2 列表类型参数传递
部分接口支持一个键对应多个值的参数形式,格式为?tag=java&tag=python,此时可将字典的值设置为列表,requests会自动解析为多组同名参数。
实战代码
python
运行
import requests url = "https://httpbin.org/get" # 列表作为参数值 param = { "tag": ["Python", "Java", "C++"] } resp = requests.get(url, params=param) print("完整URL:", resp.url)运行后可见 URL 自动拼接为tag=Python&tag=Java&tag=C++,完全符合接口参数规范。
3.3 请求超时设置
网络环境存在不确定性,可能出现服务器无响应、网络卡死等问题。若不设置超时时间,requests会永久阻塞等待,导致程序卡死。因此所有正式爬虫代码,必须配置超时参数。
get方法中的timeout参数用于设置超时时间,单位为秒。当请求耗时超过设定时间仍未收到响应,程序会主动抛出requests.exceptions.Timeout异常并终止请求。
实战代码
python
运行
import requests url = "https://httpbin.org/delay/5" # 设置超时时间为3秒,目标接口延迟5秒返回数据,会触发超时异常 try: # timeout=3 代表3秒超时 resp = requests.get(url, timeout=3) print(resp.text) except requests.exceptions.Timeout: print("请求超时,网络或服务器响应缓慢")原理解析
timeout参数定义了从请求发送到数据接收完成的最大允许时长,分为连接超时与读取超时,单一数值代表总超时时间。- 代码中使用
try...except异常捕获结构,主动捕获超时异常,避免程序崩溃,这是工业级爬虫的基础容错规范。 - 超时时间需根据业务场景合理设置,常规网页请求建议设置为 5~10 秒,大型文件下载可适当延长。
四、二进制资源请求实战(图片、文件下载)
前文提到resp.text适用于文本类数据,而图片、音频、视频、压缩包等二进制资源,必须使用resp.content属性读取。结合 GET 请求,本节实现图片下载、文件保存的完整案例,这也是爬虫中资源采集的常用场景。
4.1 单张图片下载实战
实战代码
python
运行
import requests # 图片资源地址 img_url = "https://httpbin.org/image/jpeg" # 发起GET请求 resp = requests.get(img_url, timeout=10) # 判断请求成功后,将二进制数据写入本地文件 if resp.status_code == 200: # 以二进制写入模式打开文件,wb代表write binary with open("test_image.jpg", "wb") as f: # 写入原始二进制数据 f.write(resp.content) print("图片下载完成") else: print("图片请求失败")原理解析
- 图片属于非文本资源,服务器返回的是原始字节流,使用
resp.text会强制解码为字符串,造成文件损坏、无法打开,因此必须使用resp.content获取字节数据。 - 文件操作模式
wb:w表示覆盖写入,b表示二进制模式,二进制文件读写必须携带b标识,否则会出现编码错误。 with open()语句为 Python 推荐的文件读写写法,执行完毕后自动关闭文件句柄,避免资源泄露。
4.2 大文件流式下载优化
下载体积较大的文件时,一次性读取全部resp.content会占用大量内存,容易造成内存溢出。requests支持流式读取,通过stream=True参数开启分块加载,配合迭代器逐块写入文件,降低内存占用。
实战代码
python
运行
import requests file_url = "https://httpbin.org/stream/100" save_path = "stream_file.txt" try: # 开启流式请求,不一次性加载全部内容到内存 resp = requests.get(file_url, stream=True, timeout=20) if resp.ok: with open(save_path, "wb") as f: # 逐块迭代读取数据,默认分块大小适配网络传输单元 for chunk in resp.iter_content(chunk_size=1024): # 过滤空数据块 if chunk: f.write(chunk) print("大文件流式下载完成") except Exception as e: print("文件下载异常:", e)原理解析
stream=True:开启流式传输模式,请求仅建立连接,不会立即加载全部响应数据到内存。iter_content(chunk_size=1024):按指定字节大小分块迭代数据,示例中每块大小为 1024 字节(1KB),逐块读取并写入本地。- 该方案广泛应用于视频、压缩包、大型文档等资源下载,是爬虫项目中优化内存占用的核心手段。
五、requests 会话对象 Session 基础使用
普通的requests.get()请求属于单次独立请求,每一次请求都会重新建立连接、重新获取 Cookie,无法维持登录状态、会话信息。而Session会话对象可以持久化 Cookie、保持 TCP 连接、复用请求上下文,模拟浏览器连续访问多个页面的行为,是实现登录态爬虫、连贯页面采集的核心工具。
5.1 Session 对象基础特性
- 自动存储服务器下发的 Cookie,并在后续同一会话的请求中自动携带;
- 复用底层 TCP 连接,提升连续请求的响应速度;
- 统一管理请求头、代理、超时等公共配置,简化重复代码。
5.2 基础会话请求实战
实战代码
python
运行
import requests # 1. 创建会话对象,整个生命周期内共享Cookie与连接 session = requests.Session() # 第一次请求,服务器返回Cookie并由session自动保存 url1 = "https://httpbin.org/cookies/set/spider/123456" resp1 = session.get(url1) print("第一次请求响应:", resp1.text) # 第二次请求,session自动携带上一步获取的Cookie url2 = "https://httpbin.org/cookies" resp2 = session.get(url2) print("第二次请求(携带Cookie):", resp2.text) # 关闭会话,释放连接与资源 session.close()原理解析
requests.Session()创建独立会话实例,该实例独立于普通请求,拥有专属的 Cookie 容器、连接池。- 第一个接口
/cookies/set会向客户端下发自定义 Cookie,会话对象自动接收并保存。 - 访问
/cookies接口查询当前请求携带的 Cookie,可见上一步设置的 Cookie 已自动携带,证明会话状态保持生效。 session.close()用于主动关闭会话,释放网络连接资源,程序结束前建议执行该操作。
5.3 会话对象设置全局请求参数
对于同一会话下的多次请求,可统一设置请求头、超时时间等参数,无需在每一个get方法中重复传入,简化代码结构:
python
运行
import requests session = requests.Session() # 为整个会话设置全局超时时间 session.timeout = 8 # 两次请求均自动继承全局超时配置 url_1 = "https://httpbin.org/get" url_2 = "https://httpbin.org/headers" resp1 = session.get(url_1) resp2 = session.get(url_2) print(resp1.status_code, resp2.status_code) session.close()六、异常捕获与健壮性优化
网络请求属于 IO 密集型操作,受网络波动、服务器状态、URL 合法性、反爬策略等多重因素影响,极易出现各类异常。完善的异常捕获机制是爬虫稳定运行的保障,本节梳理requests高频异常类型,并搭建通用异常捕获模板。
6.1 高频异常类型汇总
表格
| 异常类 | 触发场景 |
|---|---|
| requests.exceptions.Timeout | 请求超时,服务器响应缓慢或网络中断 |
| requests.exceptions.ConnectionError | 连接失败,域名错误、服务器宕机、断网 |
| requests.exceptions.SSLError | HTTPS 证书验证失败 |
| requests.exceptions.TooManyRedirects | 重定向次数过多,陷入死循环跳转 |
| requests.exceptions.RequestException | 所有 requests 异常的父类,通用捕获 |
6.2 通用异常捕获模板
该模板覆盖主流异常类型,可作为所有requests请求的标准代码框架:
python
运行
import requests from requests.exceptions import Timeout, ConnectionError, SSLError, RequestException url = "https://www.baidu.com" try: resp = requests.get(url, timeout=5) resp.raise_for_status() # 主动抛出4xx/5xx状态码异常 print("请求成功,源码长度:", len(resp.text)) except Timeout: print("异常:请求超时") except ConnectionError: print("异常:网络连接失败,请检查URL与网络状态") except SSLError: print("异常:HTTPS证书验证失败") except RequestException as e: print(f"请求通用异常:{str(e)}")原理解析
resp.raise_for_status():主动校验状态码,若为 4xx、5xx 错误,手动抛出异常,避免程序继续执行无效逻辑。- 异常捕获顺序遵循子类在前,父类在后原则,优先捕获具体异常,最后使用父类
RequestException兜底。 - 该模板可直接复用在所有爬虫请求代码中,大幅提升程序容错能力。
七、本章综合实战案例:多页面数据采集
结合本章所学的 GET 请求、参数拼接、超时设置、异常捕获、会话保持等知识点,编写综合实战案例,实现带分页的模拟数据采集,整合全部核心技能。
python
运行
import requests from requests.exceptions import RequestException # 基础配置 base_url = "https://httpbin.org/get" session = requests.Session() session.timeout = 6 # 循环采集1-3页数据 for page in range(1, 4): params = { "page_num": page, "source": "spider_demo" } try: resp = session.get(base_url, params=params) resp.raise_for_status() print(f"===== 第{page}页数据 =====") print(resp.text) except RequestException as e: print(f"第{page}页采集失败,错误信息:{e}") session.close() print("多页面采集任务执行完毕")案例说明
- 使用
Session维持会话状态,保证分页请求上下文连贯; - 通过循环 + 字典参数实现分页功能,符合真实分页爬虫的开发逻辑;
- 全局设置超时时间,搭配统一异常捕获,保证程序连续运行;
- 该案例完整复刻了常规列表页爬虫的请求逻辑,可直接迁移至真实网站使用。