如何使用PyInstaller打包Python代码为执行档

上週五好不容易用Python内建的Tkinter将操作介面拉好且测试OK,没想到在打包成执行档(.exe)这边花了一个上午,所以纪录一下自己的碰壁流程。

工作环境:
-Windows 10, Windows Server 2019
-Anaconda 2020.02
-Python 3.6.10

问题描述:

如何用PyInstaller打包Python代码为执行档(.exe)打包过程碰上的问题以及如何排除先安装PyInstaller:
pip install pyinstaller
打开Anaconda Prompt (anaconda3),并且将当前位置切至.py档存放路径:
cd C:\Users\*\Documents\GUI-20200323
输入打包代码,我要打包的是main.py。一般的教程都只到这边就停了,但后面才蛋疼:
pyinstaller main.py

4. 问题:RecursionError: maximum recursion depth exceeded

  File "c:\users\*\appdata\local\continuum\anaconda3\envs\keras4\lib\ast.py", line 253, in visit    return visitor(node)  File "c:\users\*\appdata\local\continuum\anaconda3\envs\keras4\lib\ast.py", line 263, in generic_visit    self.visit(value)  File "c:\users\*\appdata\local\continuum\anaconda3\envs\keras4\lib\ast.py", line 253, in visit    return visitor(node)  File "c:\users\*\appdata\local\continuum\anaconda3\envs\keras4\lib\ast.py", line 263, in generic_visit    self.visit(value)  File "c:\users\*\appdata\local\continuum\anaconda3\envs\keras4\lib\ast.py", line 253, in visit    return visitor(node)  File "c:\users\*\appdata\local\continuum\anaconda3\envs\keras4\lib\ast.py", line 263, in generic_visit    self.visit(value)  File "c:\users\*\appdata\local\continuum\anaconda3\envs\keras4\lib\ast.py", line 253, in visit    return visitor(node)  File "c:\users\*\appdata\local\continuum\anaconda3\envs\keras4\lib\ast.py", line 257, in generic_visit    for field, value in iter_fields(node):RecursionError: maximum recursion depth exceeded

突然蹦出这些有的没的,解决方法很简单,看一下.py档存放路径是不是出现了main.spec这个由PyInstaller自动产生的配置文件,用笔记本打开后新增下面两行代码后储存离开,然后保险起见将build和dist两个资料夹删除:
原因在于超过递迴限制,我也看不懂这什么意思。[8]

# -*- mode: python ; coding: utf-8 -*-import sys #我是新增的sys.setrecursionlimit(9000000) #我是新增的,这边数字越大越好block_cipher = Nonea = Analysis(['main.py'],             pathex=['C:\\Users\\*\\Documents\\GUI-20200323'],             binaries=[],             datas=[],             hiddenimports=[],             hookspath=[],             runtime_hooks=[],             excludes=[],             win_no_prefer_redirects=False,             win_private_assemblies=False,             cipher=block_cipher,             noarchive=False)
执行配置文件main.spec进行打包
解决上个问题后我们输入下列代码来重新製作执行档,这次我们是要执行自订的配置文件.spec,PyInstaller会遵循.spec指定规範进行打包:
pyinstaller main.spec

6-1. 闪退问题以及如何查询原因(pkg_resources.py2_warn)

等了一会儿后终于跑完了:

113390 INFO: checking EXE113390 INFO: Building EXE because EXE-00.toc is non existent113391 INFO: Building EXE from EXE-00.toc113391 INFO: Appending archive to EXE C:\Users\*\Documents\GUI-20200323\build\main\main.exe113486 INFO: Building EXE from EXE-00.toc completed successfully.113501 INFO: checking COLLECT113502 INFO: Building COLLECT because COLLECT-00.toc is non existent113502 INFO: Building COLLECT COLLECT-00.toc184733 INFO: Building COLLECT COLLECT-00.toc completed successfully.

我们来看看main.exe是不是可以正常地打开吧,main.exe的位置在:

C:\Users\*\Documents\GUI-20200323\dist\main\main.exe

但是等等,为什么会闪退!!!原来打包成功并不等于.exe可以顺利执行呀。既然这样那我们改用终端机来开启.exe,这样就能知道程是闪退的原因了[1]:

(keras4) C:\Users\*\Documents\GUI-20200323>cd C:\Users\*\Documents\GUI-20200323\dist\main #切换路径到main.exe的位置(keras4) C:\Users\*\Documents\GUI-20200323\dist\main>main.exe #执行Traceback (most recent call last):  File "site-packages\PyInstaller\loader\rthooks\pyi_rth_pkgres.py", line 13, in <module>  File "c:\users\*\appdata\local\continuum\anaconda3\envs\keras4\lib\site-packages\PyInstaller\loader\pyimod03_importers.py", line 623, in exec_module    exec(bytecode, module.__dict__)  File "site-packages\pkg_resources\__init__.py", line 86, in <module>ModuleNotFoundError: No module named 'pkg_resources.py2_warn'# 这个是问题来源[15208] Failed to execute script pyi_rth_pkgres(keras4) C:\Users\*\Documents\GUI-20200323\dist\main>

原来是因为PyInstaller再打包过程中漏掉pkg_resources.py2_warn导致产生的.exe无法顺利执行。这时我们再次开启配置文件.spec,手动添加pkg_resources.py2_warn吧,记得再次执行main.spec前要先删掉build、dist两个资料夹[2][3][4]:

