pipreqs比pip freeze更适合项目导出,因为它仅扫描源码中显式import的包,精准生成真实依赖,避免混入开发工具、临时包及未使用依赖;但无法识别动态导入和隐式依赖,需人工补充。

pipreqs 为什么比 pip freeze 更适合项目导出?
因为 pip freeze 会把当前环境所有包都列出来,包括开发依赖、临时安装的工具,甚至你根本没用到的包;而 pipreqs 只扫描项目代码里的 import 语句,只提取真实被引用的包——这才是“精准”的来源。
但前提是:你的 import 必须是显式的、可静态分析的。比如 import requests 能识别,__import__('requests') 或字符串拼接导入就完全漏掉。
- 推荐在项目根目录执行,否则可能漏扫子目录或误扫无关文件
- 默认跳过
tests/、venv/、.git/等常见排除目录,但如果你有自定义测试目录(如test_utils/),得手动加--ignore - 如果项目用了相对导入(如
from .utils import helper),pipreqs不会解析模块路径去反推依赖,它只认绝对 import 和标准第三方包名
如何避免生成空 requirements.txt 或报错 ModuleNotFoundError?
常见现象是运行 pipreqs . 后输出 WARNING: No imports found,或者直接报 ModuleNotFoundError: No module named 'xxx' —— 这通常不是 pipreqs 的 bug,而是环境或代码结构问题。
- 确保当前 Python 环境已安装所有项目实际运行所需的包(哪怕只是临时装一下),否则
pipreqs在解析 import 时会因无法 resolve 模块而跳过整行 - 检查是否在虚拟环境中运行;如果在全局 Python 下执行,而项目又依赖某些仅在 venv 中安装的包,就会漏判
- 确认入口文件(如
app.py、main.py)被包含在扫描范围内;pipreqs默认从当前目录递归找 Python 文件,但如果入口被放在src/外或用非 .py 后缀(比如run脚本),就得用--encoding=utf-8 --savepath requirements.txt src/显式指定路径
requirements.txt 版本号怎么控制?要不要带 ==?
pipreqs 默认只写包名,不带版本号(即生成 requests 而非 requests==2.31.0),这是有意为之:它认为版本锁定应由你后续用 pip install -r requirements.txt + pip freeze > requirements.txt 配合完成,而非在首次生成时固化。
立即学习“Python免费学习笔记(深入)”;
- 如果想让 pipreqs 直接写出兼容版本(如
requests>=2.28.0),目前不支持;它只做存在性检测,不做版本推断 - 若需精确锁定,建议两步走:先
pipreqs . --savepath requirements.in(无版本),再用pip-compile requirements.in(来自 pip-tools)生成带版本的requirements.txt - 注意:
pipreqs --force会覆盖已有文件,但不会自动升级已有条目中的版本号——它只重生成,不 diff
遇到中文路径、特殊字符或编码错误怎么办?
Windows 下常见报错 UnicodeDecodeError: 'gbk' codec can't decode byte 0xXX,本质是 pipreqs 默认用系统编码读 Python 文件,而你的源码是 UTF-8 且含中文注释或字符串。
- 强制指定编码:运行
pipreqs . --encoding=utf-8 - 如果仍有文件打不开,可用
--skip-initial-comment跳过首行 shebang 或编码声明前的乱码内容(极少情况需要) - 不要试图用
chcp 65001切换 cmd 编码来治标——根源在 pipreqs 读文件方式,指定--encoding才是正解
真正麻烦的是动态导入和插件式架构:比如 Flask 的 app.register_blueprint() 或 Django 的 INSTALLED_APPS 列表,这些依赖无法被静态扫描捕获。pipreqs 做不到,也没打算做到——它只解决 import 层面的最小依赖集。这部分得靠你人工补全。


















