python中pyinstaller的用法
PyInstaller 详细用法指南
PyInstaller 是一个强大的 Python 打包工具,可以将 Python 程序打包成独立的可执行文件。以下是详细的用法说明:
1. 安装和基本使用
安装 PyInstaller
pip install pyinstaller
基本打包命令
# 最简单的打包方式
pyinstaller your_script.py
# 打包为单个可执行文件
pyinstaller --onefile your_script.py
# 打包为单目录(多个文件)
pyinstaller --onedir your_script.py
2. 常用命令行选项
基本选项
| 选项 | 说明 |
|---|---|
--onefile |
打包成单个可执行文件 |
--onedir |
打包成目录(默认) |
--name NAME |
指定生成的可执行文件名称 |
--console |
显示控制台窗口(默认) |
--windowed |
不显示控制台窗口(GUI程序) |
--icon=ICON.ico |
设置程序图标 |
--version-file FILE |
设置版本信息文件 |
路径和文件选项
| 选项 | 说明 |
|---|---|
--distpath DIR |
指定输出目录 |
--workpath DIR |
指定临时文件目录 |
--specpath DIR |
指定 spec 文件目录 |
--add-data SRC;DEST |
添加数据文件 |
--add-binary SRC;DEST |
添加二进制文件 |
高级选项
| 选项 | 说明 |
|---|---|
--hidden-import MODULE |
添加隐藏导入的模块 |
--exclude-module MODULE |
排除模块 |
--key KEY |
加密 Python 字节码的密钥 |
--upx-dir DIR |
指定 UPX 压缩工具目录 |
--clean |
清理临时文件 |
--debug |
调试模式 |
3. 完整打包示例
基本 GUI 程序打包
pyinstaller --onefile --windowed --icon=app.ico --name "MyApp" main.py
包含数据文件的程序打包
pyinstaller --onefile --windowed \
--add-data "images;images" \
--add-data "config.ini;." \
--icon=app.ico \
main.py
复杂的控制台程序打包
pyinstaller --onefile --console \
--hidden-import pandas._libs.tslibs.timedeltas \
--hidden-import sklearn.utils._weight_vector \
--add-data "models;models" \
--name "DataProcessor" \
data_processor.py
4. 使用 Spec 文件
生成 spec 文件
pyinstaller --onefile main.py
编辑 spec 文件示例
# -*- mode: python ; coding: utf-8 -*-
block_cipher = None
a = Analysis(
['main.py'],
pathex=['D:\\MyProject'], # 添加项目路径
binaries=[],
datas=[
('config.ini', '.'), # 配置文件
('images/*.png', 'images'), # 图片资源
('templates/*.html', 'templates') # 模板文件
],
hiddenimports=[
'pandas._libs.tslibs.timedeltas',
'sklearn.utils._weight_vector',
'PyQt5.QtWebEngineWidgets'
],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=['tkinter', 'matplotlib'], # 排除不需要的模块
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False,
)
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
exe = EXE(
pyz,
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
[],
name='MyApplication',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True, # 启用 UPX 压缩
upx_exclude=[],
runtime_tmpdir=None,
console=False, # GUI 程序
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
icon='app.ico', # 程序图标
)
使用 spec 文件打包
pyinstaller main.spec
5. 处理常见问题
添加隐藏导入
pyinstaller --hidden-import pandas._libs.tslibs.timedeltas \
--hidden-import sklearn.utils._weight_vector \
main.py
处理动态导入
# 在代码中显式导入动态加载的模块
import importlib
# 显式导入可能动态加载的模块
import pandas._libs.tslibs.timedeltas
import sklearn.utils._weight_vector
处理数据文件
import sys
import os
def resource_path(relative_path):
"""获取资源的绝对路径"""
try:
# PyInstaller 创建临时文件夹,将路径存储在 _MEIPASS 中
base_path = sys._MEIPASS
except Exception:
base_path = os.path.abspath(".")
return os.path.join(base_path, relative_path)
# 使用示例
config_file = resource_path("config.ini")
image_file = resource_path("images/icon.png")
6. 平台特定选项
Windows 特定选项
# 添加版本信息
pyinstaller --version-file version.txt main.py
# 禁用 UAC 管理员权限请求
pyinstaller --uac-admin main.py
# 请求 UAC 管理员权限
pyinstaller --uac-admin main.py
版本信息文件示例 (version.txt)
VSVersionInfo(
ffi=FixedFileInfo(
filevers=(1, 0, 0, 0),
prodvers=(1, 0, 0, 0),
mask=0x3f,
flags=0x0,
OS=0x40004,
fileType=0x1,
subtype=0x0,
date=(0, 0)
),
kids=[
StringFileInfo([
StringTable(
u'040904B0',
[StringStruct(u'CompanyName', u'My Company'),
StringStruct(u'FileDescription', u'My Application'),
StringStruct(u'FileVersion', u'1.0.0.0'),
StringStruct(u'InternalName', u'MyApp'),
StringStruct(u'LegalCopyright', u'Copyright © 2024 My Company'),
StringStruct(u'OriginalFilename', u'MyApp.exe'),
StringStruct(u'ProductName', u'My Application'),
StringStruct(u'ProductVersion', u'1.0.0.0')])
]),
VarFileInfo([VarStruct(u'Translation', [1033, 1200])])
]
)
7. 高级配置
自定义钩子脚本
创建 hooks/hook-mymodule.py:
from PyInstaller.utils.hooks import collect_all
def hook(hook_api):
# 为 mymodule 收集所有依赖
packages = ['mymodule']
for package in packages:
datas, binaries, hiddenimports = collect_all(package)
hook_api.add_datas(datas)
hook_api.add_binaries(binaries)
hook_api.add_imports(*hiddenimports)
运行时钩子
创建 runtime-hooks/rthook.py:
import os
import sys
# 添加额外的路径
def add_extra_paths():
extra_paths = [
os.path.join(sys._MEIPASS, 'extra_libs'),
]
for path in extra_paths:
if path not in sys.path:
sys.path.insert(0, path)
add_extra_paths()
使用运行时钩子:
pyinstaller --runtime-hook=runtime-hooks/rthook.py main.py
8. 优化和调试
减小文件大小
# 安装 UPX 压缩工具
# 下载: https://upx.github.io/
# 使用 UPX 压缩
pyinstaller --onefile --upx-dir "C:\upx" main.py
# 排除不需要的模块
pyinstaller --exclude-module tkinter --exclude-module matplotlib main.py
调试模式
# 启用调试输出
pyinstaller --debug all main.py
# 或者使用 --log-level
pyinstaller --log-level=DEBUG main.py
分析导入
# 生成导入分析
pyinstaller --onefile --json main.json main.py
9. 完整打包脚本示例
Windows 批处理脚本
@echo off
echo Cleaning previous builds...
rmdir /s /q build
rmdir /s /q dist
echo Building application...
pyinstaller --onefile ^
--windowed ^
--name "MyPDFTool" ^
--icon=app.ico ^
--add-data "images;images" ^
--add-data "config.ini;." ^
--hidden-import PyPDF2 ^
--hidden-import PyQt5.QtCore ^
--hidden-import PyQt5.QtGui ^
--hidden-import PyQt5.QtWidgets ^
--clean ^
main.py
echo Build complete!
echo Output: dist\MyPDFTool.exe
pause
Python 构建脚本
# build.py
import os
import subprocess
import shutil
def build_app():
# 清理旧构建
if os.path.exists('build'):
shutil.rmtree('build')
if os.path.exists('dist'):
shutil.rmtree('dist')
# PyInstaller 命令
cmd = [
'pyinstaller',
'--onefile',
'--windowed',
'--name=PDF工具',
'--icon=app.ico',
'--add-data=images;images',
'--add-data=config.ini;.',
'--hidden-import=PyPDF2',
'--hidden-import=PyQt5.QtCore',
'--hidden-import=PyQt5.QtGui',
'--hidden-import=PyQt5.QtWidgets',
'--clean',
'main.py'
]
# 执行构建
subprocess.run(cmd)
print("构建完成!")
print("可执行文件位置: dist/PDF工具.exe")
if __name__ == '__main__':
build_app()
10. 常见问题解决
问题1:打包后程序无法运行
# 使用控制台模式查看错误
pyinstaller --console main.py
# 或者添加调试信息
import traceback
try:
# 你的代码
pass
except Exception as e:
with open('error.log', 'w') as f:
f.write(traceback.format_exc())
问题2:缺少依赖
# 在代码开头显式导入所有依赖
import sys
import os
# 显式导入可能被动态加载的模块
import pkg_resources
import importlib_metadata
# 确保所有子模块都被导入
from PyPDF2 import PdfReader, PdfWriter
from PyQt5 import QtCore, QtGui, QtWidgets
问题3:路径问题
import sys
import os
def get_resource_path(relative_path):
"""获取资源的正确路径"""
if hasattr(sys, '_MEIPASS'):
return os.path.join(sys._MEIPASS, relative_path)
return os.path.join(os.path.abspath("."), relative_path)
# 使用示例
config_path = get_resource_path('config.ini')
11. 最佳实践
- 使用虚拟环境:在干净的虚拟环境中打包
- 测试依赖:确保所有依赖都正确安装
- 逐步打包:先打包为目录,测试通过后再打包为单文件
- 版本控制:将 spec 文件加入版本控制
- 持续测试:在不同系统上测试打包结果
通过以上详细的用法说明,你应该能够熟练使用 PyInstaller 打包各种 Python 应用程序。
浙公网安备 33010602011771号