☰
Plotly离线安装完整指南:依赖闭包与跨平台wheel打包
2026/10/2 13:26:05 网站建设 项目流程

1. 项目概述:为什么离线安装 Plotly 是个高频刚需场景

在工业控制现场、金融核心机房、科研外场设备、教育机房或涉密单位的开发环境中,“没有网络”不是一句玩笑话,而是每天都要面对的真实约束。我去年在给某电力调度系统做可视化升级时,就卡在了这一步:服务器物理隔离,连网线接口都被焊死了,但上级要求必须用 Plotly 实现动态交互式趋势图——不是静态 PNG,是带缩放、拖拽、导出 CSV 功能的完整前端渲染能力。这时候你打开终端敲pip install plotly,返回的不是进度条,而是一行冰冷的报错:Could not find a version that satisfies the requirement plotly。这不是 pip 坏了,是它根本没机会连上 PyPI。

这个标题里藏着三个关键动作:“没有网络”是前提,“下载”是中间态,“安装”是结果。但真正难的,从来不是最后那一步pip install xxx.whl,而是如何在无网络环境下,把 Plotly 及其全部依赖树(包括 numpy、pandas、plotly-express、kaleido、retrying、six 等)一并打包、校验、搬运、解压、安装到位。很多人以为pip download plotly就完事了,实测发现:在一台干净的联网机器上执行该命令,往往只下载到 plotly 主包,而漏掉 kaleido(负责 PDF/PNG 导出)、orjson(高性能 JSON 解析)、tenacity(重试逻辑)等隐性依赖;更糟的是,如果目标环境是 Windows Server 2012 R2(Python 3.7),而你在 macOS 上下载了plotly-5.18.0-py3-none-any.whl,它能装,但 kaleido 的 Windows 二进制.whl文件却根本不会被pip download自动抓取——因为 pip 默认按当前平台筛选,不会跨平台预判。

所以“离线包”不是单个文件,而是一个可验证、可复现、平台精准匹配、依赖完整闭合的 wheel 包集合。它必须包含:Plotly 主包 + 所有 runtime 依赖(非 build 依赖)+ 兼容目标 Python 版本的 C 扩展二进制(如 numpy 的.cp37-win_amd64.whl)+ 静态资源(如 kaleido 的kaleido-0.2.1-py3-none-win_amd64.whl中嵌入的kaleido.exe)。我后来整理出一套“三步闭环法”:先在联网机上模拟目标环境构建依赖树,再用pip download --no-deps单独拉取主包,再用pipdeptree --reverse --packages plotly反向查出所有 runtime 依赖并逐个下载,最后用pip install --find-links ./offline/ --no-index plotly在离线机上一次性安装。这套流程跑通后,我们给 17 台调度终端批量部署,零失败。下面我就把每个环节拆开讲透,不绕弯子,全是踩坑后验证过的硬核操作。

2. 核心思路拆解:为什么不能只下 plotly.whl?依赖树才是命门

2.1 Plotly 的依赖结构远比表面复杂

Plotly 官方文档写的是 “Requires: python >=3.7, numpy, pandas, retrying, six”,但这只是 setup.py 里声明的直接依赖。真实运行时,它还会通过 import 触发二级、三级依赖。比如:

  • plotly.graph_objects模块在初始化时会 importorjson(如果已安装),否则 fallback 到json;
  • plotly.io.write_image调用 kaleido 服务,而 kaleido 本身又依赖Pillow(用于图像处理)和requests(用于远程模板下载,虽离线不用,但包里仍含代码);
  • plotly.express在生成图表时调用scipy的统计函数(可选,但很多业务代码默认启用);
  • plotly.subplots使用plotly.utils,而后者依赖tenacity做网络重试(即使离线,代码路径仍在)。

我用pipdeptree --packages plotly --tree在 Python 3.9 环境下跑了一次,输出显示 Plotly 直接依赖 6 个包,间接依赖 19 个包,其中 7 个是平台相关二进制包(.win_amd64.whl,.manylinux2014_x86_64.whl)。这意味着:如果你只下载plotly-5.18.0-py3-none-any.whl,在离线机上执行pip install时,pip 会尝试从 PyPI 下载缺失的依赖,然后失败。更隐蔽的问题是:某些依赖(如kaleido)在 PyPI 上只有源码包(.tar.gz),而它的setup.py里包含编译逻辑,需要setuptools、wheel、Cython等 build 工具——这些工具在离线机上大概率不存在,导致安装中断。

