1. 项目概述:Python+requests实现视频下载的核心逻辑
用Python下载网络视频是爬虫领域最经典的实战场景之一。不同于简单的文本抓取,视频下载需要处理流媒体协议、大文件分块传输、反爬机制等特殊问题。requests库作为Python生态中最主流的HTTP客户端工具,其简洁的API设计和强大的扩展能力,使其成为视频下载任务的理想选择。
我经手过的视频下载项目涉及B站、YouTube、抖音等20+平台,总结出requests方案的核心优势在于:
- 无需依赖浏览器环境,资源占用极低
- 可精细控制下载过程中的每个参数(如headers、代理、超时等)
- 支持断点续传和大文件分块下载
- 能绕过部分平台的防爬限制
典型应用场景包括:
- 批量下载教学视频建立本地资源库
- 采集竞品宣传视频进行数据分析
- 备份自媒体平台原创内容
- 构建视频处理管道的原料采集环节
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 环境准备与基础配置
2.1 开发环境搭建
推荐使用Python 3.8+版本,与requests库的兼容性最稳定。通过以下命令安装核心依赖:
bash复制pip install requests tqdm
其中tqdm用于显示下载进度条,是提升用户体验的关键组件。
验证安装是否成功:
python复制import requests
print(requests.__version__) # 应输出2.25.1以上版本
2.2 代理与请求头配置
视频网站通常会对高频请求实施封禁,建议在脚本开始处预设通用配置:
python复制HEADERS = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
'Referer': 'https://www.example.com/'
}
PROXIES = {
'http': 'http://your_proxy:port',
'https': 'http://your_proxy:port'
}
重要提示:不要直接复制这段User-Agent,建议从自己浏览器的开发者工具中获取实时可用的值
3. 核心下载逻辑实现
3.1 获取真实视频地址
视频网站通常不会直接暴露.mp4/.flv等地址,需要通过以下方式解析:
python复制def extract_video_url(page_url):
# 示例:B站视频地址解析逻辑
resp = requests.get(page_url, headers=HEADERS)
pattern = r'"baseUrl":"(https://.*?\.flv)"'
match = re.search(pattern, resp.text)
if match:
return match.group(1).replace('\\u002F', '/')
raise Exception("视频地址提取失败")
3.2 分块下载与进度显示
直接下载大视频文件可能导致内存溢出,应采用流式下载:
python复制def download_with_progress(video_url, save_path):
with requests.get(video_url, stream=True, headers=HEADERS) as r:
r.raise_for_status()
total_size = int(r.headers.get('content-length', 0))
with open(save_path, 'wb') as f, tqdm(
desc=save_path,
total=total_size,
unit='iB',
unit_scale=True
) as bar:
for chunk in r.iter_content(chunk_size=8192):
f.write(chunk)
bar.update(len(chunk))
关键参数说明:
chunk_size=8192:内存与下载速度的平衡点(值越小内存占用越低)stream=True:启用流式传输模式unit_scale=True:自动转换单位(KB/MB/GB)
4. 高级功能实现
4.1 断点续传实现
通过HTTP Range头实现中断后继续下载:
python复制def resume_download(video_url, save_path):
file_size = os.path.getsize(save_path) if os.path.exists(save_path) else 0
headers = HEADERS.copy()
headers['Range'] = f'bytes={file_size}-'
with requests.get(video_url, headers=headers, stream=True) as r:
with open(save_path, 'ab') as f, tqdm(
initial=file_size,
total=int(r.headers.get('content-length')) + file_size,
unit='iB',
unit_scale=True
) as bar:
for chunk in r.iter_content(chunk_size=8192):
f.write(chunk)
bar.update(len(chunk))
4.2 多线程加速下载
对支持分段的视频源,可采用多线程并行下载:
python复制from concurrent.futures import ThreadPoolExecutor
def download_segment(start, end, url, filename):
headers = HEADERS.copy()
headers['Range'] = f'bytes={start}-{end}'
with requests.get(url, headers=headers, stream=True) as r:
with open(f"{filename}.part{start}", 'wb') as f:
for chunk in r.iter_content(chunk_size=8192):
f.write(chunk)
def merge_files(parts, final_name):
with open(final_name, 'wb') as f:
for part in sorted(parts):
with open(part, 'rb') as p:
f.write(p.read())
os.remove(part)
5. 实战问题排查手册
5.1 常见错误代码处理
| 错误代码 | 可能原因 | 解决方案 |
|---|---|---|
| 403 Forbidden | 请求头缺失/被识别为爬虫 | 更新User-Agent,添加Referer |
| 404 Not Found | 视频地址过期 | 重新解析最新地址 |
| 206 Partial Content | 服务器不支持Range请求 | 改用普通下载模式 |
| 503 Service Unavailable | IP被封禁 | 更换代理IP,降低请求频率 |
5.2 性能优化技巧
- 连接池复用:创建Session对象重复使用
python复制session = requests.Session()
session.mount('https://', HTTPAdapter(pool_connections=10, pool_maxsize=100))
- 超时设置组合:
python复制timeout_config = (3.05, 27) # (连接超时, 读取超时)
- DNS缓存加速:
python复制import socket
socket.setdefaulttimeout(10) # 全局DNS查询超时
6. 完整实现案例
以下是一个可直接运行的B站视频下载脚本:
python复制import re
import os
from tqdm import tqdm
import requests
def get_bvid(url):
pattern = r'bvid=([^&]+)'
match = re.search(pattern, url)
return match.group(1) if match else url.split('/')[-1]
def get_play_info(bvid):
api_url = f'https://api.bilibili.com/x/player/playurl?bvid={bvid}&qn=80'
resp = requests.get(api_url, headers={
'User-Agent': 'Mozilla/5.0',
'Referer': 'https://www.bilibili.com/'
})
return resp.json()['data']['durl'][0]['url']
def download_video(url, save_path):
video_url = get_play_info(get_bvid(url))
with requests.get(video_url, stream=True, headers={
'User-Agent': 'Mozilla/5.0',
'Referer': 'https://www.bilibili.com/'
}) as r:
total_size = int(r.headers.get('content-length', 0))
with open(save_path, 'wb') as f, tqdm(
desc=save_path,
total=total_size,
unit='iB',
unit_scale=True
) as bar:
for chunk in r.iter_content(chunk_size=8192):
f.write(chunk)
bar.update(len(chunk))
if __name__ == '__main__':
download_video('https://www.bilibili.com/video/BV1uv411q7Mv', 'demo.mp4')
实测注意事项:B站接口需要携带正确的Referer和Cookie,新账号建议先手动在浏览器观看几个视频再运行脚本
