python打包成exe的可执行文件

发布时间 2023-03-23 17:04:00作者: 琴声悠悠-悠悠琴声

注意,最好用管理员权限运行cmd,否则可能安装包过程中报错

 

普通打包

1、第一步下载pyinstaller,执行:pip install pyinstaller

2、第二步打包,执行:pyinstaller -w -F -i tb.ico xxx.py

-w 表示希望在生成的.exe程序运行过程中,不要出现cmd黑框,一般用于打包GUI界面

-F:表示希望将所有的程序全部打包在一起,生成的只有一个.exe文件,这样的文件集成度高,但是运行速度慢

  如果不写-F,生成的还有一堆.dll文件,这样的程序里文件很多,但是运行速度比较快

-D:生成一个文件目录包含可执行文件和相关动态链接库和资源文件等

对于打包结果较大的项目,选用-d生成目录相比单可执行文件的打包方式,执行速度更快,但包含更加多的文件。

-p:自定义需要加载的类的路径

-i:自己做的软件可以放上自己的图标,分享一个网站,可以把其他格式图片转成ico格式:https://app.xunjiepdf.com/img2icon/

XXX.py:指的是你整个项目的入口程序,大家写项目时很可能是多文件编程,你整个项目时靠哪个文件作为主入口拉起来的,就填哪个文件的名字

 

 

 

总结:

pyinstall -F xxxx.py  打包exe

pyinstall -F -w xxxx.py   不带控制台的打包

pyinstall -F -w -i tb.ico xxxx.py  指定exe图标打包,tb是图标文件名

 

问题与解决:

一、提示病毒

原因:看看我们是否有os库,os库虽然很方便,也是python的内置库,但是,据说某些不怀好意的人,写病毒的时候经常用到os库,于是可怜的os库就被各大杀毒软件跟谷歌拉黑了。

解决方案:

pathlib替换os、os.path、os.system

from pathlib import Path

但是实际仍然提示病毒

实际解决:去掉-w参数,保留cmd窗口

 

二、打包之前程序能正常运行,但是pyinstall打包后提示第三库找不到:ModuleNotFoundError:No module named ‘testlink’

解决方法:

1、在要打包的py文件同级目录下新建一个文件夹package(文件夹自己随便命名即可)。注意,一定要和打包的py文件在同一级目录下

2、在pycharm点击file---》setting---》project----》Python interpreter下,然后将鼠标放到报错的库名上面,可以看到库所在路径,一般在工程的.\project\venv\Lib\site-packages下

3、找到库所在文件夹,然后将库复制处理,放到第1步建好的文件夹中即可

4、最后运行使用打包命令时,加入-p参数 ,pyinstall -F -p package xxx.py就可以解决问题了

 

 三、pyinstall打包exe后文件找不到(路径不对),包括配置文件找不到,excel文件找不到等等

原因:运行路径和当前文件真实路径不是同一个,运行时,程序中所有的相对路径都会指向运行时的路径,如果需要到exe文件所在目录下读取配置文件则需要用到os.path.dirname(sys.executable)

解决:先获取exe文件所在目录,在获取配置文件路径

cur_path = os.path.dirname(sys.executable)
self.conf_path = os.path.join(cur_path, 'param.ini')

 

总结

有dirname的是返回文件所属目录,abspath是文件的绝对路径

print(os.path.dirname(os.path.abspath('./yyyyTools.py')))  输出为exe文件所在目录   F:\Project\pythonProject\yyyyTools\dist    对应的pathlib库写法 print(Path('./yyyyTools.py').resolve().parent)
print(os.path.abspath('./yyyyTools.py'))        输出为exe文件的绝对路径    F:\Project\pythonProject\yyyyTools\dist\yyyyTools.py  对应的pathlib库写法   print(Path('./yyyyTools.py').resolve())
print(os.path.dirname(sys.executable))       输出为exe文件所在目录 F:\Project\pythonProject\yyyyTools\dist  对应的pathlib库写法 print(Path(sys.executable).parent)
print(os.path.abspath(sys.executable))     输出为exe文件路径    F:\Project\pythonProject\yyyyTools\dist\yyyyTools.exe  对应的pathlib库写法   print(Path(sys.executable).resolve())

