pyinstaller使用
- PyInstaller是一个跨平台的Python应用打包工具,支持 Windows/Linux/MacOS三大主流平台,能够把 Python 脚本及其所在的 Python 解释器打包成可执行文件,从而允许最终用户在无需安装 Python 的情况下执行应用程序。
- PyInstaller 制作出来的执行文件并不是跨平台的,如果需要为不同平台打包,就要在相应平台上运行PyInstaller进行打包。
- PyInstaller打包的流程:读取编写好的Python项目–>分析其中条用的模块和库,并收集其文件副本(包括Python的解释器)–>将副本和Python项目文件(放在一个文件夹//封装在一个可执行文件)中。
安装
1、安装pywin32==>pyinstaller依赖于
-
下载安装文件:查找到跟自己适用的python版本及window系统版本匹配的pywin32,下载后安装
-
使用pip命令安装:
pip install pywin32
、``
2、安装Pyinstaller
-
下载安装文件安装:官网
-
使用pip命令安装:
pip install PyInstaller
注:如果安装pyinstaller报错,可以按照pyinstaller安装失败的解决办法, 即pip install pywin32 wheel
, 再安装pip install pyinstaller
此外,使用Pycharm
直接搜索pyinstaller
会自动安装依赖库pywin32
使用
1、使用下载安装的方式安装的Pyinstaller打包方式
将需要打包的文件放在解压得到的Pyinstaller文件夹中,打开cmd窗口,把路径切换到当前路径打开命令提示行,输入以下内容(最后的是文件名)==>调用pyinstaller.py文件打包
:
python pyinstaller.py -F myfile.py
2、使用pip方式安装的Pyinstaller打包方式
打开cmd窗口,把路径切换到文件所在路径(文件随便放在哪里都行)打开命令提示行,输入以下内容(最后的是文件名):
pyinstaller -F myfile.py
使用实例
pyinstaller -F test.py -i src\logo.ico
参数说明:
- -F 表示生成单个可执行文件
- -w 表示去掉控制台窗口,这在GUI界面时非常有用。不过如果是命令行程序的话那就把这个选项删除吧!
- -p 表示你自己自定义需要加载的库路径,一般情况下用不到
- -i 表示可执行文件的图标
- -D: 生成文件夹形式的可执行程序(默认)
▲. -i
的参数为.ico
格式,其他格式的图片会报错。
注:除了直接通过CLI参数来生成,另一个比较好的方法是通过.spec
文件来定义:pyi-makespec -D main.py
(-D是让spec中多一个coll的实例,从而变成文件夹),更多spec文件参数选择见:https://blog.csdn.net/tangfreeze/article/details/112240342。-i
相当于.spec
中EXE中icon=".\\debugs\\favicon.ico"
(注:必须是绝对路径)
文件中使用了第三方库的打包方式
注: 一般入口文件,比如main.py中会遍历导入所有依赖的模块,从而扫描得到所有需要的三方库,Pyinstaller会自动把这些依赖到的三方库打包进exe,但是如果是动态导入的见hiddenimports即–hide-import,或者是还是无法导入的见pathex
在打包之前务必找到第三方库的包,把包复制到到跟myfile.py
同目录下,然后再使用以上2种方式打包,否则会打包失败或者即使打包成功,程序也会闪退。
pyqt5打包出现错误
一 、当写这篇文章的时候,pyinstaller官网版本对pyqt5打包可能会遇到Could not find QtWebEngineProcess.exe.
的错误。解决方法为:安装最新的pyinstaller
1.在github下载新版本的开发包。
2.打开解压后的文件夹,shift+鼠标右键,点击“在此处打开命令窗口”。之后依次运行如下命令:
1 | pip uninstall pyinstaller |
二 、如果有报错:“could not find or load the Qt platform plugin "windows" ”
。原因之一可能是你把打包后的文件放在了中文目录下。只需要将打包后的文件放在英文目录下,就可以解决。
多文件打包
1 | pyinstaller [主文件] -p [其他文件1] -p [其他文件2] |
1 | pyinstaller main.py -p mysql.py -p other.py --hidden-import mysql --hidden-import other |
打包配置、数据文件
-
pyinstaller -makespec main.py
创建main.spec
,spec的全称是specification
-
通过
.spec
配置文件中的datas
, 第一个参数为打包前的名称,第二个参数为打包进去的位置(如果不存在目录则会创建)修改说明:Each tuple has two values, both of which must be strings:
- The first string specifies the file or files as they are in this system now
- The second specifies the name of the folder to contain the files at run-time
1 | a = Analysis(['main.py'], |
- 然后使用
.spec
文件来打包:pyinstaller main.spec
使用--add-data "src;dest"
参数 ,比如pyinstaller.exe test.py --add-data "yes.txt;./"
就会在exe同级目录下创建yes.txt
文件,更多详情见:https://blog.csdn.net/u012219045/article/details/114841287
注:上述的只有在创建文件夹exe时有效,-F
生成单个时并不会创建add_data资源
Adding Data Files
You can add data files to the bundle by using the --add-data
command option, or by adding them as a list to the spec file.
When using the spec file, provide a list that describes the files as the value of the datas=
argument to Analysis
. The list of data files is a list of tuples. Each tuple has two values, both of which must be strings:
- The first string specifies the file or files as they are in this system now.
- The second specifies the name of the folder to contain the files at run-time.
For example, to add a single README file to the top level of a one-folder app, you could modify the spec file as follows:
1 | a = Analysis(... |
And the command line equivalent (see What To Bundle, Where To Search for platform-specific details):
1 | pyinstaller --add-data 'src/README.txt:.' myscript.py |
You have made the datas=
argument a one-item list. The item is a tuple in which the first string says the existing file is src/README.txt
. That file will be looked up (relative to the location of the spec file) and copied into the top level of the bundled app.
The strings may use either /
or \
as the path separator character. You can specify input files using “glob” abbreviations. For example to include all the .mp3
files from a certain folder:
1 | a = Analysis(... |
All the .mp3
files in the folder /mygame/sfx
will be copied into a folder named sfx
in the bundled app.
The spec file is more readable if you create the list of added files in a separate statement:
1 | added_files = [ |
You can also include the entire contents of a folder:
1 | added_files = [ |
The folder /mygame/data
will be reproduced under the name data
in the bundle.
附录
打包后日志文件位置不正确->打包时__file__
的使用问题
其实有生成log文件,但是不是在exe文件所在的文件夹内。
path = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'log', self.loggerName)
问题在这一句代码。
os.path.dirname(__file__)
返回的是当前脚本的所在路径,使用pycharm和直接点击运行py文件,这个路径均为脚本的所在路径,而生成exe之后点击运行,这个路径变为exe释放路径C:Users...AppDataLocalTemp_MEI***
,所以log文件生成在这个路径下,在结束运行后,这个路径文件夹会被删除。
最后改这句代码为,目前无法
1 | if getattr(sys, 'frozen', False): |
由于上述问题主要出现在打包成单个exe文件的情况下,并且打包test.py成test.exe后可以直接手动将yes.txt
放在test.exe同级目录中,这也是能读取到的(现象)。因此上述问题发生的主要原因是exe运行涉及解压程序的过程、加上对__file__
的理解不深,所以比较棘手
1 | # test.py |
为了赶时间,可以使用不打包成单个exe,而是文件夹的形式,这样就不涉及程序解压了,而是跟运行python脚本类似,因此__file__
不会出问题。
如pyinstaller.exe main.py -i debugs/f.ico --add-data="user_config.ini;." --add-data="push_config.ini;."
生成exe文件夹,代码中继续使用USER_DIR_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), "users")
,就能正确运行了
动态导入模块
有些脚本中,我们使用了__import__
等一些动态导入库的函数时,pyinstaller打包是无法找到这些模块的,在使用时就会报"ImportError 找不到指定模块",这个时候就需要手动导入动态加载的模块。
更多参数介绍见:https://blog.csdn.net/tangfreeze/article/details/112240342
使用pyinstaller打包时引入自己编写的库
https://blog.csdn.net/weixin_42134325/article/details/119384047
- 通过-p参数:
-p F:\projects\python
- 通过spec中: pathex指定
Spec文件
使用命令pyinstaller 选项 name.spec
, 从规范文件构建时,只有以下命令行选项有效:
- –upx-dir=:要用到一个压缩程序UPX,用于压缩文件,需要单独下载。
- –noconfirm:表示不再询问,会自动覆盖上次打包的内容
- –key= :加密,需要安装tinyaes第三方库,最多16位字符
- –distpath=
- –workpath=
- –ascii
- –clean
1 | # -*- mode: python ; coding: utf-8 -*- |
Author: Mrli
Link: https://nymrli.top/2018/12/03/Pyinstaller使用/
Copyright: All articles in this blog are licensed under CC BY-NC-SA 3.0 unless stating additionally.