学爬虫不学Requests,就像学做菜不学用刀——切不动,撕不烂,只能干瞪眼。
一、为什么Requests是Python爬虫的第一课?
在Python的HTTP请求库中,Requests是一个绕不开的名字。它被开发者誉为“HTTP for Humans”——为人类设计的HTTP库 。相比Python自带的urllib,Requests的API设计极其简洁,几行代码就能完成复杂的请求操作 。
Requests的优势速览
| 代码简洁度 | ⭐⭐⭐⭐⭐ | ⭐⭐ |
| 会话管理 | 自动处理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?
假设你要模拟用户操作:
如果每次都用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的核心优势
| 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限制,避免被封 |
最后几点建议
Requests库就像爬虫世界的一把瑞士军刀——简单、实用、功能强大。掌握它,你的爬虫之路就成功了一半!

