前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >PyInstaller打包python程序为exe可执行文件

PyInstaller打包python程序为exe可执行文件

作者头像
悟乙己
发布2023-11-26 09:40:42
6890
发布2023-11-26 09:40:42
举报
文章被收录于专栏:素质云笔记素质云笔记

教程千千万,貌似我的window电脑就是打包不了,而且不同电脑的表现都不一致,很是奇怪。

1 极简版

代码语言:javascript
复制
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple pyinstaller #清华源

然后

代码语言:javascript
复制
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来执行打包

代码语言:javascript
复制
# -*- 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里边的元素是以元组的形式来存储的,有这么一个映射关系:

代码语言:javascript
复制
datas = [('源文件路径','目标路径')]

如果有多个,就多放几个元素,内容不限,如果目标路径是打包后的根目录,那就写. 修改好之后,运行这条命令即可:

代码语言:javascript
复制
pyinstaller  xx.spec

其中datas和binaries注意,这是一个键值对,可以枚举一个或多个。 其中,前边的表示拷贝的文件,第二个表示拷贝的路径。

代码语言:javascript
复制
#注意,必须有'.'。否则报错: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,每个元素是个二元组

代码语言:javascript
复制
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

代码语言:javascript
复制
# 打包成一个exe文件
Pyinstaller -F py_word.py 打包exe
# 打包成一个文件夹
Pyinstaller py_word.py 打包exe

pyinstaller打包文件包含两种情况: (1)将py文件、python及第三方库全部打包为一个单独的Exe中。

(2)将以上三者打包形成一个文件夹,文件夹中包含一个Exe,一个python,及其依赖的第三方库。 二者通过不同的选项 二者的优劣对比: (a)启动时间 单一可执行文件比文件夹的启动时间要长 因为当程序运行时,单一的可执行文件需要解压程序的第三方依赖文件到临时文件夹中。 (b)文件结构 单一可执行文件的文件结构和工程目录是一样的,但是生成文件夹就不一样了,若程序中包含相对路径,这个相对路径自然基于的是文件夹目录,这点需要注意。 在打包过程出现问题时,可以生成文件结构,进入细致查看发生了什么。

2 虚拟环境打包

按照极简版,其可能会将你所有依赖打包,就会让文件变得非常大。 可以使用conda的虚拟环境

代码语言:javascript
复制
#创建虚拟环境
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 + 密码 参数即可,例如:

代码语言:javascript
复制
pyinstaller --key 666777 xxx.py

不过这个加密也不是很强,对保密性有很强要求的建议使用把需要加密的模块通过C或者C++编写,通过python调用,再打包。

3.2 Pyinstaller打包多个py文件为一个exe文件

来自:https://blog.csdn.net/weixin_43804047/article/details/119704965

建议将所有的非py脚本放在根目录下新建文件夹中去调用,所有的py脚本放在根目录下

代码语言:javascript
复制
project
|---- test.py
|---- func1.py
|---- func2.py
|---- dir
       |------ file
       
# test.py为你要封装的文件,func1.py和func2.py为test.py需要调用的py脚本,dir中的文件为py脚本需要调用的非py类文件

你需要这样运行即可:

代码语言:javascript
复制
$ 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)文件

代码语言:javascript
复制
# 安装:直接执行下载的 py 文件即可
# 解包 xx.exe
python pyinstxtractor.py xx.exe

然后再通过python-uncompyle6工具,将pyc文件反编成.py文件

代码语言:javascript
复制
# 安装 
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

代码语言:javascript
复制
utf-8' codec can't decode byte 0xce in position

这是由于cmd的编码格式导致的。 各种路径错误导致的问题 很多人在拼接路径的时候喜欢使用+来拼接路径字符串,这会导致在打包后出现各种资源无法访问的错误,且不好排查,建议多使用os.path的各种方法来处理路径。

5.2 exe文件要从dist文件拿出来

被调用的脚本需要拷贝到dist中打包好的文件夹中,否则可能导致调用失败

代码语言:javascript
复制
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

代码语言:javascript
复制
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文件在文件头添加两行代码:

代码语言:javascript
复制
import sys
sys.setrecursionlimit(2000)

之后通过以下方式继续打包:

代码语言:javascript
复制
pyinstaller -D *.spec

5.6 模块找不到的问题解决办法

参考:使用pyinstaller将python程序打包成exe执行文件时遇到模块找不到的问题

在这里插入图片描述
在这里插入图片描述

解决办法是:打包时加入你自编模块(或第三方模块所在文件夹路径),笔者程序中调用了shiyanshi自编模块,在D:\Pycharm\Program路径下。

因此打包时需要添加路径进行打包。

使用pyinstaller ***.py -F -p D:\Pycharm\Program 命令在主程序所在文件目录下进行打包,即可解决模块找不到的问题。

在这里插入图片描述
在这里插入图片描述

参考: Python脚本打包成exe,看这一篇就够了!

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2023-11-25,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 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 模块找不到的问题解决办法
                      领券
                      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档