# -*- mode: python ; coding: utf-8 -*-import syssys.setrecursionlimit(9000000)block_cipher = Nonea = Analysis(['main.py'],             pathex=['C:\\Users\\*\\Documents\\GUI-20200323'],             binaries=[],             datas=[],             hiddenimports=['pkg_resources.py2_warn'], #我是新增的             hookspath=[],             runtime_hooks=[],             excludes=[],             win_no_prefer_redirects=False,             win_private_assemblies=False,             cipher=block_cipher,             noarchive=False)
pyinstaller main.spec

6-2. 闪退问题以及如何查询原因(sklearn.utils._cython_blas)

现在我们再次执行.exe,结果又闪退了...,没关係我们用上面讲的方法,透过终端机来执行.exe档就能知道问题了:

(keras4) C:\Users\*\Documents\GUI-20200323>cd C:\Users\*\Documents\GUI-20200323\dist\main #切换路径到main.exe的位置(keras4) C:\Users\*\Documents\GUI-20200323\dist\main>main.exe # 执行Traceback (most recent call last):  File "main.py", line 3, in <module>  File "c:\users\*\appdata\local\continuum\anaconda3\envs\keras4\lib\site-packages\PyInstaller\loader\pyimod03_importers.py", line 623, in exec_module    exec(bytecode, module.__dict__)  File "mylib.py", line 10, in <module>  File "c:\users\*\appdata\local\continuum\anaconda3\envs\keras4\lib\site-packages\PyInstaller\loader\pyimod03_importers.py", line 623, in exec_module    exec(bytecode, module.__dict__)  File "site-packages\sklearn\linear_model\__init__.py", line 12, in <module>  File "c:\users\*\appdata\local\continuum\anaconda3\envs\keras4\lib\site-packages\PyInstaller\loader\pyimod03_importers.py", line 623, in exec_module    exec(bytecode, module.__dict__)  File "site-packages\sklearn\linear_model\_least_angle.py", line 22, in <module>  File "sklearn\utils\arrayfuncs.pyx", line 1, in init sklearn.utils.arrayfuncsModuleNotFoundError: No module named 'sklearn.utils._cython_blas'# 这个是问题来源[11656] Failed to execute script main(keras4) C:\Users\*\Documents\GUI-20200323\dist\main>

这次是打包过程中漏掉sklearn.utils._cython_blas,PyInstaller你这个小淘气~:

# -*- mode: python ; coding: utf-8 -*-import syssys.setrecursionlimit(9000000)block_cipher = Nonea = Analysis(['main.py'],             pathex=['C:\\Users\\*\\Documents\\GUI-20200323'],             binaries=[],             datas=[],             hiddenimports=['pkg_resources.py2_warn', 'sklearn.utils._cython_blas'], # 再加1个             hookspath=[],             runtime_hooks=[],             excludes=[],             win_no_prefer_redirects=False,             win_private_assemblies=False,             cipher=block_cipher,             noarchive=False)
收工
根据孟母三迁原理,我们终于顺利打包完成并且可以执行main.exe了(洒花)。然后你的萤幕会弹出辛苦拉的视窗以及一个黑色画面,消除黑色画面的方法很简单,只要依照下面代码位置方式修改.spec档后再次打包即可。
成果
a = Analysis(['main.py'],             pathex=['C:\\Users\\*\\Documents\\GUI-20200323'],             binaries=[],             datas=[],             hiddenimports=['pkg_resources.py2_warn', 'sklearn.utils._cython_blas'],             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',          debug=False,          bootloader_ignore_signals=False,          strip=False,          upx=True,          console=False # console要从True改成False)

结论:

打包完成不等于可以顺利运行.exe档PyInstaller的打包方式是由.spec定义我们可以自定义.spec如果有引用第三方套件(Numpy、Pandas等等),容易有漏打包问题,导致执行档有闪退问题用终端机执行.exe来确认闪退原因每次自动打包前都要删掉资料夹build、资料夹dist、配置文件.spec,以确保遗毒消除每次手动打包前都要删掉资料夹build、资料夹dist,以确保遗毒消除补一下最后的main.spec代码,可以拿来跟下一篇比较
# -*- mode: python ; coding: utf-8 -*-import sys # 这边要注意sys.setrecursionlimit(9000000) # 这边要注意block_cipher = Nonea = Analysis(['main.py'],             pathex=['C:\\Users\\e10832\\Documents\\GUI-20200323'],             binaries=[],             datas=[],             hiddenimports=['pkg_resources.py2_warn', 'sklearn.utils._cython_blas'], # 这边要注意             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',          debug=False,          bootloader_ignore_signals=False,          strip=False,          upx=True,          console=True )# 命令视窗开启(True)coll = COLLECT(exe,               a.binaries,               a.zipfiles,               a.datas,               strip=False,               upx=True,               upx_exclude=[],               name='main')

参考资料:
[1]https://blog.csdn.net/weixin_41417982/article/details/82216363
[2]https://blog.csdn.net/qq_40587575/article/details/86500445
[3]https://blog.csdn.net/j754379117/article/details/77281354
[4]https://medium.com/@peaceful0907/%E5%B0%87%E4%BD%A0%E7%9A%84python-code-%E6%89%93%E5%8C%85-pyinstaller-6777d0e06f58
[5]https://zhuanlan.zhihu.com/p/58199926
[6]https://zhuanlan.zhihu.com/p/40716095
[7]https://zhuanlan.zhihu.com/p/76974787
[8]https://xken831.pixnet.net/blog/post/463075799-%5Bpython%5D-%E8%A7%A3%E6%B1%BA-recursionerror%3A-maximum-recursion-depth-exce


关于作者: 网站小编

码农网专注IT技术教程资源分享平台,学习资源下载网站,58码农网包含计算机技术、网站程序源码下载、编程技术论坛、互联网资源下载等产品服务,提供原创、优质、完整内容的专业码农交流分享平台。

热门文章