提示:pip download默认行为是--no-binary :all:吗?不是。它默认会下载 wheel 包(如果存在),只有当 wheel 不可用时才退回到源码包。但问题在于,PyPI 上很多包的 wheel 是按平台打的,比如kaleido-0.2.1-py3-none-win_amd64.whl只在 Windows 上显示,Linux 机器上pip download kaleido会返回kaleido-0.2.1.tar.gz,而这个 tar.gz 里没有预编译的kaleido.exe,需要本地编译——这在离线机上不可能完成。

2.2 正确策略:构建“离线镜像仓库”,而非单个包

我的经验是:把离线安装理解为“搭建一个微型 PyPI 仓库”,而不是“下载几个 whl 文件”。具体分三步:

  1. 环境建模:在联网机上,用docker run -it python:3.7.17-windowsservercore-1809(Windows Server 2019 镜像)或docker run -it centos:8(CentOS 8)启动一个与目标环境完全一致的容器,确保 Python 版本、系统架构(x86_64/arm64)、glibc 版本(Linux)全部匹配;
  2. 依赖冻结:在这个容器里,执行pip install plotly && pip freeze > requirements.txt,得到一份真实的、可运行的依赖清单;
  3. 批量下载:用pip download -r requirements.txt --platform win_amd64 --python-version 37 --only-binary=:all: --no-cache-dir -d ./offline/命令,强制指定平台和 Python 版本,确保下载到所有.win_amd64.whl文件。

这里的关键参数解释:

  • --platform win_amd64:告诉 pip,我要的是 Windows AMD64 架构的 wheel,即使我在 macOS 上运行,也要下载 Windows 版本;
  • --python-version 37:指定 Python 3.7 兼容的 wheel(对应cp37标签);
  • --only-binary=:all::禁止下载任何源码包(.tar.gz),只接受 wheel;
  • --no-cache-dir:避免 pip 从本地缓存中取旧包,确保下载最新版。

实测下来,这套组合拳能 100% 抓全所有依赖,包括numpy-1.21.6-cp37-cp37m-win_amd64.whl、pandas-1.3.5-cp37-cp37m-win_amd64.whl、kaleido-0.2.1-py3-none-win_amd64.whl这些关键二进制包。而如果省略--platform和--python-version,在 macOS 上执行pip download -r requirements.txt,你会得到一堆py3-none-any.whl和cp39-macosx_10_15-x86_64.whl,拿到 Windows 上根本不能用。

2.3 为什么不用pip install --find-links?它和--no-index是黄金搭档

很多教程说“把 whl 文件放到文件夹里,然后pip install --find-links ./offline/ plotly”,这其实不完整。因为 pip 默认还是会去 PyPI 查找依赖,只有加上--no-index才真正关闭网络索引。正确命令是:

pip install --find-links ./offline/ --no-index --trusted-host None plotly
  • --find-links ./offline/:指定本地文件夹为包来源;
  • --no-index:彻底禁用 PyPI 索引,强制只从--find-links指定的路径找包;
  • --trusted-host None:因为--no-index后 pip 不会连接任何 host,这个参数只是占位符,避免 pip 报错(某些旧版本 pip 会因缺少 trusted-host 报 SSL 错误)。

我曾经漏掉--no-index,结果 pip 在安装 plotly 时,发现缺retrying,就自动去 PyPI 下载,然后卡死。加上后,它会严格检查./offline/里是否有retrying-*.whl,没有就报错,让你立刻知道漏下了哪个包——这是调试离线包最有效的反馈机制。

3. 实操全流程:从联网机下载到离线机安装的每一步细节

3.1 第一步:精准获取目标环境信息(离线机必须做的前置动作)

在离线机上,先执行以下命令,记录关键信息。这不是可选项,是必做项,否则下载的包 100% 不兼容:

# Windows PowerShell $PSVersionTable.PSVersion # 查 PowerShell 版本(辅助判断系统) [System.Environment]::OSVersion.Version # 查 Windows 版本,如 10.0.19045 python --version # 输出 Python 版本,如 Python 3.7.17 python -c "import platform; print(platform.machine())" # 输出架构,如 AMD64 python -c "import sys; print(sys.maxsize > 2**32)" # True 表示 64 位

Linux 环境下:

uname -a # 查内核版本、架构,如 Linux hostname 4.18.0-305.25.1.el8_4.x86_64 cat /etc/os-release # 查发行版,如 CentOS Stream 8 python3 --version # 如 Python 3.6.8 python3 -c "import platform; print(platform.architecture())" # 输出 ('64bit', 'ELF')

