总结Pyinstaller打包的⾼级⽤法⼀、安装pyinstaller
PyInstaller是⼀个⽤来将Python程序打包成⼀个独⽴可执⾏⽂件的第三⽅包。
因是第三⽅包,所以需要安装⼀下:
pip install pyinstaller
或者升级到最新版本:
pip install --upgrade pyinstaller
或者安装开发者版本:
pip install github/pyinstaller/pyinstaller/archive/
当然了,也可以下载whl⽂件,然后pip install安装
更多可参考官⽹指引:
⼆、打包初体验
我们简单试下打包python代码为exe可执⾏⽂件,测试代码如下:
# 测试.py
import os
path = os.getcwd()
print(f'当前⽂件路径:{path}')
os.system('pause')
这段代码是打印⽂件所在的⽬录,我们⽤pyinstaller简单打包的命令如下:
pyinstaller -F 测试.py
这个命令,执⾏过程如下:
(env_test) F:\PythonCool\pyinstaller>pyinstaller -F 测试.py
403 INFO: PyInstaller: 4.3
403 INFO: Python: 3.8.10 (conda)
434 INFO: Platform: Windows-10-10.0.19042-SP0
436 INFO: wrote F:\PythonCool\pyinstaller\测试.spec
455 INFO: UPX is not available.
468 INFO: Extending PYTHONPATH with paths
['F:\\PythonCool\\pyinstaller', 'F:\\PythonCool\\pyinstaller']
501 INFO: checking Analysis
...
...
15006 INFO: Appending archive to EXE F:\PythonCool\pyinstaller\dist\测试.exe
18999 INFO: Building EXE completed successfully.
成功后会在同级⽬录下⽣成⼀个dist⽂件,⾥⾯就是⼀个和代码⽂件名同名的可执⾏⽂件:
双击该可执⾏⽂件,我们可以看到直接在python解释器⾥运⾏测试.py⽂件时⼀样的结果:
这⾥需要注意的是,我们在进⾏打包的时候,有必要指定被打包的py⽂件的路径,两种⽅式供选择:
⽅式⼀:先切换到被打包py⽂件⽬录,再执⾏打包指令
(base) C:\Users\Gdc>cd F:\PythonCool\pyinstaller
(base) C:\Users\Gdc>F:
(base) F:\PythonCool\pyinstaller>pyinstaller -F 测试.py
⽅式⼆:打包指令中指定py⽂件的绝对路径
(base) C:\Users\Gdc>pyinstaller -F F:\PythonCool\pyinstaller\测试.py
关于成功打包的测试.exe可执⾏⽂件,我们发现其图标是默认的,且启动时会显⽰命令⾏窗⼝。那么,我们可以怎么⾃定义exe图标,⼜或者去掉命令⾏窗⼝呢?
三、打包进阶体验
好了,接下来,我们先看看关于pyinstaller打包时候的⼀些别的参数都有哪些,如何⾃定义exe图标以及如何去掉命令⾏窗⼝等等。
(env_test) F:\PythonCool\pyinstaller>pyinstaller -h
pyinstaller -h可以查看其参数说明,由于较多这⾥不做完整展⽰,摘取部分常⽤参数做简要介绍:
参
说明
数
-F产⽣单个的可执⾏⽂件
-D产⽣⼀个⽬录(包含多个⽂件)作为可执⾏程序
-a不包含 Unicode 字符集⽀持
-d debug 版本的可执⾏⽂件
-w指定程序运⾏时不显⽰命令⾏窗⼝(仅对 Windows 有效)
-c指定使⽤命令⾏窗⼝运⾏程序(仅对 Windows 有效)
-o指定 spec ⽂件的⽣成⽬录。如果没有指定,则默认使⽤当前⽬录来⽣成 spec ⽂件
-
p设置 Python 导⼊模块的路径(和设置 PYTHONPATH 环境变量的作⽤相似)。也可使⽤路径分隔符(Windows 使⽤分号,Linux 使⽤冒号)来分隔
多个路径
-n指定项⽬(产⽣的 spec)名字。如果省略该选项,那么第⼀个脚本的主⽂件名将作为 spec 的名字
打包⼀个带⾃定义icon的exe可执⾏⽂件
我们可以去这⾥下载icon⽂件:
可以去这⾥将图⽚转化为icon⽂件:
然后,⽤⼀下命令可以⾃定义exe图标:
(env_test) F:\PythonCool\pyinstaller>pyinstaller -F -i icon.ico 测试.py
成功后,我们可以看到图标变成了我们⾃定义的这个:
打包去掉命令⾏弹窗的exe可执⾏⽂件
如果我们是有GUI的程序,想在启动的时候去掉命令⾏窗⼝,那么可以⽤以下指令进⾏打包,这⾥以tkinter内置GUI库为例展⽰:
# 测试.py
import tkinter
top = tkinter.Tk()
# 进⼊消息循环
top.mainloop()
以上测试代码,如果⽤初体验中的⽅式,在GUI界⾯出现的同时也会出现命令⾏弹窗,我们想去掉命令⾏弹窗可以:
(env_test) F:\PythonCool\pyinstaller>pyinstaller -F -w -i icon.ico 测试.py
双击打包后的exe⽂件,可以看到只会出现GUI界⾯,命令⾏窗⼝并没有出现。
四、带配置⽂件打包
所谓带配置⽂件打包,这⾥是指打包的时候除了py⽂件、依赖的库之外,还存在需要引⽤的其他资源⽂件。直接⽤以上⽅式打包的时候,这些资源是⽆法被打进包的,我们需要进⾏修改打包时的spec⽂件来实现。
spec⽂件是告诉Pyinstaller怎么打包py⽂件,⽐如路径、资源、动态库、隐式调⽤的模块等等。⼀般来说,我们不需要对它进⾏修改…
这⾥我⽤此前《词云绘制⼩⼯具》的案例来进⾏介绍。
我们直接⽤打包进阶体验中的命令可以进⾏成功打包,不过这⾥我们发现有两个问题:①包体很⼤,⽐此前案例⾥⼤了10倍左右;②启动exe⽂件的时候报错了。
关于包体较⼤的情况,可以试着创建虚拟环境,然后只安装程序⾥需要调⽤的库即可,这⾥只简单介绍:
# 创建虚拟环境
conda create -n your_env_name python=3.8.10
# 启动虚拟环境
activate your_env_name
关于启动报错的情况,由于⽐较复杂,我们⼀步⼀步来看:
①由于⽆命令⾏弹窗,⽆法查看到具体的报错,这⾥先去带命令⾏窗⼝形式看下报错信息,我们看报错如下:
提⽰缺少这个⽂件,我们可以在打包⽣成的词云绘制⼯具.spec配置⽂件⾥将这个资源放上
# -*- mode: python ; coding: utf-8 -*-
# 词云绘制⼯具.spec
block_cipher = None
a = Analysis(['词云绘制⼯具.py'],
pathex=['F:\\PythonCool\\pyinstaller'],
binaries=[],
datas=[], # 这⾥带上资源⽂件地址
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='词云绘制⼯具',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=True , icon='icon.ico')
通过在wordcloud模块⽬录⾥查到了stopwords⽂件,我们将其放到data中。
datas=[('C:\\Users\\Gdc\\anaconda3\\envs\\env_test\\Lib\\site-packages\\wordcloud\\stopwords','wordcloud')],
前者是资源⽂件在本机的位置,后者为打包后⽂件调⽤的相对路径,编辑好spec⽂件后,通过以下命令进⾏打包:
(env_test) F:\PythonCool\pyinstaller>pyinstaller -D 词云绘制⼯具.spec
好吧,还有⼀些⽂件未被打进包,所以⼜出现同样的问题了。所以,我们是需要把全部的资源⽂件都加到spec⽂件⾥的data中。我们到全部的资源⽂件全部加上吧,然后再执⾏打包命令。
datas=[('C:\\Users\\Gdc\\anaconda3\\envs\\env_test\\Lib\\site-packages\\stylecloud\\static','stylecloud\\static'),
('C:\\Users\\Gdc\\anaconda3\\envs\\env_test\\Lib\\site-packages\\wordcloud\\stopwords','wordcloud'),
('C:\\Users\\Gdc\\anaconda3\\envs\\env_test\\Lib\\site-packages\\jieba\\analyse\\','jieba\\analyse'),
('C:\\Users\\Gdc\\anaconda3\\envs\\env_test\\Lib\\site-packages\\jieba\\','jieba')]
我们将配置资源打进包后可以正常启动exe可执⾏⽂件了。
但是,⼜发现在执⾏词云绘制的时候,也会出现报错。不过看报错的情况是提⽰不存在xx模块,那么这是什么情况呢?!
五、添加隐式调⽤库
我们到报错的地⽅代码如下,采⽤了__import__()函数⽤于动态加载类和函数palettable模块。
def gen_palette(palette: str):
"""Generates the corresponding palette function from `palettable`."""
palette_split = palette.split(".")
palette_name = palette_split[-1]
字符串函数strip 的作用是什么# stackoverflow/a/6677505
palette_func = getattr(
__import__(
"palettable.{}".format(".".join(palette_split[:-1])),
fromlist=[palette_name],
),
palette_name,
)
return palette_func
对于这个问题,我试过两种⽅案,⼤家可以参考⼀下。
⽅案⼀:在spec⽂件中hiddenimports中添加动态引⽤的模块
hiddenimports=['palettable'], # 动态引⼊的库或模块
这种情况下,palettable库⾥也有⼀些配置⽂件需要添加到spec⽂件⾥的data中
('C:\\Users\\Gdc\\anaconda3\\envs\\env_test\\Lib\\site-packages\\palettable\\colorbrewer\\data','palettable\\colorbrewer\\data')
⽅案⼆:修改stylecloud库中调⽤palettable模块的代码部分
import palettable
def gen_palette(palette: str):
palette_func = getattr(palettable.tableau,'BlueRed_6')
return palette_func
# """Generates the corresponding palette function from `palettable`."""
# palette_split = palette.split(".")
# palette_name = palette_split[-1]
# stackoverflow/a/6677505
# palette_func = getattr(
# __import__(
# "palettable.{}".format(".".join(palette_split[:-1])),
# fromlist=[palette_name],
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论