Python使用pyinstaller打包exe 报错: No module named ‘PySide2’
0X00 问题背景
在之前使用Python写过一个小工具,具体功能就是给PDF文档添加水印,但是水印也是提前准备好的一pdf文档,所以其实就是合并pdf文件!具体内容看这里Python轻松给PDF文档加水印! - 编程那点事儿 (imyjs.cn)。再后来为了方便自己后期使用,就实用PySide2写了UI界面,具体实现代码看这里使用Python实现PDF文档常用操作 - 编程那点事儿 (imyjs.cn)。那么下边就是打包成exe程序并使用了。在这里我选择的是PyInstaller
打包第三方库工具。但是中间出现了问题,现在记录一下,希望可以帮助到你!
0X01 问题分析
关于PyInstaller的使用可以通过pyinstaller -h
查看命令帮助。PyInstaller 支持的常用选项见下表:
-h,--help | 查看该模块的帮助信息 |
---|---|
-F,-onefile | 产生单个的可执行文件 |
-D,--onedir | 产生一个目录(包含多个文件)作为可执行程序 |
-a,--ascii | 不包含 Unicode 字符集支持 |
-d,--debug | 产生 debug 版本的可执行文件 |
-w,--windowed,--noconsolc | 指定程序运行时不显示命令行窗口(仅对 Windows 有效) |
-c,--nowindowed,--console | 指定使用命令行窗口运行程序(仅对 Windows 有效) |
-o DIR,--out=DIR | 指定 spec 文件的生成目录。如果没有指定,则默认使用当前目录来生成 spec 文件 |
-p DIR,--path=DIR | 设置 Python 导入模块的路径strong>(和设置 PYTHONPATH 环境变量的作用相似)。也可使用路径分隔符(Windows 使用分号,Linux 使用冒号)来分隔多个路径 |
-n NAME,--name=NAME | 指定项目(产生的 spec)名字。如果省略该选项,那么第一个脚本的主文件名将作为 spec 的名字 |
-i path,--icon=path | 指定项目的图标。如果省略该选项,那么为默认图标 |
这里我们直接运行
pyinstaller -w pdf.py
因为 pyinstaller
默认打包是控制台程序,我们这里加上-w
的命令是说明我们是windows桌面程序,也就是说打开文件后没有cmd黑窗口。
打包成功后,我们切到目录下面去,发现多了几个文件。
build\
和 dist\
和 pdf.spec
是多出来的打包生成的文件。
- build我们不需要使用,可以忽略掉。
- dist\ 路径包含了我们生的的exe和各种依赖文件, 可以直接拿去发布。
- pdf.spec 是pyinstaller自动生成的配置文件,后续修改打包配置都可以直接在上面修改
好了,我们现在尝试运行dist\pdf\pdf.exe
的exe文件,不出意料的出错了。
报错No module named XXX(以PySide2为例),但是XXX(以PySide2为例)明明已经安装成功。那么原因是?
其实是PySide2被安装到了工程文件pythonProject下面C:\Users\Smile\Desktop\pythonProject\venv\Lib\site-packages
而不是python整个全局下的文件位置D:\Python3.9\Lib\site-packages下。
因此在使用pyinstaller打包的时候,需要指定所依赖包的文件路径。
具体解决方案看下边!
在解决了上个问题后,再次打包后点击执行发现果不其然不报那个错误了,结果新的问题又来了:
这个问题原因是我们的.ui文件找不到,没有包含到包里面,所以报错。具体解决方案看下边!
0X02 问题解决
No module named XXX
使用pyinstaller打包时,需要指定PySide2的文件路径
即 pyinstaller -w pdf.py -p C:\Users\Smile\Desktop\pythonProject\venv\Lib\site-packages
.ui文件找不到
方法一:手动拷贝
手动将.\pdf.ui
目录下的的文件,拷贝到dist\pdf\pdf.ui
重新运行,exe,成功。
方法二:修改打包命令
我们通过 pyinstaller -h 可以看到,有这么个命令--add-data
--add-data <SRC;DEST or SRC:DEST>
Additional non-binary files or folders to be added to
the executable. The path separator is platform
specific, os.pathsep
(which is ;
on Windows
and :
on most unix systems) is used. This option
can be used multiple times.
可以帮我们自动拷贝过去。
然后我们修改我们的打包命令再次重试。
pyinstaller -w pymain.py --add-data="formmain.ui;."
检查确定ui文件被拷贝到了exe同级目录,exe也运行成功。
注: 这里--add-data 可以多次添加,如果有多个ui文件或者其他资源文件,可以添加多个,然后一起拷贝过去,比如
pyinstaller -w pdf.py --add-data="main.ui;." --add-data="main2.ui;." --add-data="demo.jpg;."
方法三:修改.spec文件
首先我们先要了解spec文件,相当于pyinstaller运行后生成的配置文件。也就是说只要配置文件生成后,我们直接修改配置文件,然后重新运行配置文件就可以了。具体官方介绍戳这里
# -*- mode: python ; coding: utf-8 -*-
block_cipher = None
a = Analysis(['pymain.py'],
pathex=['C:\\Users\\Administrator\\Documents\\PyDemo'],
binaries=[],
datas=[],
hiddenimports=[],
hookspath=[],
hooksconfig={},
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='pymain',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
console=False,
disable_windowed_traceback=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None )
coll = COLLECT(exe,
a.binaries,
a.zipfiles,
a.datas,
strip=False,
upx=True,
upx_exclude=[],
name='pymain')
- 其中里面的
datas=
就相当于3.3.2章节里面的--add-data=
参数 console=False
就相当于命令行的-w
参数name=
可以设置打包的exe的名字
在这里我们只需要修改datas=
就行了。
a = Analysis(['pymain.py'],
pathex=['C:\\Users\\Administrator\\Documents\\PyDemo'],
binaries=[],
datas=[('main.ui', '.')],
hiddenimports=[],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False)
或者,有多个资源文件也可以修改成这样
a = Analysis(['pymain.py'],
pathex=['C:\\Users\\Administrator\\Documents\\PyDemo'],
binaries=[],
datas=[
('main.ui', '.'),
('main2.ui', '.'),
('demo.jpg', '.')
],
hiddenimports=[],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False)
修改保存好了,直接运行命令:pyinstaller pymain.spec
完美运行!
以上解决办法参考自网络资源!