本文记录在Windows上,使用PyCharm打包Python项目的操作。
1. 安装pyinstaller
打开PyCharm的设置,File --> Settings --> Python Interpreter
,选择环境,点击+
,搜索pyinstaller
,点击安装。
2. 打包可执行文件
2.1 通过命令行打包
pyinstaller [options] script [script …] | specfile
在PyCharm,打开终端Terminal,输入命令pyinstaller命令,举例:
pyinstaller --icon icon.ico --name "芝麻酱" -F main.py scrapyimages.py --add-data "fake_useragent_0.1.11.json;." --add-binary "C:\Anaconda3\Library\bin\mkl_intel_thread.1.dll;."
一些常用的选项:
-F, --onefile 打包成一个文件
-i, --icon 可执行程序的图标
-n, --name 可执行程序文件名
-w, --noconsole 不显示控制台
-d, --debug 带调试信息
--add-data 添加依赖文件
--add-binary 添加库
PyInstaller更多用法见:Using PyInstaller — PyInstaller documentation。另:
- icon转换工具:Icon Converter | Convert Image to ICO File Online - RedKetchup
- 更换环境,在终端使用命令
conda activate [myenv]
执行pyinstaller options.. myscript.py
,PyInstaller会创建一个规范说明文件name.spec
(specification file)。事实上,运行pyinstaller的参数都在这里。因此,更建议直接在name.spec
上修改,再打包。
2.2 通过规范说明文件打包
可以使用pyinstaller -F main.py
生成main.spec
,再编辑该文件:
# -*- mode: python ; coding: utf-8 -*-
block_cipher = None
a = Analysis(['main.py', 'scrapyimages.py'],
pathex=['D:\\workspace\\images_crawler\\src'],
binaries=[('C:\\Anaconda3\\Library\\bin\\mkl_intel_thread.1.dll', '.')],
datas=[('D:\\workspace\\images_crawler\\src\\fake_useragent_0.1.11.json', '.')],
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,
a.binaries,
a.zipfiles,
a.datas,
[],
name='芝麻酱',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=True , icon='icon.ico')
然后运行:
pyinstaller -F main.spec
关于规范说明文件说见:Using Spec Files — PyInstaller documentation。
3. 遇到问题及解决
(1)Cannot load mkl_intel_thread.1.dll
打包完,双击.exe
文件,控制台输出错误:
Intel MKL FATAL ERROR: Cannot load mkl_intel_thread.1.dll
在电脑上找到mkl_intel_thread.1.dll
的位置,C:\Anaconda3\Library\bin\mkl_intel_thread.1.dll
,将该动态库添加到main.spec
。
(2)软件需要外部数据
我打包的这个应用,用到这个文件fake_useragent_0.1.11.json
,打包时,不能用相对路径,原因是[1]:
运行可执行文件时,会先将可执行文件进行压缩再执行,压缩的位置在 /tmp 下。因此,被打包进去的数据文件在被解压的路径下,而程序是在运行的路径下搜索,即可执行文件的目录下,所以找不到数据文件。
因此,我这样处理:
from fake_useragent import UserAgent
#ua = UserAgent(path='./fake_useragent_0.1.11.json')
cur_dir = os.path.dirname(os.path.abspath(__file__))
ua = UserAgent(path = os.path.join(cur_dir, 'fake_useragent_0.1.11.json'))
(3)运行完退出
程序运行完,控制台就关了。想让控制台在程序执行完不关闭,方法很多。
- 在main()函数末尾加上
input('按任意键关闭窗口')
- 在main()函数末尾加上
os.system('pause')
- 打开cmd,运行可执行文件
(4)程序运行一会,退出,没有错误信息
我将打包好的可执行文件放到其他电脑运行,双击后,运行一会,就退出,没有错误信息,也不是闪退。首先,加上-d
选项,重新打包成带有调试信息的可执行文件。再次运行,得到如下信息:
C:\Users\admin\Desktop>芝麻酱.exe
[11884] PyInstaller Bootloader 3.x
[11884] LOADER: executable is C:\Users\admin\Desktop\芝麻酱.exe
...
[4100] LOADER: Running pyi_rth_pyqt5.py
[4100] LOADER: Running pyi_rth_mplconfig.py
[4100] LOADER: Running pyi_rth_mpldata.py
[4100] LOADER: Running pyi_rth_certifi.py
[4100] LOADER: Running pyi_rth__tkinter.py
[4100] LOADER: Running main.py
[11884] LOADER: Back to parent (RC: -1066598274)
[11884] LOADER: Doing cleanup
[11884] LOADER: Freeing archive status for C:\Users\admin\Desktop\芝麻酱.exe
我估计问题出在tkinter
包,搜索了下,说是缺少libiomp5md.dll
[2]。在Anaconda目录搜索该文件,找到C:\Anaconda3\Library\bin\libiomp5md.dll
,将libiomp5md.dll
拷贝到main.py
同一个目录下,并添加到spec文件的datas
中,重新打包文件。
datas=[('libiomp5md.dll', '.')]
遗憾的是,问题依旧,知道方法的,烦请告知。
(5)Could not find the matplotlib data files
用Pyinstaller打包时,报错误“Could not find the matplotlib data files”。
这是因为matplotlib从3.2
开始,mpl-data
被分离出去了,安装离3.2
之前最近的版本3.1.3
。
$ pip install matplotlib==3.1.3
Collecting matplotlib==3.1.3
Downloading matplotlib-3.1.3-cp38-cp38-win_amd64.whl (9.1 MB)
|████████████████████████████████| 9.1 MB 6.4 MB/s
Requirement already satisfied: python-dateutil>=2.1 in c:\anaconda3\lib\site-packages (from matplotlib==3.1.3) (2.8.1)
Requirement already satisfied: cycler>=0.10 in c:\anaconda3\lib\site-packages (from matplotlib==3.1.3) (0.10.0)
Requirement already satisfied: pyparsing!=2.0.4,!=2.1.2,!=2.1.6,>=2.0.1 in c:\anaconda3\lib\site-packages (from matplotlib==3.1.3) (2.4.7)
Requirement already satisfied: kiwisolver>=1.0.1 in c:\anaconda3\lib\site-packages (from matplotlib==3.1.3) (1.3.1)
Requirement already satisfied: numpy>=1.11 in c:\anaconda3\lib\site-packages (from matplotlib==3.1.3) (1.20.1)
Requirement already satisfied: six in c:\anaconda3\lib\site-packages (from cycler>=0.10->matplotlib==3.1.3) (1.15.0)
Installing collected packages: matplotlib
Attempting uninstall: matplotlib
Found existing installation: matplotlib 3.5.2
Uninstalling matplotlib-3.5.2:
Successfully uninstalled matplotlib-3.5.2
Successfully installed matplotlib-3.1.3
参考资料:
[1] Pyinstaller将外部数据文件打包到可执行文件中(onefolder or onefile)教程_m0_37477175的博客-CSDN博客
[2] python - PyInstaller .exe file terminates early without an error message - Stack Overflow