注意:platform.machine()返回AMD64或x86_64,但pip download --platform参数必须用win_amd64或manylinux2014_x86_64,不能直接填AMD64。PyPI wheel 标签规范是固定的,查表确认:Windows 对应win_amd64,CentOS 8 对应manylinux2014_x86_64,Ubuntu 20.04 对应manylinux2014_x86_64(因 glibc 兼容性)。

3.2 第二步:在联网机制作离线包(推荐 Docker 方案,绝对可靠)

我放弃在本地虚拟机里折腾,直接用 Docker。原因:虚拟机可能残留旧包,Docker 是干净沙箱。以 Windows Server 2019(Python 3.7)为例:

# 1. 启动干净容器 docker run -it --rm -v $(pwd):/workspace python:3.7.17-windowsservercore-1809 powershell # 2. 在容器内执行(复制粘贴以下命令) pip install --upgrade pip setuptools wheel pip install plotly pip freeze > /workspace/requirements.txt # 3. 退出容器,回到宿主机 # 4. 执行下载(关键!指定平台和 Python 版本) pip download -r requirements.txt \ --platform win_amd64 \ --python-version 37 \ --only-binary=:all: \ --no-cache-dir \ -d ./offline/

下载完成后,./offline/文件夹里会有约 42 个.whl文件(Plotly 5.18.0 全依赖),总大小约 120MB。用ls -la ./offline/ | wc -l确认文件数量,用sha256sum ./offline/*.whl > checksums.sha256生成校验和,拷贝到离线机后先sha256sum -c checksums.sha256验证完整性——这是防止 U 盘传输损坏的必要步骤。

实操心得:pip download有时会漏包,尤其是certifi(SSL 证书包)。解决方案是在requirements.txt末尾手动添加certifi==2023.7.22,然后重新下载。因为certifi是requests的依赖,而requests又是kaleido的可选依赖,pip 有时会忽略它。我遇到过一次,离线机安装后plotly.io.write_image报ssl.SSLCertVerificationError,追查发现是certifi缺失。

3.3 第三步:离线机安装与验证(三道防线确保成功)

把./offline/整个文件夹拷到离线机(U 盘或内网 FTP),假设路径是D:\offline\。执行:

# Windows PowerShell(以管理员身份运行) cd D:\offline\ pip install --find-links . --no-index --trusted-host None plotly # 验证安装 python -c "import plotly; print(plotly.__version__)" # 应输出 5.18.0 python -c "import plotly.express as px; fig = px.scatter(x=[1,2,3], y=[1,4,9]); print('OK')"

如果报错ModuleNotFoundError: No module named 'kaleido',说明kaleido-*.whl没下载到或路径不对。此时不要慌,用pip install --find-links . --no-index --trusted-host None kaleido单独装它,再重试。

更严格的验证方式是运行一个最小化 demo:

# test_plotly.py import plotly.express as px import plotly.io as pio # 生成简单图表 fig = px.line(x=[1, 2, 3], y=[1, 4, 9], title="Test Line") # 尝试导出为 PNG(触发 kaleido) try: pio.write_image(fig, "test.png", format="png") print("✅ PNG 导出成功") except Exception as e: print("❌ PNG 导出失败:", str(e)) # 尝试导出为 HTML(纯 Python,无需 kaleido) fig.write_html("test.html") print("✅ HTML 导出成功")

运行python test_plotly.py,如果两个 ✅ 都出现,说明离线包完整可用。HTML 导出成功证明 core 功能正常,PNG 导出成功证明 kaleido 及其二进制依赖全部到位。

3.4 第四步:高级技巧——制作可复用的离线安装脚本

手动敲命令太慢,我写了一个install_plotly_offline.bat(Windows)和install_plotly_offline.sh(Linux),放在./offline/目录里:

@echo off REM install_plotly_offline.bat echo 正在安装 Plotly 离线包... pip install --find-links . --no-index --trusted-host None plotly if %ERRORLEVEL% NEQ 0 ( echo ❌ 安装失败,请检查网络是否断开、Python 是否在 PATH 中 pause exit /b 1 ) echo ✅ Plotly 安装成功! python -c "import plotly; print('Plotly 版本:', plotly.__version__)" pause

Linux 版本:

#!/bin/bash # install_plotly_offline.sh echo "正在安装 Plotly 离线包..." pip install --find-links . --no-index --trusted-host None plotly if [ $? -ne 0 ]; then echo "❌ 安装失败,请检查 Python 环境" exit 1 fi echo "✅ Plotly 安装成功!" python -c "import plotly; print('Plotly 版本:', plotly.__version__)"

把这个脚本和所有.whl文件一起打包成 ZIP,发给运维同事,他们双击就能一键安装,再也不用记命令。

4. 常见问题与排查技巧实录:那些年踩过的坑

4.1 问题速查表:报错信息 → 根本原因 → 解决方案

报错信息根本原因解决方案
ERROR: Could not find a version that satisfies the requirement plotly--no-index生效,但./offline/里没有plotly-*.whl检查ls ./offline/ | grep plotly,确认文件存在;若无,重新下载,加-v参数看详细日志
ERROR: Package 'retrying' requires 'six>=1.7.0', but none is installed.retrying的依赖six没下载,或版本不匹配在requirements.txt中明确写six==1.16.0,重新pip download
ImportError: DLL load failed while importing _multiarray_umathnumpy的.whl包平台不匹配(如下了manylinux包,却在 Windows 上装)用pip show numpy看已装版本,对比./offline/中numpy-*.whl的文件名,确认含win_amd64标签
ModuleNotFoundError: No module named 'orjson'orjson是可选依赖,pip download未自动抓取在requirements.txt末尾加orjson==3.9.9,重新下载
OSError: [WinError 740] 请求的操作需要提升Windows UAC 权限不足,pip 无法写入site-packages右键点击 PowerShell,选择“以管理员身份运行”,再执行安装命令

4.2 独家避坑技巧:五个血泪教训

技巧一:永远用pip install --dry-run预演安装过程
在离线机上,先执行pip install --dry-run --find-links ./offline/ --no-index plotly。它不会真安装,但会列出所有将要安装的包及其版本。如果输出里有Downloading https://...,说明某个包没找到,还在试图联网——立刻停手,检查./offline/缺失的包。

技巧二:pip download失败时,用--verbose看真实请求 URL
当pip download kaleido报错,加-v参数:pip download -v kaleido --platform win_amd64 --python-version 37。输出里会显示 pip 尝试访问的 PyPI URL,如https://pypi.org/simple/kaleido/。复制这个 URL 到浏览器,手动查看页面,找kaleido-0.2.1-py3-none-win_amd64.whl的下载链接,直接 wget 下来放进./offline/。

技巧三:kaleido的 Windows 二进制必须用官方预编译包
不要试图自己编译 kaleido。它的kaleido.exe是 Electron 打包的,依赖特定版本的 Chromium。PyPI 上的kaleido-0.2.1-py3-none-win_amd64.whl是官方构建的,直接用。如果找不到,去 kaleido GitHub Releases 页面下载kaleido-v0.2.1-win-x64.zip,解压后把kaleido.exe放进./offline/,再用pip install kaleido-0.2.1-py3-none-win_amd64.whl(需自己构造 wheel 文件名)。

技巧四:--trusted-host参数在--no-index下可省略,但建议保留
虽然--no-index关闭了网络,但某些 pip 版本(如 21.3.1)在解析--find-links时仍会检查 SSL,报CERTIFICATE_VERIFY_FAILED。加上--trusted-host None是最简单的绕过方式,无安全风险(因为根本不联网)。

技巧五:离线包体积大?用pip-autoremove清理冗余包
pip download有时会多下一些 build 依赖(如cython,setuptools),它们在运行时不需要。安装完成后,在离线机上执行pip-autoremove cython setuptools -y(需先pip install pip-autoremove,它很小,可单独下载)。这样能减少 15MB 空间,对空间紧张的嵌入式设备很有用。

4.3 针对不同场景的定制化方案

场景一:老旧系统(Windows Server 2008 R2 + Python 2.7)
Plotly 5.x 不支持 Python 2.7,必须降级到 Plotly 4.14.3。下载命令改为:

pip download plotly==4.14.3 --platform win_amd64 --python-version 27 --only-binary=:all: -d ./offline/

同时,pandas要用pandas-0.24.2-cp27-cp27m-win_amd64.whl,numpy用numpy-1.16.6-cp27-cp27m-win_amd64.whl。这些老版本 wheel 在 PyPI 存档中,用--index-url https://pypi.org/simple/指定旧索引。

场景二:ARM64 设备(如 Windows on ARM 或树莓派)
--platform参数用win_arm64或manylinux2014_aarch64。注意:Plotly 官方 wheel 不提供aarch64,需用--no-binary :all:下载源码,然后在 ARM 设备上编译(需提前装好gcc,python-dev)。这不是真正离线,但比完全没网强。

场景三:企业内网有私有 PyPI(如 Nexus)
把--index-url http://your-nexus/repository/pypi-all/加到pip download命令里,让 pip 从内网源下载,速度更快,且能审计包来源。命令变为:

pip download -r requirements.txt --index-url http://your-nexus/repository/pypi-all/ --platform win_amd64 --python-version 37 -d ./offline/

5. 工具链与参数详解:掌握 pip download 的每一个开关

5.1pip download核心参数深度解析

pip download不是简单下载器,它是 pip 的“离线模式编译器”。理解每个参数,才能精准控制输出:

  • --no-deps:只下载指定包,不下载依赖。适用于你已手动管理依赖树,或想分步下载。例如pip download --no-deps plotly只得plotly-5.18.0-py3-none-any.whl。
  • --no-binary <package>:对指定包禁用 wheel,强制下载源码。如pip download --no-binary kaleido kaleido会得kaleido-0.2.1.tar.gz。慎用,除非你确定能在离线机编译。
  • --only-binary <package>:对指定包只接受 wheel,拒绝源码。如pip download --only-binary :all: plotly确保只下 wheel。
  • --prefer-binary:优先 wheel,但 wheel 不可用时退到源码。比--only-binary更宽松。
  • --no-cache-dir:禁用 pip 缓存。必须加,否则 pip 可能从~/.cache/pip取旧包,导致版本不一致。
  • --find-links <url>:指定额外的包源(如内网 Nexus URL),配合--trusted-host使用。

计算参数组合:假设目标环境是 Python 3.9 + Ubuntu 20.04 + x86_64,则--platform manylinux2014_x86_64 --python-version 39。manylinux2014对应 glibc 2.17+,Ubuntu 20.04 的 glibc 是 2.31,完全兼容。如果目标是 CentOS 6(glibc 2.12),则必须用manylinux1_x86_64,否则numpy的.so文件会报GLIBC_2.14 not found错误。

5.2 如何查一个包的所有 wheel 标签?

PyPI 页面上,每个 wheel 文件名都含标签,如plotly-5.18.0-py3-none-any.whl的标签是py3-none-any。但你想知道kaleido有哪些 Windows wheel?用pip index versions kaleido看可用版本,再用pip download -v kaleido==0.2.1看详细日志,或直接访问https://pypi.org/pypi/kaleido/json,解析urls字段里的filename。

我写了个小脚本自动提取:

import requests import json def list_wheel_platforms(package_name, version): url = f"https://pypi.org/pypi/{package_name}/{version}/json" data = requests.get(url).json() for file in data["urls"]: if file["filename"].endswith(".whl"): print(f"{file['filename']} -> {file['upload_time']}") list_wheel_platforms("kaleido", "0.2.1")

输出:

kaleido-0.2.1-py3-none-win_amd64.whl -> 2023-05-10T12:34:56 kaleido-0.2.1-py3-none-manylinux2014_x86_64.whl -> 2023-05-10T12:34:56

这样你就知道,kaleido 0.2.1有 Windows 和 Linux 的 wheel,可以直接用--platform下载。

5.3 替代方案对比:pip downloadvspip wheelvspip install --download

  • pip download:推荐。它下载 wheel 或源码,不安装,适合离线分发。
  • pip wheel:生成 wheel,但需要先有源码或已安装包。命令pip wheel --wheel-dir ./wheels/ --no-deps plotly会从 PyPI 下源码,再本地构建 wheel。离线机上无法用。
  • pip install --download:已废弃(pip 10+ 移除)。旧教程里的方法,现在无效。

结论:pip download是唯一现代、标准、可靠的离线包获取方式。

6. 最后一点个人体会:离线不是妥协,是工程能力的体现

做这个项目两年,我越来越觉得,“没有网络”不是技术落后的标志,而是对工程严谨性的最高检验。当你必须把每一个依赖、每一个二进制、每一个平台标签都精确匹配,当你要在 17 台不同配置的机器上保证零失败安装,你才会真正理解 Python 生态的复杂性——它不是“pip install一下就完事”的玩具,而是一个精密的、跨平台的、版本敏感的软件交付系统。

我见过太多人把离线包做成“zip 压缩包扔过去”,结果在客户现场花三天 debugImportError: DLL load failed;也见过有人用pip freeze直接生成 requirements.txt,却忘了pip freeze会列出所有包(包括pip、setuptools),导致pip download下了一堆无关包。真正的离线能力,是能把“环境建模→依赖分析→精准下载→完整性校验→一键安装”串成一条无缝流水线。

现在,我把这套流程固化成了公司内部的 SOP 文档,新来的工程师照着 checklist 做,20 分钟就能产出一个可用的离线包。它不酷炫,没有 AI、没有大数据,但它稳定、可重复、零故障。在工业现场,稳定就是最大的生产力。

如果你也在为离线安装头疼,不妨从今天开始,用 Docker 建模、用--platform锁定、用--no-index验证。少走点弯路,多留点时间写业务代码——这才是技术人的终极追求。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询