print(os.path.dirname(os.path.abspath(__file__)))  输出运行路径      C:\Users\Louxq\AppData\Local\Temp\_MEI121  对应的pathlib库写法  print(Path(__file__).resolve().parent)
print(os.path.abspath(__file__))  输出运行路径C:\Users\Louxq\AppData\Local\Temp\_MEI121\yyyyTools.py  对应的pathlib库写法  print(Path(__file__).resolve())


资源文件打包

我们除了常用的-i添加exe图标功能、py文件、-p依赖的库外外,很多时候还希望能把各种图片、声音、字体等资源打包到exe中,这些资源文件无法直接通过命令参数被打进包中,我们需要进行修改打包时的spec文件来实现
spec文件是告诉pyinstall怎么打包py文件,比如路径、资源、动态库、隐式调用的模块等等,一般来说,我们不需要对它进行修改
最强大的方法:直接修改pyinstaller生成的spec文件
1、首先确认是否安装pyinstaller
2、其次确认自己源程序内import的所有第三方库是否均已安装
3、执行命令生成spec文件:pyi-makespec -F -p Package -i favicon.ico yyyyTools.py
其中pyi-makespec会生成一个spec文件(用于指定打包的配置)
-F : 效果是打包成一个文件
-w :则可以使打包后的程序运行时不弹出黑窗口
-i : 后跟一个ico格式的图标,其他格式会报错,指定打包后程序的图标
-p : 则是把package打进去
yyyyTools.py则是打包程序的入口文件(其他被调用的文件会自动导入)
此时可以看到多出了一个yyyyTools.spec文件(spec文件是一个python脚本,本质上是txt文本文件,可用记事本打开,是实现默认/个性化打包的文件)我们可以用记事本打开
spec文件中主要包含4个class:Analysis、PYZ、EXE、COLLECT
Analysis以py文件为输入,它会分析py文件的依赖模块,并生成相应的信息
PYZ是一个.pyz的压缩包,包含程序运行需要的所有依赖
EXE根据上面两项生成
COLLECT生成其他部分的输出文件夹,COLLECT也可以没有
a、py文件打包配
针对多目录多文件的python目录,打包时候需要将所有相关的py文件输入到Analysis类里,Analysis类中的pathex定义了打包的主目录,对于在此目录下的py文件可以只写文件名不写路径,如上的spec脚本,将所有项目中的py文件路径以列表形式写入Analysis,这里为了说明混合使用了绝对路径和相对路径

b、资源文件打包配置
资源文件包括打包的python项目使用的相关文件,包括如表文件,文本文件等。对于此类资源文件的打包需要设置Analysis的datas,
如例子所示datas接收元组:datas=[(SETUP_DIR+'lib\\icon','lib\\icon'),(SETUP_DIR+'data','data')]。
datas[('res','.')]
元组的组成为(原项目中资源文件路径,打包后路径),
例子中的(SETUP_DIR+'lib\\icon','lib\\icon')表示从D:\\install_test\\FASTPLOT\\lib\\icon下的图标文件打包后放入打包结果路径下的lib\\icon目录。

c、Hidden import配置
pyinstaller在进行打包时,会解析打包的python文件,自动寻找py源文件的依赖模块,但是pyinstaller解析模块时可能会遗漏某些模块,造成打包后执行程序时出现类似No Module named xxx。这是我们就需要在Analysis下hiddenimports中加入遗漏的模块

d、递归深度设置
在打包导入某些模块时,长红出现“RecursionError:maximum recursion depth exceeded”的错误,这可能是打包时出现了大量的递归超出了python预设的递归深度。因此需要在spec文件中添加递归深度的设置,设置一个足够大的值来保证打包的进行
即:
import sys
sys.setrecursionlimit(5000)

