PyInstaller打包exe

发布时间 2023-07-12 11:03:41作者: 宏图英雄

PyInstaller打包exe

一:安装

注:安装pyinstaller前,先安装几个Python模块 pypiwin32,pywin32 和 pefile 包
直接使用使用pip安装:
pip install pypiwin32
pip install pywin32
pip install pefile

安装PyInstaller
方法一:直接使用pip pip install pyinstaller
方法二:下载源码安装 下载页面:http://www.pyinstaller.org/downloads.html
该页面有安装方法和源码包下载 查看安装结果 pyinstaller -v 或 pyinstaller --version

二:打包exe 相关参数

pyinstaller 参数 test.py
-D (-onedir); 创建一个目录,包含exe文件,但会依赖很多文件(默认选项)。
-c (-console, –nowindowed); 使用控制台,无界面(默认)
-F (-onefile); 打包成一个exe文件
-w (-windowed, –noconsole); 使用窗口,无控制台
-F -i 图标名称.ico test.py; 可为exe文件生成图标。
-upx (--upx-dir UPX_DIR); 压缩生成的exe文件(使用后可能会提vcruntime140.dll错误或其它莫名奇妙的问题)
--add-data; 打包额外资源
--add-binary;打包额外的代码

-upx

  1. 下载upx:
    地址:http://upx.sourceforge.net/
  2. 把upx解压到要转换到的py文件目录下
  3. pyinstaller参数中添加upx路径
    pyinstaller -F test.py --upx-dir upx391w 注:upx391w 为upx文件夹

--add-data
pyinstaller -F test.py -add-data=src;dest windows以 ; 分割,linux以 : 分割
src 打包前资源文件路径或资源文件所在文件夹(相对test.py路径)
dest 打包后资源文件释放的文件夹(相对“临时文件夹”的路径,exe运行时会将所需的文件释放到Windows系统的临时文件夹中)
注:使用这个参数的功能也可用编辑.spec文件实现,可参考的“如何将资源文件一起打包至exe中”

--add-binary
和--add-data差不多。
与--add-data不同的是,用--add-binary添加的.py文件,pyinstaller会分析它引用的文件并把它们一同添加进来

简单示例
如:

注:在执行pyinstaller编译时,建议先手动删除编译生成的文件 pycache、build、dist、 test.spec 等相关文件
效果:

其它复杂用法只需参考上面 "相关参数" 使用说明 添加参数即可。

三:其它

3.1 打包多进程程序

我们需要在main方法里,第一行加入如下代码:

multiprocessing.freeze_support()
import multiprocessing
 
 if __name__ == '__main__':
    freeze_support() # main方法第一行必须先添加

3.2 如何将资源文件一起打包至exe中

要将资源文件打包进exe且正常调用资源文件进行使用,首先要知道2个知识点:

  1. pyinstaller打包后的exe是怎么工作的(简单理解)
  2. pyinstaller如何把资源文件打包进exe

1、打包后的exe是怎么工作的(简单理解)
打包后的exe运行时,会将脚本文件及一些所需要的文件释放到Windows的一个临时目录中。
如图:

如何在代码中获取到该临时目录的路径呢?程序可通过sys.MEIPASS访问临时目录中的资源
定义一个函数用于获取打包exe前后脚本所在路径:

获取资源文件所在路径(打包前和打包后路径是不一样的)

def resource_path(relative_path):
    if getattr(sys, 'frozen', False): # 是否Bundle Resource
        base_path = sys.MEIPASS
    else:
        base_path = os.path.abspath(".")
    return os.path.join(base_path, relative_path)

2、如何把资源文件打包进exe
有2种方法实现把资文件打包进exe,这2种方法其实都是一样,途径不同而已。
a. 使用打包命令参数 --add-data
b. 编辑.spec配置文件

