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 支持的常用选项见下表:

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

完美运行!

以上解决办法参考自网络资源!

0X04 微信关注

WeChat

阅读剩余
THE END