一、为什么还要学习 requests
在前面的章节中,我们已经学习了如何使用 urllib 发送请求。
但是 urllib 的写法相对底层:
- 需要手动构造 Request 对象
- 需要手动处理编码
- 代码相对繁琐
而在实际开发中,我们更希望:
- 写更少的代码
- 更直观地发送请求
- 更方便地处理参数、请求头、Cookie
requests 正是为了解决这些问题而设计的。
可以简单理解为:
- urllib:底层工具
- requests:工程级工具(更常用)
为了更直观理解差异,可以对比一个简单请求:
# urllib 写法(简化示例)
from urllib import request
# 构造请求对象
req = request.Request('https://www.baidu.com')
# 发送请求并获取响应
res = request.urlopen(req)
# 读取内容(字节)
html = res.read()
# requests 写法
import requests
# 一行完成请求
res = requests.get('https://www.baidu.com')
# 直接获取文本
html = res.text
可以看到 requests 在可读性和简洁性上更有优势。
二、requests 是什么
requests 是 Python 中一个用于发送 HTTP 请求的第三方库。
它的核心作用是:
- 向服务器发送请求
- 接收服务器返回的数据
相比 urllib,它的优势在于:
- API 简洁
- 代码更易读
- 内置很多常用功能(参数、Cookie、代理等)
常见的 HTTP 方法包括:
- GET:获取数据(最常见)
- POST:提交数据(表单、接口)
- PUT/PATCH:更新数据
- DELETE:删除数据
在爬虫中,最常用的是 GET 和 POST。
三、安装 requests
pip install requests
安装完成后,可以测试:
# 导入 requests 模块
import requests
如果没有报错,说明安装成功。
建议在虚拟环境中安装:
python -m venv venv
source venv/bin/activate # macOS / Linux
pip install requests
四、第一个 requests 程序
# 导入 requests
import requests
# 定义目标网址
url = 'https://www.baidu.com'
# 发送 GET 请求
response = requests.get(url)
# 获取网页内容(字符串形式)
text = response.text
# 输出内容
print(text)
执行流程说明
- 导入 requests
- 定义 URL
- 调用 get() 发送请求
- 获取返回结果(Response 对象)
- 读取内容
可以简单检查请求是否成功:
# 状态码判断
if response.status_code == 200:
print('请求成功')
else:
print('请求失败,状态码:', response.status_code)
也可以使用:
# 若状态码不是 2xx 会抛异常
response.raise_for_status()
五、Response 对象详解
# 导入 requests
import requests
# 发送请求
response = requests.get('https://www.baidu.com')
# 获取文本内容(已解码)
print(response.text)
# 获取二进制内容
print(response.content)
# 获取状态码
print(response.status_code)
# 获取最终 URL
print(response.url)
# 获取响应头
print(response.headers)
# 查看编码
print(response.encoding)
如果接口返回的是 JSON 数据,也可以直接使用:
# 将响应内容直接解析为 Python 对象
print(response.json())
不过要注意:只有当服务器返回的内容本身就是 JSON 格式时,json() 才能正常使用。
重点说明
- text:字符串(自动解码)
- content:字节(适合图片/文件)
- status_code:200 表示成功
- url:最终访问地址(适合检查参数拼接结果)
- headers:响应头信息
- encoding:当前响应编码
如果页面出现乱码,可以手动设置编码:
response.encoding = 'utf-8'
print(response.text)
也可以查看服务器返回的编码:
print(response.apparent_encoding)
获取单个响应头:
print(response.headers.get('Content-Type'))
六、GET 请求详解
# 导入 requests
import requests
# 定义 URL
url = 'https://www.baidu.com/s'
# 定义参数
params = {
'wd': 'Python'
}
# 定义请求头
headers = {
'User-Agent': 'Mozilla/5.0'
}
# 发送 GET 请求
response = requests.get(url, params=params, headers=headers)
# 输出结果
print(response.text)
还可以通过 response.url 查看 requests 最终拼接出来的请求地址:
# 输出最终请求地址
print(response.url)
说明
- params:自动拼接到 URL
- headers:伪装浏览器
- requests 会自动处理参数编码
- 相比 urllib,不需要手动调用
urlencode()
params 也可以传入多个参数:
params = {
'wd': 'Python',
'pn': 10
}
设置超时时间:
response = requests.get(url, params=params, timeout=10)
七、POST 请求详解
# 导入 requests
import requests
# 接口地址
url = 'https://httpbin.org/post'
# POST 数据
data = {
'username': 'test',
'password': '123456'
}
# 发送 POST 请求
response = requests.post(url, data=data)
# 输出返回结果
print(response.text)
如果接口要求提交 JSON 数据,也可以使用 json 参数:
# 导入 requests
import requests
# 接口地址
url = 'https://httpbin.org/post'
# JSON 数据
json_data = {
'username': 'test',
'password': '123456'
}
# 发送 POST 请求,并以 JSON 格式提交
response = requests.post(url, json=json_data)
# 输出返回结果
print(response.text)
说明
- data:POST 表单数据
- POST 常用于提交数据
data常用于普通表单提交json常用于接口请求
当使用 json= 时,requests 会自动设置:
Content-Type: application/json
如果使用 data=,通常是:
Content-Type: application/x-www-form-urlencoded
八、GET 与 POST 的区别
| 类型 | GET | POST |
|---|---|---|
| 参数位置 | URL | 请求体 |
| 安全性 | 较低 | 较高 |
| 使用场景 | 查询 | 提交 |
九、Session(会话保持)
在多个请求之间共享 Cookie,可以使用 Session。
import requests
# 创建会话对象
session = requests.Session()
# 第一次请求(登录或设置 Cookie)
session.get('https://httpbin.org/cookies/set?name=python')
# 第二次请求会自动带上 Cookie
response = session.get('https://httpbin.org/cookies')
print(response.text)
适用于:
- 登录后访问页面
- 多次请求需要共享状态
十、代理参数 proxies
import requests
url = 'https://httpbin.org/ip'
proxies = {
'http': 'http://127.0.0.1:7890',
'https': 'http://127.0.0.1:7890'
}
response = requests.get(url, proxies=proxies)
print(response.text)
说明:
http表示 HTTP 请求使用的代理https表示 HTTPS 请求使用的代理- 代理地址是否可用,会直接影响请求是否成功
也可以通过环境变量设置代理:
export HTTP_PROXY=http://127.0.0.1:7890
export HTTPS_PROXY=http://127.0.0.1:7890
十一、Cookie 基础说明
import requests
url = 'https://httpbin.org/cookies'
cookies = {
'name': 'python'
}
response = requests.get(url, cookies=cookies)
print(response.text)
说明:
- Cookie 常用于保持登录状态
- 某些网站如果不携带 Cookie,返回的页面内容可能不完整
- requests 中可以直接通过字典传入 Cookie
有时需要从浏览器复制 Cookie:
headers = {
'Cookie': 'name=python; sessionid=xxx'
}
response = requests.get(url, headers=headers)
十二、实战小案例
import requests
url = 'https://www.baidu.com/s'
params = {'wd': '爬虫'}
response = requests.get(url, params=params)
# 保存结果
with open('result.html', 'w', encoding='utf-8') as f:
f.write(response.text)
下载图片示例:
import requests
url = 'https://httpbin.org/image/png'
# 获取二进制内容
response = requests.get(url)
# 写入文件
with open('image.png', 'wb') as f:
f.write(response.content)
十三、常见问题
1. 乱码
response.encoding = 'utf-8'
2. 403
需要添加 headers。
3. 参数无效
检查 params / data 是否正确。
4. 接口返回的不是想要的数据
需要检查:
- 请求方式是否正确(GET / POST)
- 参数位置是否正确(params / data / json)
- 是否缺少请求头
- 是否需要携带 Cookie
5. 请求超时
可以设置超时时间:
response = requests.get(url, timeout=10)
这样可以避免程序长时间卡住。
6. 请求不稳定(建议重试)
import requests
for i in range(3):
try:
response = requests.get(url, timeout=5)
response.raise_for_status()
break
except Exception as e:
print('重试中...', i)
十四、补充:登录、验证码与代理排查思路
实际使用 requests 时,很多问题不是 requests.get() 或 requests.post() 本身不会写,而是目标网站对登录态、验证码、频率、请求头做了限制。
1. 使用 Session 保持登录态
如果多个请求之间需要共享 Cookie,推荐使用 Session。
import requests
session = requests.Session()
headers = {
'User-Agent': 'Mozilla/5.0'
}
# 第一步:访问首页,让服务端下发初始 Cookie
session.get('https://example.com', headers=headers)
# 第二步:提交登录表单
data = {
'username': 'user',
'password': 'password'
}
session.post('https://example.com/login', headers=headers, data=data)
# 第三步:访问需要登录的页面
response = session.get('https://example.com/user', headers=headers)
print(response.text)
这里的重点不是账号密码,而是 session 会自动保存并携带 Cookie。
2. Cookie 登录的基本思路
如果登录流程比较复杂,也可以先从浏览器中复制 Cookie,再放到请求头中测试。
headers = {
'User-Agent': 'Mozilla/5.0',
'Cookie': 'sessionid=xxx; token=xxx'
}
response = requests.get('https://example.com/user', headers=headers)
不过这种方式只适合临时测试。正式代码中不要把真实 Cookie 写死到文件里,更不要提交到 Git。
3. 验证码处理流程
遇到验证码时,建议先判断验证码在业务流程中的位置。
常见情况有三种:
| 场景 | 处理思路 |
|---|---|
| 普通图片验证码 | 下载验证码图片,人工输入或调用识别服务 |
| 滑块验证码 | 通常需要浏览器环境,更适合 Selenium |
| 行为验证码 | 不建议强行绕过,应优先降低请求频率或使用人工流程 |
如果只是学习流程,可以把验证码处理拆成三步:
- 请求验证码图片。
- 保存到本地。
- 输入识别结果后再提交表单。
4. 代理是否生效的排查
配置代理后,建议先访问测试接口确认出口 IP。
import requests
proxies = {
'http': 'http://127.0.0.1:7890',
'https': 'http://127.0.0.1:7890'
}
response = requests.get(
'https://httpbin.org/ip',
proxies=proxies,
timeout=10
)
print(response.text)
如果这里都访问失败,就不要继续排查业务网站了,应该先确认代理地址、端口、协议是否正确。