• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录

SOC/IP验证工程师

  • 博客园
  • 联系
  • 订阅
  • 管理

公告

View Post

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. 最佳实践

  1. 使用虚拟环境:在干净的虚拟环境中打包
  2. 测试依赖:确保所有依赖都正确安装
  3. 逐步打包:先打包为目录,测试通过后再打包为单文件
  4. 版本控制:将 spec 文件加入版本控制
  5. 持续测试:在不同系统上测试打包结果

通过以上详细的用法说明,你应该能够熟练使用 PyInstaller 打包各种 Python 应用程序。

posted on 2025-10-06 10:38  SOC验证工程师  阅读(35)  评论(0)    收藏  举报

刷新页面返回顶部
 
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3