在日常开发工程中,难免会需要将自己的code转化到另一台机器上运行,这时候你可能涉及到需要将python编写的脚本编译成一个系统可执行文件,这时候就需要借助pyinstall来实现。pyinstaller支持在多个系统平台将Python脚本打包成可执行程序,在没有Python环境的机器上运行。
同时还支持experimentally Solaris and AIX系统,以及python2.7-3.x,下面就该库的使用进行简单的总结。
(1)安装
由于是第三方库,可以直接通过pip来进行安装,
官方网站:http://www.pyinstaller.rg 或者国内镜像 Links for pyinstaller
第三方库:使用前需要额外安装
安装第三方库需要用到pip工具
pip install pyinstaller -i https://pypi.douban.com/simple
(2)使用
利用pyinstall来实现对python文件打包,支持的文件类型有
babel |
OK |
Fully supported, including "localedata" external data files (automatically handled). |
chardet、cx_oracle |
OK |
|
ctypes |
OK |
Features/CtypesDependencySupport in PyInstaller 1.4+ |
Django |
OK |
Preliminar support, see Recipe/DjangoApplication for howto |
docutils |
OK |
development branch |
ElementTree、FileLike、gadfly、Greenlet |
OK |
|
idlelib |
OK |
development branch |
IPython |
OK |
development branch |
Matplotlib |
OK |
Fully supported, including external data files (automatically packaged by PyInstaller). |
numpy、paste、PIL、pysycopg2、lxml、mako 、pygame、pygments、pyodbc |
OK |
|
pyenchant |
OK |
Windows only for now. |
PyGTK+ |
OK |
see #14 for how to include themes |
PyOpenGL2.X、PyOpenGL 3.x |
OK |
Works correctly since 3.0 rc1 |
PyQT3、PyQt 4、PyQT5 |
OK |
Full support, including plugins (they are automatically handled by PyInstaller). Open bug reports: #159, #363, #374, #376. See also wiki:Recipe/PyQtChangeApiVersion. Seedeploy pyqt app on Mac with pyinstaller. |
Python for .NET |
OK |
Reported to work correctly in 2.0. |
pytz |
OK |
development branch |
pywin32、pywinauto、pywintypes、pyserial |
OK |
|
SciPy |
OK |
development branch |
setuptools、SIP |
OK |
|
sphinx |
OK |
development branch |
SQLAlchemy |
OK |
|
wxPython |
OK |
Remember to use windowed mode to get correct theming. |
常见的配置参数如下,
-h,--help | 查看该模块的帮助信息 |
---|---|
-F,-onefile | 产生单个的可执行文件 |
-D,--onedir | 产生一个目录(包含多个文件)作为可执行程序 |
-a,--ascii | 不包含 Unicode 字符集支持 |
-d,--debug | 产生 debug 版本的可执行文件 |
-w,--windowed,--noconsolc | 指定程序运行时不显示命令行窗口(仅对 Windows 有效) |
-c,--nowindowed,--console | 指定使用命令行窗口运行程序(仅对 Windows 有效,可以关闭生成的dos窗口) |
-o DIR,--out=DIR | 指定 spec 文件的生成目录。如果没有指定,则默认使用当前目录来生成 spec 文件 |
-p DIR,--path=DIR | 设置 Python 导入模块的路径(和设置 PYTHONPATH 环境变量的作用相似)。也可使用路径分隔符(Windows 使用分号,Linux 使用冒号)来分隔多个路径 |
-n NAME,--name=NAME | 指定项目(产生的 spec)名字。如果省略该选项,那么第一个脚本的主文件名将作为 spec 的名字 |
-i --icon | 指定图标 |
故,使用pyinstaller生成可执行文件的方法
pyinstaller -D -w main.py #把main.py替换成你的主入口python文件即可。
-w参数代表main.py是一个窗体程序。
pyinstaller -F -w main.py
同时调查pyinstaller生成程序的加载过程,可以使用如下命令,得到运行时的跟踪,tracing ,loader 的加载过程。
pyinstaller -Fwd aui.py #把aui.py 换成你需要侦测的文件即可。
日常使用中,多为第二种打包方式,具体的指令操作如下,
pyinstaller -F -w -i app.ico app.py
补:如果想给软件添加自己喜欢的图标,这里推荐以下方式
https://www.iconfont.cn/ ####免费的在线icon图标网站
http://www.favicon-icon-generator.com/ ###免费在线生成1
http://www.ico51.cn/ ####免费在线生成2
(3)实战
case1:编写一个简单的录制摄像头的软件(单个文件)
》编码
from cv2 import cv2
from datetime import datetime
import os
# 详解cv2.VideoWriter_fourcc对象(摘自Learning OpenCV3 Computer Vision with Python,坦白讲不太懂)
# fourcc意为四字符代码(Four-Character Codes),顾名思义,该编码由四个字符组成,下面是VideoWriter_fourcc对象一些常用的参数,注意:字符顺序不能弄混
# cv2.VideoWriter_fourcc('I', '4', '2', '0'),该参数是YUV编码类型,文件名后缀为.avi
# cv2.VideoWriter_fourcc('P', 'I', 'M', 'I'),该参数是MPEG-1编码类型,文件名后缀为.avi
# cv2.VideoWriter_fourcc('X', 'V', 'I', 'D'),该参数是MPEG-4编码类型,文件名后缀为.avi
# cv2.VideoWriter_fourcc('T', 'H', 'E', 'O'),该参数是Ogg Vorbis,文件名后缀为.ogv
#捕获摄像头帧
save_file_path=str(datetime.now().date())
if not os.path.exists(save_file_path):
os.makedirs(save_file_path)
cameraCapture = cv2.VideoCapture(0)
size=(int(cameraCapture.get(cv2.CAP_PROP_FRAME_WIDTH)),int(cameraCapture.get(cv2.CAP_PROP_FRAME_HEIGHT)))
videoWriter=cv2.VideoWriter(os.path.join(save_file_path,'output.avi'),cv2.VideoWriter_fourcc('X', 'V', 'I', 'D'),30,size)
try:
success,frame = cameraCapture.read()
while success:
cv2.imshow("cap",frame)
videoWriter.write(frame)
success,frame=cameraCapture.read()
if cv2.waitKey(10) & 0xFF == ord('q'):
cameraCapture.release()
videoWriter.release()
cv2.destroyAllWindows()
sys.exit()
except:
print("cannot find camera")
》打包
pyinstaller -F -w save_video.py
如果成功,则会在当前目录下生成两个文件夹(bulid、dist)和一个文件save_video.spec,而在dist文件夹下就是生成的可执行文件。
case2:多文件打包
在日常编码过程中,使用单一文件进行项目处理的情况不多,为了低耦合,高内聚,通常会将不同的功能放在不同的函数或文件中,再通过彼此调用来实现,而通常打包这种项目时会存在两种方式,
1)方式一
通过命令行的方式来实现多文件依赖打包
pyinstaller [主文件] -p [其他文件1] -p [其他文件2]
--hidden-import [自建模块1]
--hidden-import [自建模块2]
示例为
pyinstaller -F start_menu.py -p check_default_speedup.py -p check_server_os.py -p check_speedup.py
2)方式二
可以先通过只对主文件进行编译打包生成spec文件,然后再对spec文件进行修改再编译打包即可。详细的步骤如下,一个spec文件常见内容包括如下,
变量 | 含义 |
---|---|
a | Analysis类的实例,要求传入各种脚本用于分析程序的导入和依赖。a中内容主要包括以下四部分:scripts,即可以在命令行中输入的Python脚本;pure,程序代码文件中的纯Python模块,包括程序的代码文件本身;binaries,程序代码文件中需要的非Python模块,包括–add-binary参数指定的内容;datas,非二进制文件,包括–add-data参数指定的内容。 |
pyz | PYZ的实例,是一个.pyz文件,包含了所有pure中的所有Python模块。 |
exe | EXE类的实例,这个类是用来处理Analysis和PYZ的结果的,也是用来生成最后的exe可执行程序。 |
coll | COLLECT类的实例,用于创建输出目录。在-F模式下,是没有COLLECT实例的,并且所有的脚本、模块和二进制文件都包含在了最终生成的exe文件中。 |
block_cipher | 加密密钥 |
以上内容中 修改比较多的是a、exe的内容,coll和pyz基本没有遇到需要修改的情况。
参数 | 含义 |
---|---|
Analysis参数scripts | 也是第一个参数,它是一个脚本列表,可以传入多个py脚本,效果与命令行中指定多py文件相同,即py文件不止一个时,比如“pyinstaller xxx1.py xxx2.py”,pyinstaller会依次分析并执行,并把第一个py名称作为spec和dist文件下的文件夹和程序的名称 |
Analysis参数pathex | 默认有一个spec的目录,当我们的一些模块不在这个路径下,记得把用到的模块的路径添加到这个list变量里。同命令“-p DIR/–paths DIR”. |
Analysis参数datas | 作用是将本地文件打包时拷贝到目标路径下。datas是一个元素为元组的列表,每个元组有两个元素,都必须是字符串类型,元组的第一个元素为数据文件或文件夹,元组的第二个元素为运行时这些文件或文件夹的位置。例如:datas=[(’./src/a.txt’, ‘./dst’)],表示打包时将"./src/a.txt"文件添加(copy)到相对于exe目录下的dst目录中。也可以使用通配符:datas= [ (’/mygame/sfx/*.mp3’, ‘sfx’ ) ],表示将/mygame/sfx/目录下的所有.mp3文件都copy到sfx文件夹中。也可以添加整个文件夹:datas= [ (’/mygame/data’, ‘data’ ) ],表示将/mygame/data文件夹下所有的文件都copy到data文件夹下。同命令“–add-data”。 |
Analysis参数binaries | 添加二进制文件,也是一个列表,定义方式与datas参数一样。没具体使用过。同命令“–add-binary”。 |
Analysis参数hiddenimports | 指定脚本中需要隐式导入的模块,比如在__import__、imp.find_module()、exec、eval等语句中导入的模块,这些模块PyInstaller是找不到的,需要手动指定导入,这个选项可以使用多次。同命令“–hidden-import MODULENAME/–hiddenimport MODULENAME”。 |
Analysis参数hookspath | 指定额外hook文件(可以是py文件)的查找路径,这些文件的作用是在PyInstaller运行时改变一些Python或者其他库原有的函数或者变量的执行逻辑(并不会改变这些库本身的代码),以便能顺利的打包完成,这个选项可以使用多次。同命令“–additional-hooks-dir HOOKSPATH”。 |
Analysis参数runtime_hooks | 指定自定义的运行时hook文件路径(可以是py文件),在打好包的exe程序中,在运行这个exe程序时,指定的hook文件会在所有代码和模块之前运行,包括main文件,以满足一些运行环境的特殊要求,这个选项可以使用多次。同命令“–runtime-hook RUNTIME_HOOKS”。 |
Analysis参数excludes | 指定可以被忽略的可选的模块或包,因为某些模块只是PyInstaller根据自身的逻辑去查找的,这些模块对于exe程序本身并没有用到,但是在日志中还是会提示“module not found”,这种日志可以不用管,或者使用这个参数选项来指定不用导入,这个选项可以使用多次。同命令“–exclude-module EXCLUDES”。 |
exe参数console | 设置是否显示命令行窗口,同命令-w/-c。 |
exe参数icon | 设置程序图标,默认spec是没有的,需要手动添加,参数值就是图片路径的字符串。同命令“命令-i/–icon”。 |
具体操作步骤,
pyinstaller -F -w start_menu.py
利用记事本或者notepad++打开spec文件,然后在对其进行针对性修改
# -*- mode: python ; coding: utf-8 -*-
block_cipher = None
a = Analysis(['start_menu.py','check_default_speedup.py', 'check_server_os.py', 'check_speedup.py'],#此项目中所有的python脚本 pathex=[ 'D:\\Project\\python\\xxxTool'],#项目绝对路径
binaries=[],
datas=[],#此列表存放所有的资源文件,每个文件是一个二元组元素 #add_files = [ ('fonts\\font.ttf', 'fonts'), ('images\\*.png', 'images'), ('images\\flappy.ico', 'images'), ('audios\\*.wav', 'audios'), ]
hiddenimports=[],
hookspath=[],
runtime_hooks=[],
excludes=[],
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='start_menu', #打包程序的名字
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=True )# 此处console=True表示,打包后的可执行文件双击运行时屏幕会出现一个cmd窗口,不影响原程序运行# 如果想要修改程序图标,使用在EXE()中加入 icon='xxxxx', 切记:绝对路径
如果想添加的附件:图片、声音、文档、数据等添加进去则需要在datas进行添加修改,
格式为: datas=[("5170.mp3","."),("5823.mp3","."),("6795.mp3","."),("bao.mp3","."),("baoza.mp3","."),("diji1.png","."),("ditu.jpg","."),("h1feiji.png","."),("hongfeiji.png","."),("l1feiji.png","."),("ss.MP3","."),("zfeiji.png","."),("zidan.png","."),("simsun.ttc",".")],
后面的"." 意识是当前路径下。
并保存修改。
在该路径下重新编译spec文件,指令如下
pyinstaller -F start_menu.spec
运行结束后,会新增 dist 文件夹,在该文件夹下,有打包好的程序 start_menu.exe,至此,打包结束。但是这种方式打包处理起来,往往文件都比较大,而且运行起来比较慢,这是由于python属于解释型语言,天生的比c,c++这些编译型语言要慢一些,但是如果想使压缩文件小一些是不是就没办法了呢?当然不是,可以尝试创建一个属于该项目的虚拟环境,在该环境下安装项目所需文件,最后再编译生成exe文件,这样会使结果小很多,偷偷告诉你,在虚拟环境下安装pyinstaller后再打包压缩会更小,如果对虚拟环境怎么构建不熟悉,可以查看这篇博客《深度学习之虚拟环境的配置》。最近又发现了一种新的方法,可以通过修改spec文件来加载文件需要的的动态库等,然后再借助UPX下载地址来实现文件压缩打包。利用upx命令压缩exe。下载对应版本的upx工具包解压到任意目录下,执行命令
pyinstaller -F test.spec --upx upx路径
(4)碰到的问题
有时候当你打包显示成功,但执行exe文件时显示执行错误,错误命令又一闪而过,这时候最快速定位错误的方法就是利用pyinstall -F 重新打包一次,但是选择显示命令窗口,为了避免一闪而过,在cmd下进入到dist文件下,然后运行exe文件,这时候会持久显示错误,根据错误类型进行处理。一般显示缺少xx.dll文件,这里有两种方式可以进行修正,
方法1. 使用 --add-data
pyinstaller -F -w xx.py --add-data xx.dll;.
方法2. 修改spec文件内data的值
# 先生成xx.spec文件
pyinstaller -F xx.py
# 修改.spec文件, 在datas内添加(资源文件, pathex的相对路径)
datas=[('xx.dll', '.')]
# 生成exe
pyinstaller -F -w xx.spec
常见的还有打包好的程序运行后出现No such file or directory,但是文件啥的都有,解决这样的错误,最常见的做法有两种,
1、最简单的就是将跟相关的文件放到dist目录下(生成的exe在dist目录下,并且要使用exe时,要挪动一整个dist目录),执行就OK了。
2、打开.spec文件,在datas里面添加文件的路径即可。
(5)可视化操作
如果不习惯在终端下进行打包操作,可以借助auto-py-to-exe进行可视化打包,其底层原理还是pyinstaller,打包具体操作如下,
在打开的界面主要配置的有,
》主脚本位置,就是打包py文件的位置
》打包格式,是形成一个打包文件夹还是只需要一个打包好的exe文件。
》控制台窗口,设置需不需要显示黑窗口。
》图标,给打包程序加上ico
》附加文件,一般添加主py文件所依赖的所有模块路径
配置完成之后点击 CONVERT .PY TO .EXE 按钮,即可以得到一个打包好的可执行程序。
好了,关于这个pyinstlaaer的使用总结先记录到这吧!
参考链接:
1、python生成exe文件运行闪退解决方法
2、python3.7将代码打包成exe程序并添加图标
3、Pyinstaller打包附带DLL、图标和压缩EXE方法
4、Pyinstaller的Spec文件用法