教程千千万,貌似我的window电脑就是打包不了,而且不同电脑的表现都不一致,很是奇怪。
文章目录
- 1 极简版
- 1.1 生成文件`spec`详解
- 1.2 是否变成一个exe主文件
- 2 虚拟环境打包
- 3 其他打包需求
- 3.1 加密打包
- 3.2 Pyinstaller打包多个py文件为一个exe文件
- 4 如何反编译
- 5 一些报错
- 5.1 utf-8' codec can't decode byte 0xce in position
- 5.2 exe文件要从dist文件拿出来
- 5.3 windows打包会将所有之前的依赖统统整上
- 5.4 pyinstaller的版本一定要保证最新
- 5.5 A RecursionError (maximum recursion depth exceeded) occurred
- 5.6 模块找不到的问题解决办法
官方地址:
https://github.com/pyinstaller/pyinstaller
官方文档:https://pyinstaller.org/en/stable/
python版本要求: Python version 3.8-3.12.
1 极简版
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple pyinstaller #清华源
然后
Pyinstaller -F py_word.py 打包exe
Pyinstaller -F -w py_word.py 不带控制台的打包
Pyinstaller -F -w -i chengzi.ico py_word.py 打包指定exe图标打包
这里的参数设定:
来看看生成的文件都是什么:
- 同名的
.spec
:重要配置文件,.spec文件
中主要包含4部分:Analysis、PYZ、EXE、COLLECT:- Analysis:主要是分析py文件的依赖信息
- PYZ:是一个.pyz的压缩包,包含程序运行需要的依赖
- EXE:是根据上述两项内容而生成的
- COLLECT:主要是输出信息
- dist文件夹:最终的exe文件存放位置,可能要从dist拿出来
- build文件夹:中间过程,创建好之后可以直接删除
1.1 生成文件spec
详解
参考:
https://blog.csdn.net/kevinshift/article/details/104880101
其实如果你自己会写
.spec
,可以直接通过pyinstaller xx.spec
来执行打包
# -*- mode: python ; coding: utf-8 -*-
a = Analysis(['gui.py'],
pathex=['D:\\gui'],
binaries=[],
datas=[('D:\\gui\\config.ini','.'),('D:\\gui\\清洗规则.xlsx','.')],
hiddenimports=['pandas'],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False)
datas里边的元素是以元组的形式来存储的,有这么一个映射关系:
datas = [('源文件路径','目标路径')]
如果有多个,就多放几个元素,内容不限,如果目标路径是打包后的根目录,那就写.
修改好之后,运行这条命令即可:
pyinstaller xx.spec
其中datas和binaries注意,这是一个键值对,可以枚举一个或多个。
其中,前边的表示拷贝的文件,第二个表示拷贝的路径。
#注意,必须有'.'。否则报错:ValueError: too many values to unpack (expected 2)
#下面这个表示将文件\lib\general.pyc拷贝到当前文件夹下,就是解压的__MIE...等
binaries=[(r'\lib\general.pyc','.')],
#下面表示将\lib\general.xml拷贝到.\data文件夹下
datas=[(r'\lib\general.xml',r'.\data')],
#还可以整个文件夹的拷贝,或者一类文件的拷贝。如下设置了多个规则的
datas= [ ('/mygame/sfx/*.mp3', 'sfx' ) , #/mygame/sfx/文件夹下所有mp3
( '/mygame/data', 'data' ), #/mygame/data文件夹下所有文件
( 'src/README.txt', '.' ),
],
上面说了有时候我们需要另外添加资源文件,可以通过编辑spec文件,也可以通过命令行参数。
例如使用opencv的时候存在找不到视频编解码器的情况(Pyinstaller详细教程)
即找不到opencv_ffmpeg341_64.dll
这时候需要我们手动设置资源路径,
可以通过–add-binary参数设置,也可以在spec文件添加binaries参数,这个参数是个list,每个元素是个二元组
binaries=[('D:\\ProgramSourceCode\\PycharmProjects\\video_proc\\venv\\Lib\\site-packages\\cv2\\opencv_ffmpeg341_64.dll', './cv2')]
前一个代表原始资源路径,后一个代表拷贝到可执行文件夹的文件路径。
1.2 是否变成一个exe主文件
来自:https://blog.csdn.net/kevinshift/article/details/104880101
# 打包成一个exe文件
Pyinstaller -F py_word.py 打包exe
# 打包成一个文件夹
Pyinstaller py_word.py 打包exe
pyinstaller打包文件包含两种情况:
(1)将py文件、python及第三方库全部打包为一个单独的Exe中。
(2)将以上三者打包形成一个文件夹,文件夹中包含一个Exe,一个python,及其依赖的第三方库。
二者通过不同的选项
二者的优劣对比:
(a)启动时间
单一可执行文件比文件夹的启动时间要长
因为当程序运行时,单一的可执行文件需要解压程序的第三方依赖文件到临时文件夹中。
(b)文件结构
单一可执行文件的文件结构和工程目录是一样的,但是生成文件夹就不一样了,若程序中包含相对路径,这个相对路径自然基于的是文件夹目录,这点需要注意。
在打包过程出现问题时,可以生成文件结构,进入细致查看发生了什么。
2 虚拟环境打包
按照极简版,其可能会将你所有依赖打包,就会让文件变得非常大。
可以使用conda的虚拟环境
#创建虚拟环境
conda create -n aotu python=3.6
#激活虚拟环境
conda activate aotu
# 安装必要的依赖
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple pandas
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple python-docx
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple pyinstaller
#Pyinstaller打包
Pyinstaller -F -w -i apple.ico py_word.py
安装完之后,可以在自己的虚拟镜像里面python x.py
试一下是否可以正常执行,就可以开始Pyinstaller
打包
3 其他打包需求
3.1 加密打包
加密打包
来自: https://zhuanlan.zhihu.com/p/470301078
虽然被如此轻松的解密手段😰到了,但是Pyinstaller也是支持加密打包的,使用 --key + 密码 参数即可,例如:
pyinstaller --key 666777 xxx.py
不过这个加密也不是很强,对保密性有很强要求的建议使用把需要加密的模块通过C或者C++编写,通过python调用,再打包。
3.2 Pyinstaller打包多个py文件为一个exe文件
来自:https://blog.csdn.net/weixin_43804047/article/details/119704965
建议将所有的非py脚本放在根目录下新建文件夹中去调用,所有的py脚本放在根目录下
project
|---- test.py
|---- func1.py
|---- func2.py
|---- dir
|------ file
# test.py为你要封装的文件,func1.py和func2.py为test.py需要调用的py脚本,dir中的文件为py脚本需要调用的非py类文件
你需要这样运行即可:
$ cd project
$ conda activate your_env
$ pyinstaller -w -D test.py func-1.py func-2.py
# 最新测试
# pyinstaller -w -D test.py 也可以
4 如何反编译
来自: https://zhuanlan.zhihu.com/p/470301078
先下载pyinstxtractor包,提取生成的exe中的pyz(一般是pyc)文件
# 安装:直接执行下载的 py 文件即可
# 解包 xx.exe
python pyinstxtractor.py xx.exe
然后再通过python-uncompyle6工具,将pyc文件反编成.py文件
# 安装
pip install uncompyle6
# 反编译 xxx.pyc 文件,输出为 xxx.py 源码文件
uncompyle6 -o xxx.py xxx.pyc
5 一些报错
5.1 utf-8’ codec can’t decode byte 0xce in position
来着:https://zhuanlan.zhihu.com/p/470301078
utf-8' codec can't decode byte 0xce in position
这是由于cmd的编码格式导致的。
各种路径错误导致的问题
很多人在拼接路径的时候喜欢使用+来拼接路径字符串,这会导致在打包后出现各种资源无法访问的错误,且不好排查,建议多使用os.path的各种方法来处理路径。
5.2 exe文件要从dist文件拿出来
被调用的脚本需要拷贝到dist中打包好的文件夹中,否则可能导致调用失败
project
|---- test.py
|---- func1.py
|---- func2.py
|---- dir
|------ file
input
比如你代码里是直接用./input
文件夹,那就要放在跟input
平级的文件夹上
5.3 windows打包会将所有之前的依赖统统整上
windows建议使用新建虚拟环境进行打包,新建的envs中只install你的python脚本中import的包即可,这样打包文件很小。笔者做了测试,使用你本来的虚拟环境会把原来的包都打在一块,有300M左右,而新建的envs打包只有50M;Linux系统可以随意安装python库,封装的时候会按照python导入的包去封装,不会将环境内所有package打包。
5.4 pyinstaller的版本一定要保证最新
pyinstaller的版本一定要保证最新,否则运行exe后,小黑框还是原样,什么也不显示,但是拖入cmd中debug是没毛病的。笔者就被这个坑了好久才弄明白。
5.5 A RecursionError (maximum recursion depth exceeded) occurred
Explanation: Python's stack-limit is a safety-belt against endless recursion,
eating up memory. PyInstaller imports modules recursively. If the structure
how modules are imported within your program is awkward, this leads to the
nesting being too deep and hitting Python's stack-limit.
With the default recursion limit (1000), the recursion error occurs at about
115 nested imported, with limit 2000 at about 240, with limit 5000 at about
660.
参考:使用pyinstaller打包pyqt5报With the default recursion limit (1000)
当支行过一次pyinstaller后此时运行过的目录下会有一个与要打包的.py文件同名的.spec文件
打开*.spec文件在文件头添加两行代码:
import sys
sys.setrecursionlimit(2000)
之后通过以下方式继续打包:
pyinstaller -D *.spec
5.6 模块找不到的问题解决办法
参考:使用pyinstaller将python程序打包成exe执行文件时遇到模块找不到的问题
解决办法是:打包时加入你自编模块(或第三方模块所在文件夹路径),笔者程序中调用了shiyanshi自编模块,在D:\Pycharm\Program路径下。
因此打包时需要添加路径进行打包。
使用pyinstaller ***.py -F -p D:\Pycharm\Program
命令在主程序所在文件目录下进行打包,即可解决模块找不到的问题。
参考:
Python脚本打包成exe,看这一篇就够了!