4、编辑spec文件,修改默认脚本,完成自定义打包需要的配置
把全部的资源文件都加到spec文件里的data中,
datas=【('path1','path2'),(),()】
path1为资源文件在本机的位置
path2为打包后文件调用的相对路径

5、使用spec这些打包命令:pyinstaller xxx.spec
注意用spec文件打包时不能有其他参数了

python主文件中最前面加入下面的代码
#资源文件目录访问
def source_path(relative_path):
#是否Bundle Resource
if getattr(sys, 'frozen', False):
base_path = sys._MEIPASS
else:
base_path = os.path.abspath(".")
return os.path.join(base_path, relative_path)

#修改当前工作目录,使得资源文件可以被正确访问
cd = source_path('')
os.chdir(cd)
这段代码的功能是,当程序未打包时,不改变当前工作目录;
当程序被pyinstaller打包成exe时,则会将工作目录修改未一个临时文件夹,届时打包好的程序会将资源文件都放到此处
加下了我们解析datas=【】此列表内可以加入一个元组(注意,此元组最多可以有两个元素)指定要打包的资源和打包后在临时文件夹内的文件夹名称,比如datas=[“res”,'.'],第一个res代表需要打包的文件夹名res,其内部存放的全都是各种资源文件。
第二个'.'代表打包后在临时文件夹中的文件夹名称。因为我的程序资源原本是存放在main.py的同级目录中,所以这里不需要运行后将资源释放到指定的文件夹中,直接使用'.'即可。如本身被调用的资源在一个二级文件夹“resource”里,则修改为datas=["res",'.')]




pyinstaller打包其他常见问题

1、路径最好为英文,没有中文字符
2、脚本名称里没有特殊字符
3、使用utf-8编码
4、图标文件必须是正常格式,为ico文件
5、命令使用pyinstaller和pyinstaller.exe结果都是一样的
6、参数的添加得在pyinstaller和xxx.py文件中间
7、如果你打包的代码中用到了静态文件,如图片和资源文件,需手动复制到文件夹中,否则exe文件会报找不到文件的错误
8、代码里导包最好使用from的方式,可节省打包后的文件大小
9、当你使用错误的参数去打包或者打包到一半中断,等等此类运行到一半没了的情况。会导致你原来的py文件变成一个0KB的空文件。里面的代码会全部消失!!!所以以后要有个良好的习惯,就是复制一份代码出来,用这个副本进行打包。并且参数出错,或者打错了导致失败时,检查下副本文件的py文件是否还存在再继续重新打包,不然打出来的就是空的文件,自然一直闪退,因为压根没有内容(这点我没遇到过,来自别人的提醒)
10、pygame代码调试的时候要在结束时加quit()不然程序会崩溃
11、py文件运行没问题,不代表你打包后的文件运行就没问题,所以在打包好文件,打算运行exe文件测试时一定要录屏,因为报错会一闪而逝然后程序关闭,不仔细看的话,发现不了还报错,只会认为程序一运行就闪退,会让人不明所以,都不知道为什么,只有清楚报的什么错才好去解决,所以,一定要录屏
12、如果在py文件中用到了多进程,且你在window下编译需要加一行代码在开头,multiprocessing.freeze_support()
13、打包的时候要进入到能运行这个py文件的虚拟环境中,不能再别的环境中对py文件打包,不然打包的结果还是你原来的环境,可能打包文件过大,或者引起缺失包等其他问题
14、如果有打包错误,具体看build里的warn***.txt文档,里面详细记录了错误的原因,一半都是库丢失

15、权限问题:通常在打包时出现的某些文件拒绝访问或没有权限执行某些操作等,解决这个的方法一般有这几个方面:
a、使用管理员权限运行cmd或其他命名行窗口
b、关闭杀毒软件
c、使用完全权限的管理员账户