Python文件Pyinstaller打包指南(学不会作者直播倒立演示)

Python 使用 Pyinstaller 打包文件

  • 引言
  • 正文
  • 1. 最常用的带 console 框的打包方式
  • 2. 不带 console 框的打包方式
  • 3. 只有一个应用程序的打包方式
  • 4. 通过 spec 文件进行调整的打包方式
  • 第 2 小节效果复现
  • 第 3 小节效果复现
  • 直接获取可以实现第 3 小节效果的 spec 文件
  • 5 包含 data 文件
  • 6. 在 console 中使用命令打包并包含 data 数据
  • 引言

    作者本人也使用过这个打包模块无数次尝试打包过程序,让它变成可以执行的应用程序,但是每次打包过程中都会出现各式各样的问题。不是模块没有收集,就是数据没有打包进来。本文我们将对这些问题一一介绍,旨在希望凡是阅读过这篇文章的小伙伴从此之后不再收到打包问题的困扰。

    这是一篇 DeepSeek 也无法给出正确解答的博文。

    正文

    1. 最常用的带 console 框的打包方式

    本文,我们将以作者自己做的一个桌面宠物程序进行说明。
    首先,我们所有的资源都被放置在如下图所示的文件目录下,打包时,我们推荐将所有资源都放置在同一个目录下。

    通常,我们需要从 console 中进入这个目录下,如下图所示:

    接下来,在这个目录下,我们需要输入:

    pyinstaller LongSitReminderV0.9.0.py
    

    输入后,按下回车,运行完成后,当前文件夹下会多出来三个文件,两个文件夹和一个 .spec 文件。

    build 文件夹:这是 PyInstaller 在打包过程中生成的临时文件,包含编译的中间结果。这个文件夹不能直接运行,可以安全删除。
    dist 文件夹:这是打包后的最终输出目录,包含可执行文件(如 .exe 文件)以及相关的依赖文件。你需要运行的是这个文件夹中的可执行文件。
    .spec 文件:这是 PyInstaller 的配置文件,用于定义打包的规则和参数。这个文件不能直接运行,但可以用于重新打包或修改打包配置。
    我们打开 dist 文件夹会看到:

    此时,这个文件是不能够直接被运行的,因为,我们的 LongSitReminderV0.9.0.py 代码中使用到了两个图片作为数据,我们需要将两个图片拷贝到 LongSitReminderV0.9.0.exe 相同的目录再次打开应用程序才可以正常执行。如下图所示:

    执行应用程序后得到的运行效果如下:

    此时,我们会得到我们的桌面宠物,并且会有一个黑色的 console 框产生,如果此时关闭 console 框,应用程序也会被关闭。

    2. 不带 console 框的打包方式

    显然,这个 console 框让我们很难受,通常我们不想要它,那么我们再打包的时候可以使用:

    pyinstaller --noconsole LongSitReminderV0.9.0.py
    

    使用上述代码打包后,将代码中用到的两个图片和应用程序放在同一个目录下,执行应用程序后,我们就会在看到桌面宠物的同时不会看到黑色的 console 框,本质上,–noconsole 相当于将 console 框隐藏起来了。这一功能也可以通过下面的代码实现。

    pyinstaller --windowed LongSitReminderV0.9.0.py
    

    具体效果如下图,此时只有桌面宠物而没有黑色的 console 框。

    3. 只有一个应用程序的打包方式

    有时候,我们只想要用户看到一个应用程序,其他的程序我们不想展示,此时可以使用如下方式将代码和数据打包为一个可以执行的应用程序。

    pyinstaller --onefile LongSitReminderV0.9.0.py
    

    打包后,我们在 dist 文件夹下会看到如下图所示的结果:

    此时,同样,我们需要将代码中用到的两个图片和这个应用程序放在同一个目录下,然后执行这个应用程序即可。

    4. 通过 spec 文件进行调整的打包方式

    前面我们提到,spec 文件是 PyInstaller 的配置文件,用于定义打包的规则和参数。这个文件不能直接运行,但可以用于重新打包或修改打包配置。这个文件我们可以通过在 concole 中执行如下代码得到:

    pyi-makespec LongSitReminderV0.9.0.py
    

    运行后,我们就可以在当前目录下得到一个如下图所示的 spec 文件。

    用记事本打开 spec 文件后我们可以看到里面的内容是:

    第 2 小节效果复现

    通过设置 exe=EXE() 部分中的参数 console=False 的方式我们可以实现第 2 小节中我们提及的效果。

    第 3 小节效果复现

    通过删除 coll = COLLECT() 中的所有内容,并且将 a.binaries 和 a.datas 放置在 exe=EXE() 的函数内部作为参数,且我们需要将 exclude_binaries=True 删除掉。这样,我们就可以实现第 3 小节中实现的效果。设置好以后,我们可以通过执行如下命令获取最终的应用程序。

    pyinstaller LongSitReminderV0.9.0.spec
    

    直接获取可以实现第 3 小节效果的 spec 文件

    获取 spec 文件时,我们也可以通过在 console 中输入命令直接获取。

    pyi-makespec --onefile LongSitReminderV0.9.0.py
    

    5 包含 data 文件

    有时候,我们自己的 data 文件可能是原创的,涉密的,我们也不希望用户获取到,此时,我们可以通过如下方式将数据集成在应用程序中,这里我们不介绍传统的方法,我们直接通过修改 spec 文件实现这一功能。比如,这里,我们将 spec 文件修改为如下图所示的形式:

    这样,我们再次执行 pyinstaller LongSitReminderV0.9.0.spec 后,我们会在 dist 文件下得到 LongSitReminderV0.9.0.exe,此时我们所有的 data 数据都会在这个文件里。

    理论上来说,我们此时不需要将图片数据导入放在这个目录,直接运行就可以,但是,事实上,通常,我们如果不将图片数据放到这个目录下,我们运行程序后仍旧无法得到得到想要的结果。这是因为我们在代码中从目录中导入图片出现了问题。我们需要在我们的代码中加入一个函数:

    def resource_path(relative_path):
        base_path = getattr(sys, '_MEIPASS', os.path.dirname(os.path.abspath(__file__)))
        return os.path.join(base_path, relative_path)
    

    代码中所有需要通过路径导入的数据都调用这个函数,这样执行上述操作后我们就可以单独运行 LongSitReminderV0.9.0.exe 应用程序得到我们想要的结果。

    反之,如果我们不在代码中使用上述函数,那么我们就需要使用下面的结构。

    截至这里,理论上本篇教程应该结束了,但是我相信还有很多朋友按照上述过程仍旧无法正确打包。这是因为,我们在代码中的路径引用均应该使用相对路径而非绝对路径。 resource_path() 函数的作用是当我们使用相对路径在代码中对我们的需要使用的数据进行引用时,该函数会自动获取打包后代码中使用资源相对于 exe 文件的相对位置,这样,我们就无需将使用的数据和 exe 文件放置在同一目录下了。但是需要注意,这里本质上打包后我们还是使用了原来位置处的原始数据,如果原始数据的位置发生了变化,比如原始数据所在文件夹的文件名称发生改变。那么我们打包后的 exe 程序就无法运行。 这意味着我们打包后的 exe 文件只能在当前电脑上运行,如果发送给其他人,在别的电脑上是无法运行的。

    事实上,解决这个问题非常容易,我们只需要通过打包时将 data 文件也打包进去就可以了(可以参考本节之前的部分以及第 6 小节),这样原始数据会被拷贝一份到打包后的目录下,我们在运行时, exe 程序会调用我们打包后的拷贝文件位置,这样我们就可以将所有数据一起压缩发送到其他电脑(用户)使用了。然而这个方法的弊端是,此时,我们拷贝进入打包文件的原始文件和我们的原始文件是一致的,用户也会看到我们的原始文件,这对于开发者是不友好的。

    解决这个问题的办法是,我们可以使用 –onefile 的打包方式,最终打包好之后原始数据会被集成在 exe 文件中,这样用户就无法很直观的获取到我们的原始数据文件了。但是这也是不安全的,因为通过 –onefile 的打包生成的 exe 程序在运行时会将集成在它中间的临时文件解压出来,临时放置在 用户/AppData/Temp/Mypass 目录下,用户仍旧可以通过此种方式获取我们的原始数据文件。AppData 是一个隐藏文件,如果找不到,可以在 Windows 中设置显示隐藏文件夹选项。

    为了解决数据安全性问题,我们可以通过一些数据加密的方式对我们的原始数据进行处理,具体方法大家自行查找。

    至此,打包应用程序基本就可以完美实现了。

    6. 在 console 中使用命令打包并包含 data 数据

    有些小伙伴可能不喜欢使用手动更改 .spec 文件的方式进行打包,事实上,我们也可以在 console 中使用命令来完成 data 数据的添加。具体方式如下:

    --add-data "C:\Project\PythonProject\LongSitReminderPet\Pets\MengJi_Orange.png:."
    

    如果我们查看官方文档,我们会得到这样的提示:

    --add-data <SRC;DEST or SRC:DEST>
    

    SRC 是 source 的缩写,意味在冒汗或者分号之前应该书写我们要打包数据存放的原始位置。
    DEST 是 destination 的缩写,意味着在冒号或者分号之后我们要书写我们想要将数据打包后存放的位置,一般是与 dist 目录相对的位置。
    上述命令中冒号后面的 . 就标识我们将数据直接打包在 dist 文件目录下。

    这里特别要注意,虽然在 Python 中,书写字符串时 “” 和 ‘’ 没有区别,但是对于 console 中的形式,必须使用 “”,否则就会报错。(作者本人踩坑数个小时终于想明白了这个问题)

    那对于多个 data 数据,我们可以采用

    --add-data "C:\Project\PythonProject\LongSitReminderPet\Pets\MengJi_Orange.png:." --add-data "C:\Project\PythonProject\LongSitReminderPet\Pets\MengJi_White.png:."
    

    本文不用部分内容来源于如下网站:

    https://coderslegacy.com/add-image-data-files-in-pyinstaller-exe/#comment-7976

    如果大家觉得有用,就点个赞让更多的人看到吧~

    作者:勤奋的大熊猫

    物联沃分享整理
    物联沃-IOTWORD物联网 » Python文件Pyinstaller打包指南(学不会作者直播倒立演示)

    发表回复