使用pyinstaller打包程序
1.pyinstaller的下载和安装
一般通过pip命令安装即可,命令如下
pip install pyinstaller
不过,有些程序的打包可能出错,可以安装开发版本,命令如下
pip install https://github.com/pyinstaller/pyinstaller/archive/develop.zip
2.命令参数说明
命令pyinstaller [options] ***.py
可选参数[options]
如下:
(1)-F
或--onefile
将程序打包成一个文件,即exe
文件。
优点:比较简洁,毕竟只有一个文件;当程序需要外部资源文件时,打包的资源文件的相对路径将会与打包前工程中的相对路径相同。
缺点:通过这种打包方式打包的exe
文件,打开时会花费较长的时间。原因是PyInstaller
是将程序所用到的所有外部资源文件,依赖库等压缩到这一个文件中,当运行这一文件时,需要将先前压缩的文件解压到临时文件夹中,耗费较多的时间。
(2)-D
或--onedir
将程序打包成一个文件夹,其中包括需要的外部资源文件,依赖库,以及exe
文件等。PyInstaller
默认把程序打包成文件夹。
优点:打开exe
文件的速度较快,且可以通过查看文件夹中的dll
文件检查缺少哪些依赖库。
缺点:不够简洁,文件夹中包含许多其他文件;外部资源文件的相对路径与打包前在工程中的相对路径有所不同。如果在程序中用到了相对路径访问资源文件,可能会由于找不到指定文件而造成程序运行失败。
(3)--distpath
将打包好的文件或文件夹放置在指定位置,默认为./dist
。可以通过--distpath=***
修改打包好的文件的放置位置。
(4)--workpath
将打包过程中的临时文件放置在指定位置,默认为./build
。可以通过--workpath=***
修改临时文件的放置位置。这部分临时文件中有一个warn*.txt
文件,其中列举了PyInstaller
未能找到的模块,可以通过这个文件检查丢失的依赖库。
(5)--specpath
将生成的spec
文件放置在指定位置,默认为和要打包的py
文件在同目录下。可以通过--specpath=***
修改spec
文件的放置位置。
(6)--name
或-n
指定打包后的exe
文件和文件夹名称,默认为和要打包的py
文件同名。可以通过--name=***
来修改名称。
(7)--icon
或-i
指定打包后的exe
文件的图标,默认为python自带的图标。可以通过--icon=***.ico
来修改图标,指定的文件必须是ico
文件。
(8)--add-data
添加外部资源文件,可以多次使用。通过--add-data=source;destination
添加资源文件,其中source
是资源文件(夹)的相对路径,destination
是该资源文件(夹)打包在程序中的相对路径,具体例子见实例。
(9)--add-binary
添加二进制文件,可以多次使用。可以用来添加PyInstaller
找不到的库文件。
(10)--windowed
适用于GUI
程序,即将程序以窗口的形式打包,隐藏控制台。
更多详细的参数介绍可以查看知乎作者王熊貓的文章。
3.实例
我使用的是win10
操作系统,anaconda
环境编写python
程序。
编写一个GUI
程序,实现修改窗体图标,展示一张图片的功能,test.py
代码如下:
# -*- coding: utf-8 -*-
import tkinter as tk # 导入Tkinter库
window = tk.Tk() # 创建窗体
window.title('Test') # 给窗体命名
window.geometry('500x350+500+100') # 设置窗体大小及位置
window.iconbitmap('icon.ico') # 设置窗体图标
img = tk.PhotoImage(file='images/qulv.gif')
lab = tk.Label(window, image=img)
lab.pack()
window.mainloop()
工程目录如图:
(1)打包成一个文件(即使用--onefile
)
当不需要外部资源文件时,通过如下命令即可:
pyinstaller --onefile --icon=icon.ico --windowed --name=ShowImage test.py
但是,当程序中需要外部资源文件时,这个命令虽然能够执行,但是运行exe
文件时,会出现下图中的问题(我这里截取的是我在其他工程中遇到的相同问题,截图中的Main
在上述实例中应该为test
):
出现这种情况的具体原因可能是程序找不到指定的外部资源文件或者是未找到程序中引用的依赖库等。
下面只讲将外部资源文件打包入程序中的过程:
- 如果将程序打包成一个文件,且程序中用到了相对路径访问外部文件,建议在程序中创建一个资源路径函数
resource_path(relative_path)
,代码如下:
# 资源路径函数
def resource_path(relative_path):
try:
base_path = sys._MEIPASS
except Exception:
base_path = os.path.abspath('.')
return os.path.join(base_path, relative_path)
然后在使用相对路径时,使用该函数对相对路径进行处理。例如:
img = tk.PhotoImage(file='images/qulv.gif')
应该改为
img = tk.PhotoImage(file=resource_path('images/qulv.gif'))
- 运行
cmd
进入test.py
所在目录,通过参数--add-data
来添加外部资源文件,命令如下:
pyinstaller --onefile --icon=icon.ico --windowed --name=ShowImage --add-data=images/qulv.gif;images/qulv.gif --add-data=icon.ico;. test.py
等待命令执行结束,在同目录下多出来了build
和dist
文件夹,以及ShowImage.spec
文件。打开dist
文件夹,即可得到打包后的exe
程序,图标为icon.ico
,名称为ShowImage
。
如果觉得上面的命令太长,也可以先生成spec
文件,通过修改spec
文件相关参数添加外部资源文件,步骤如下:
- 先通过如下命令生成
spec
文件。注意:设置程序图标,修改名称,设置是否隐藏控制台等需要在下面的命令中设置,否则通过spec
文件打包程序时,只有--upx-dir --distpath --nonconfirm --ascii
参数可用。当然,也可以修改spec
文件设置。
pyi-makespec --onefile --icon=icon.ico --windowed --name=ShowImage test.py
命令执行完毕后,同目录下出现了ShowImage.spec
文件。
- 使用
notepad++
或记事本打开spec
文件,对Analysis()
函数参数中的datas
进行修改。初始时datas
如下所示:
datas=[]
修改为
datas=[('images','images'),('icon.ico','.')]
意思是,将images
文件夹打包入程序根目录中,名称为images
,将icon.ico
文件打包入程序根目录中。
- 最后,执行如下命令:
pyinstaller ShowImage.spec
等待命令执行完毕,即可得到build
和dist
文件夹,打包的exe
文件在dist
文件夹中。
(2)打包成文件夹(即没有--onefile
参数)
如果将程序打包成文件夹,当程序中使用了相对路径访问外部资源文件,可以不用像打包成单个文件那样,需要在程序中添加一个资源路径函数resource_path(relative_path)
,直接使用命令,将资源文件放入文件夹中的指定位置。
以上面的程序为例,首先执行命令生成spec
文件:
pyi-makespec --windowed --icon=icon.ico --name=ShowImage test.py
然后修改spec
文件中的datas
,和上面修改spec
文件的过程一样。最后执行如下命令:
pyinstaller ShowImage.spec
即可生成bulid
和dist
文件夹。在dist
文件夹中有ShowImage
文件夹,即是打包后的文件夹,该文件夹中包括ShowImage.exe
文件,通过运行该文件执行程序。
注意:有时该exe
文件的图标可能没有更改,可以将打包后的文件夹复制到其他目录下,该图标可能会改变为指定图标。