离线环境用 pip 安装本地 whl 包,关键在于把依赖收集和版本解析提前到有网机器上完成,目标机只做纯本地安装:pip install --no-index --find-links=<本地目录> <包名>。--no-index 让 pip 不去访问任何远程索引,--find-links 指向你拷贝进去的 wheel 目录,安装过程就不会因为网络超时或索引不可达而失败。这条命令能成功的前提是 wheel 的文件名标签与目标机的 Python 版本、操作系统、CPU 架构匹配;不匹配时 pip 通常直接报找不到可用的发行版,安装阶段无法补救。
离线装 whl 的正确顺序是先在联网机器上用pip download把主包和全部依赖下载成 wheel,再拷贝到目标机,用--no-index --find-links指到本地目录安装。判断能否成功,要看 wheel 文件名里的 Python 标签(如 cp311)和平台标签(如 manylinux、win_amd64)是否与目标机一致,以及依赖是否下载完整。带 C 扩展的包、仅有源码包的依赖、pip 自身过旧,是常见的三个失败点。
先确认当前场景和目标
动手前需要把几件事核对清楚,否则后面的命令会白跑。第一,目标机是完全断网,还是只是无法访问公网索引但能访问内网源;这两种情况的处理方式不同,前者必须用 --no-index,后者可以先用 --index-url 试内网源。第二,目标机的 Python 版本和解释器路径,包括是否在虚拟环境里,用 python -V 和 python -c "import sys;print(sys.executable)" 确认,联网机器上下载 wheel 时要用同版本 Python,否则标签容易对不上。第三,目标机是否已有可用的 pip 和 setuptools;有些精简镜像里只装了 Python 没装 pip,这种情况得先解决 pip 本身。
第四,要安装的是单个包还是整份依赖清单。单个包可以手工下载依赖,清单则建议用 requirements.txt 一次性下载、一次性安装,避免逐个排查传递依赖。第五,安装位置是系统 site-packages、用户目录还是指定的 target 目录,这决定后面要不要加 --user 或 --target,也决定权限问题怎么处理。
按这个顺序处理
第一步在联网机器上收集 wheel。目录建议固定为 wheelhouse,命令和参数按你的实际文件名替换:
# 联网机器,Python 版本与目标机保持一致
python -m pip download -d ./wheelhouse -r requirements.txt --only-binary=:all:
--only-binary=:all: 的作用是只下载 wheel、不下源码包,能提前暴露「某个依赖没有可用 wheel」这个问题。如果某个包只有源码包,这条命令会失败,此时需要去掉该参数单独确认,或者放弃该包换用其他方案。
第二步把整个 wheelhouse 目录通过介质拷贝到目标机,注意不要改文件名,wheel 的平台标签和版本信息全靠文件名承载。第三步在目标机上核对兼容标签,可以先执行 python -m pip debug --verbose 看当前解释器支持的标签列表,再对照 wheel 文件名。
第四步安装。单个包直接指定文件名或包名加版本:
python -m pip install --no-index --find-links=/data/wheelhouse "requests==2.31.0"
批量安装则用清单,顺序交给 pip 解析:
python -m pip install --no-index --find-links=/data/wheelhouse -r requirements.txt
没有 root 权限时加 --user;需要装到独立目录供多个解释器共用时用 --target,并记得把该目录加入 PYTHONPATH:
python -m pip install --no-index --find-links=/data/wheelhouse --user ./wheelhouse/xxx-1.0.0-py3-none-any.whl
如果报错说 pip 版本过低、无法识别某个 wheel 的元数据,先离线升级 pip 本身,前提是 wheelhouse 里已经下载了 pip 的 wheel:
python -m pip install --no-index --find-links=/data/wheelhouse --upgrade pip
pip 和 setuptools、wheel 建议放在安装顺序的最前面,它们是后续构建和安装的基础。

改完后怎么验证
安装命令返回成功后不要直接结束,至少做三件事。一是确认包的版本和安装路径,确认它落在了你预期的解释器下:
python -m pip show requests
python -c "import requests; print(requests.__version__, requests.__file__)"
预期信号是版本号与你指定的版本一致,__file__ 路径位于预期的 site-packages 或 target 目录内。如果路径指向了另一个解释器的目录,说明装错了环境。
二是检查依赖是否完整、有无版本冲突,pip check 是本地执行的,不需要网络:
python -m pip check
预期信号是输出没有缺失依赖或版本不满足的提示。出现提示时,通常说明 wheelhouse 里缺少某个依赖或依赖版本不对,需要回到联网机器补下载。
三是跑一次最小可用的导入或调用,尤其是带 C 扩展的包,import 能过基本说明二进制兼容没问题。命令行工具类的包还要确认入口脚本是否生成在 PATH 覆盖的目录里。
容易忽略的边界
平台标签不能跨系统通用。文件名里带 win_amd64 的 wheel 装不到 Linux 上,manylinux 的 wheel 也未必能在 musl 环境使用;只有 py3-none-any 这类纯 Python 包才是跨平台的。CPU 架构同理,ARM 机器需要单独的 wheel。
--no-index 会让 pip 完全放弃索引,任何漏带的依赖都会表现为「找不到可用的发行版」。这不是命令写错,而是依赖没有带全,需要回联网机器补齐,不要把 --no-index 去掉当临时方案,离线环境去掉它只会变成超时。
只有源码包(sdist)的依赖在离线环境里通常需要本地编译工具链,缺编译器时装不上,建议优先寻找 wheel 版本,或者把该包换掉。pip 版本过旧对较新的 wheel 元数据支持不足,也会导致装不上,需要先离线升级 pip。
如果确实找不到匹配的 wheel,回退思路有两条:一是把整个虚拟环境连同解释器一起打包搬到同系统的目标机,注意绝对路径和 C 扩展的差异;二是改用 --target 把依赖装到一个目录里整体拷贝,运行时通过 PYTHONPATH 引入。这两条都要结合目标机的系统版本和架构确认后再用。