a. 使用打包命令参数 --add-data
--add-data 打包额外资源
如:
pyinstaller -F test.py -add-data=src;dest windows以 ; 分割,linux以 : 分割
src 打包前资源文件路径或资源文件所在文件夹(相对test.py路径)
dest 打包后资源文件释放的文件夹(相对“临时文件夹”的路径,exe运行时会将所需的文件释放到Windows系统的临时文件夹中)
使用该参数打包,执行命令后,打开test.spec配置文件,你会发现在datas项的值是[('src', 'dest')],所以该参数简化了修改配置文件的步骤。
b. 编辑.spec配置文件
b.1 首先使用Pyinstaller -F test.py打包,生成配置文件
执行完后 删除build和dist文件夹,然后修改test.spec文件,如下图所示:

b.2 把要打包的资源文件添加到pyinstaller配置文件中“.spec”
编辑test.spec文件datas项,datas项中的元组功能参考如图:

编辑好后,对test.spec文件进行编译:
命令:pyinstaller -F test.spec
b.3 实现案例 构建一个简单程序: 如图:

test.py代码:
import os, sys

获取资源文件所在路径(打包前和打包后路径是不一样的)

def resource_path(relative_path):
    if getattr(sys, 'frozen', False): # 是否Bundle Resource
        base_path = sys._MEIPASS
    else:
        base_path = os.path.abspath(".")
    return os.path.join(base_path, relative_path)
 
binDir = resource_path('')
aPath = resource_path(r'bin\a.txt')
bPath = resource_path(r'bin\b.txt')
 
print(binDir)
print(aPath)
print(bPath)
input()

pyinstaller打包:
命令:pyinstaller -F test.py --add-data=bin;bin
运行效果:

3.3 替换tkinter左上角图标后,打包的exe执行失败

test.py 代码:
from tkinter import *
 
window = Tk()
window.title('测试')
window.iconbitmap('icon.ico')  # 加图标
window.mainloop()

打包exe前test.py正常运行,如图:

解决办法
网上方法有很多种,我这提供的方法是把icon.ico以资源文件的形式打包进exe文件中。
取得icon.ico打包后所在路径
打包后的exe,运行exe后会把相关的文件释放到系统的临时文件夹中,这时我们只要取得该临时文件夹的路径即可得到icon.ico。
把icon.ico打包进exe中
取得icon.ico打包后所在路径

基本原理:Pyinstaller 可以将资源文件一起bundle到exe中,当exe在运行时,会生成一个临时文件夹,程序可通过sys._MEIPASS访问临时文件夹中的资源

定义一个函数,以获取打包前打包后脚本所在路径。 代码:

获取资源文件所在路径(打包前和打包后路径是不一样的)

def resource_path(relative_path):
    if getattr(sys, 'frozen', False): # 是否Bundle Resource
        base_path = sys.MEIPASS
    else:
        base_path = os.path.abspath(".")
    return os.path.join(base_path, relative_path)

把icon.ico打包进exe中
命令:pyinstaller -F --add-data=icon.ico;. test.py . 表示.py脚本所在路径
--add-data 打包额外资源 如:
pyinstaller -F test.py -add-data=src;dest windows以 ; 分割,linux以 : 分割
src 打包前资源文件路径或资源文件所在文件夹(相对test.py路径)
dest 打包后资源文件释放的文件夹(相对“临时文件夹”的路径,exe运行时会将所需的文件释放到Windows系统的临时文件夹中)
注:使用这个参数的功能也可用编辑.spec文件实现,可参考的“如何将资源文件一起打包至exe中”

实现代码
test.py代码:

from tkinter import *
import os, sys
 
# 获取资源文件所在路径(打包前和打包后路径是不一样的)
def resource_path(relative_path):
    if getattr(sys, 'frozen', False): # 是否Bundle Resource
        base_path = sys._MEIPASS
    else:
        base_path = os.path.abspath(".")
    return os.path.join(base_path, relative_path)
 
iconPath = resource_path('icon.ico')
 
window = Tk()
window.title('测试')
window.iconbitmap(iconPath)  # 加图标
window.mainloop()

3.4 使用-w打包后,运行过程中还显示cmd窗口

解决办法:
代码中调用命令或程序的模块换成subprocess模块
subprocess模块目标是代替一些老的模块,比如os.system和os.spawn。
使用subprocess设置相应的参数即可。如:
subprocess.run(r'命令', shell=True, creationflags=0x08000000)
creationflags=0x08000000 隐藏cmd窗口