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
- 下载upx:
地址:http://upx.sourceforge.net/ - 把upx解压到要转换到的py文件目录下
- 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个知识点:
- pyinstaller打包后的exe是怎么工作的(简单理解)
- 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代码:
PyInstaller打包exe
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窗口