Mrli
别装作很努力,
因为结局不会陪你演戏。
Contacts:
QQ博客园

Pyinstaller使用

2022/05/01 Python
Word count: 2,542 | Reading time: 11min

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
2
3
pip uninstall pyinstaller
python setup.py build
python setup.py install

二 、如果有报错:“could not find or load the Qt platform plugin "windows" ”。原因之一可能是你把打包后的文件放在了中文目录下。只需要将打包后的文件放在英文目录下,就可以解决。

多文件打包

1
2
3
4
pyinstaller [主文件] -p [其他文件1] -p [其他文件2] 
--hidden-import [自建模块1]
--hidden-import [自建模块2]
# 以上为一整条命令
1
pyinstaller main.py -p mysql.py -p other.py --hidden-import mysql --hidden-import other

打包配置、数据文件

  1. pyinstaller -makespec main.py创建main.spec,spec的全称是specification

  2. 通过.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
2
3
4
a = Analysis(['main.py'],
pathex=['F:\\aDevelopment\\Python\\pythonGitProject\\feiyu_shoot'],
binaries=[],
datas=[("datas", "user_data"), ("xxx", "yyy")],
  1. 然后使用.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
2
3
4
a = Analysis(...
datas=[ ('src/README.txt', '.') ],
...
)

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
2
3
4
a = Analysis(...
datas= [ ('/mygame/sfx/*.mp3', 'sfx' ) ],
...
)

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
2
3
4
5
6
7
8
added_files = [
( 'src/README.txt', '.' ),
( '/mygame/sfx/*.mp3', 'sfx' )
]
a = Analysis(...
datas = added_files,
...
)

You can also include the entire contents of a folder:

1
2
3
4
5
added_files = [
( 'src/README.txt', '.' ),
( '/mygame/data', 'data' ),
( '/mygame/sfx/*.mp3', 'sfx' )
]

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
2
3
4
if getattr(sys, 'frozen', False):
pathname = sys._MEIPASS
else:
pathname = os.path.split(os.path.realpath(__file__))[0]

由于上述问题主要出现在打包成单个exe文件的情况下,并且打包test.py成test.exe后可以直接手动将yes.txt放在test.exe同级目录中,这也是能读取到的(现象)。因此上述问题发生的主要原因是exe运行涉及解压程序的过程、加上对__file__的理解不深,所以比较棘手

1
2
3
# test.py
with open("yes.txt", "r") as f:
print(f.read())

为了赶时间,可以使用不打包成单个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

  1. 通过-p参数:-p F:\projects\python
  2. 通过spec中: pathex指定

Spec文件

使用命令pyinstaller 选项 name.spec, 从规范文件构建时,只有以下命令行选项有效:

  • –upx-dir=:要用到一个压缩程序UPX,用于压缩文件,需要单独下载。
  • –noconfirm:表示不再询问,会自动覆盖上次打包的内容
  • –key= :加密,需要安装tinyaes第三方库,最多16位字符
  • –distpath=
  • –workpath=
  • –ascii
  • –clean
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# -*- mode: python ; coding: utf-8 -*-

block_cipher = None # 此处在使用--key= 会有变化


a = Analysis(['ai\\main.py'],
pathex=['C:\\Users\\Admin\\Downloads\\marsai-master'],
binaries=[],
datas=[],# 此处可以添加静态资源,例如你有个图片文件夹imgs,可以这样写[('imgs','imgs'),('test.txt','.')],打包以后会有一个一样的文件夹,点表示当前文件夹。
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,
[],
exclude_binaries=True,
name='main', # 生成的exe的名字
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True, # 打包的时候进行压缩,False表示不压缩
console=True # 是否显示黑窗口,刚开始打包的时候一般都会有问题,建议设为True,解决所有问题后可以设置为False)
coll = COLLECT(exe,
a.binaries,
a.zipfiles,
a.datas,
strip=False,
upx=True,
upx_exclude=[],
name='main' # 文件夹的名字)

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.

< PreviousPost
HTML和CSS学习
NextPost >
pyqt5与QT5
CATALOG
  1. 1. pyinstaller使用
    1. 1.1. 安装
      1. 1.1.1. 1、安装pywin32==>pyinstaller依赖于
      2. 1.1.2. 2、安装Pyinstaller
    2. 1.2. 使用
      1. 1.2.1. 1、使用下载安装的方式安装的Pyinstaller打包方式
      2. 1.2.2. 2、使用pip方式安装的Pyinstaller打包方式
      3. 1.2.3. 使用实例
    3. 1.3. 文件中使用了第三方库的打包方式
    4. 1.4. pyqt5打包出现错误
    5. 1.5. 多文件打包
  2. 2. 打包配置、数据文件
    1. 2.1. Adding Data Files
  • 附录
    1. 1. 打包后日志文件位置不正确->打包时__file__的使用问题
    2. 2. 动态导入模块
    3. 3. 使用pyinstaller打包时引入自己编写的库
    4. 4. Spec文件