pyinstaller打包技巧

这篇具有很好参考价值的文章主要介绍了pyinstaller打包技巧。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

简介

当我们使用Python开发好程序需要打包成exe时,主流的做法便是使用pyinstaller,这玩意,看似简单,其实挺麻烦的,坑比较多,特别是涉及到比较复杂的库时,另外一个麻烦的事情是,打包失败后,搜索到的很多解决方案是没有效果的。

前一段时间,我用Python开发了视频同步助手,也是用pyinstaller打包的,其中涉及到opencv-python、ffmpeg、moviepy等包,嗯,这个过程比较磨人,在我配合pyinstaller源码与其文档后,掌握了一些技巧,本文简单总结记录一下,希望对你有所帮助。

动态导入问题

如果你项目中使用了opencv-python库,简单利用pyinstaller打包,很容易出现打包成功了,却无法运行exe的情况,如下图:

pyinstaller打包,python,java,mysql,大数据,人工智能

从报错细节来看,它让你检查OpenCV是否安装(Check OpenCV installation),但这其实不是报错原因,核心在这句:

native_module = importlib.import_module("cv2")

importlib库在业务型项目中是比较少使用的,其作用就是动态载入相应的库,而我们在日常的业务开发中,使用import关键字来实现库的载入。

很多Python开源项目会使用importlib来实现插件系统,值得学习,但这里却因为importlib的原因,让pyinstaller打包失败。

阅读pyinstaller文档中的【What PyInstaller Does and How It Does It】小节,可知,pyinstaller在打包时,会将项目的依赖也打包进来,但不包含下面几种情况:

  1. 实现了__import__()方法的类实例,在项目中使用时,无法被pyinstaller检测

  2. 通过importlib.import_module()方法导入的库,无法被pyinstaller检测

  3. 通过sys.path执行的逻辑,无法被pyinstaller检测

嗯,pyinstaller存在这些局限,而很多知名的库却大量出现上面的三种情况,比如Django、opencv-python。

怎么办?文档给出了4种解决方案:

  1. 通过pyinstaller命令行打包时,通过相应的配置参数,给出额外的信息

  2. 将项目修改成使用import关键字导入的形式

  3. 编写spec文件,给出额外信息,这与第1种方法相同,命令行上指定的参数,等价于spec配置文件中的配置

  4. 使用hook,实现动态替换

首先排除方法2,因为这种方式只适用于你自己的项目,而Django、opencv-python这类第三方库,改不动,改动了也不好维护。

然后排除方法1与方法3,对于简单情况,这两种方法是可以的,文本后面点也会介绍,但一些第三方库,动态导入的地方比较多,你通过写死配置的形式不太靠谱。

嗯,剩下方法4了。

什么是pyinstaller的hook?其实就是动态替换一些信息的一种方法。以opencv-python为例,开发者自己知道不同版本的opencv-python动态导入时,会导入什么地方的数据,通过hook的形式,在不改动opencv-python的基础上,动态映射成我们自己的导入方式。

pyinstaller文档中给出了hook的开发细节,但不用急着动手,pyinstaller的社区已经将一些知名库的hook都开发好了,当你安装好pyinstaller时,相应的hook库其实也安装好了,叫pyinstaller-hooks-contrib。

pyinstaller打包,python,java,mysql,大数据,人工智能

pyinstaller-hooks-contrib 是社区维护的pyinstaller hooks机制

pyinstaller打包,python,java,mysql,大数据,人工智能

我们以opencv-python为例,找到opencv-python代码动态导入的位置,如下图:

pyinstaller打包,python,java,mysql,大数据,人工智能

当我们打包opencv-python时,需要注意opencv-python的版本,因为不同版本的opencv-python,需要hook的位置可能会改变,我们看到pyinstaller opencv-python相关的hook代码中的注释也可以看出其版本要求:

pyinstaller打包,python,java,mysql,大数据,人工智能

经过多次实验,下面的版本关系可以让opencv-python成功打包。

pip uninstall pyinstaller-hooks-contrib
pip install pyinstaller-hooks-contrib==2021.3

pip uninstall pyinstaller
pip install pyinstaller==4.5.1


pip uninstall opencv-python
pip install opencv-python==4.5.4.58

但,单纯的解决版本问题,还是无法很好的使用opencv-python,我们还需要将opencv-python的完整路径告诉pyinstaller,这需要使用方法1或方法3,我个人习惯使用方法3,即利用spec配置文件的形式来给pyinstaller更多额外信息。

spec文件

阅读pyinstaller文档中的【Using Spec Files】小节可知,spec文件会告诉pyinstaller打包时,如何处理被打包脚本,且spec文件实际上是可执行的python代码。

从文档可知,spec文件主要有4个用途:

  1. 当你希望将数据文件与打包程序捆绑在一起时

  2. 当你希望包含运行时库时(DLL、SO等文件)

  3. 当你希望将Python run-time options添加到可执行文件时

  4. 当您想创建一个包含合并的公共模块的多程序包时

用途3与用途4没有在实际项目中使用过,所以不讨论,我们主要来看看用途1与用途2。

我们可以使用下面命令创建spec文件:

pyi-makespec main.py

下面是【无感视频同步助手】的spec文件,相比于创建出的默认spec文件,内容多会多一些,建议你直接从我这里复制出去用。

# -*- mode: python ; coding: utf-8 -*-

import json
import os
import sys

import PyInstaller.config

# 存放最终打包成app的相对路径
buildPath = 'build'
PyInstaller.config.CONF['distpath'] = buildPath

# 存放打包成app的中间文件的相对路径
cachePath = os.path.join(buildPath, 'cache')
if not os.path.exists(cachePath):
    os.makedirs(cachePath)
PyInstaller.config.CONF['workpath'] = cachePath

# icon相对路径
icoPath = os.path.join('logo.ico')

# 项目名称
appName = '无感视频同步助手'

# 版本号
version = '1.0.0'

# 对Python字节码加密
block_cipher = pyi_crypto.PyiBlockCipher(key='875650321356')


a = Analysis(['gui_main.py'],
            pathex=["venv\\Lib\\site-packages\\cv2"],
            binaries=[("venv\\Lib\\site-packages\\cv2\\opencv_videoio_ffmpeg453_64.dll", ".")],
            datas=[('gui\\frontend', 'gui\\frontend')],
            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,
        a.binaries,
        a.zipfiles,
        a.datas,
        [],
        name=appName,
        debug=False,
        bootloader_ignore_signals=False,
        strip=False,
        upx=True,
        upx_exclude=[],
        runtime_tmpdir=None,
        console=False,
        disable_windowed_traceback=False,
        target_arch=None,
        codesign_identity=None,
        entitlements_file=None,
        icon=icoPath)

其中:

pathex=["venv\\Lib\\site-packages\\cv2"],

便是将opencv-python完整项目的路径告诉pyinstaller,这样打包pyinstaller-python时,再配合上正确的pyinstaller与opencv-python版本,便可以打包出可正常打开的exe。

知识点:第三方库代码相关的放在pathex字段中

打包后的opencv-python无法处理视频

一切似乎很ok,但真正运行业务逻辑时,会报错:

pyinstaller打包,python,java,mysql,大数据,人工智能

经过加日志重打包后分析可知,它在下面位置报错:

pyinstaller打包,python,java,mysql,大数据,人工智能

opencv-python处理视频其实利用了ffmpeg.dll,而我们打包时,如果没有告诉pyinstaller ffmpeg.dll的位置,pyinstaller就不会将其打包进来,则会导致运行报错。

所以,spec文件中需要下面的内容:

binaries=[("venv\\Lib\\site-packages\\cv2\\opencv_videoio_ffmpeg453_64.dll", ".")],

知识点:dll、so这类动态库,要写在binaries字段中。

静态资源打包

【无感视频同步助手】使用了html、css来做布局,这些不是python代码,对python而言,类似于image、video之类的静态资源,这类静态资源,我们需要写到spec文件的datas字段中:

datas=[('gui\\frontend', 'gui\\frontend')],

打包moviepy

搞定opencv-python后,你可以用类似的方法来搞moviepy这个库,毕竟moviepy也是基于ffmpeg来弄的,这不简单。

嗯,不会灵活变通的话,可能会懵逼,因为moviepy有如下导入方式,且社区没有提供moviepy的hook:

pyinstaller打包,python,java,mysql,大数据,人工智能

moviepy的作者偷懒,直接通过exec来批量导入需要的库,不可为不骚。

怎么解决?

使用方法2,没错,将其改成使用import关键字导入的形式,但不是改moviepy的代码。我们创建moviepy_import.py文件,将需要导入的库都写进去。

pyinstaller打包,python,java,mysql,大数据,人工智能

然后再项目入口py文件中,import moviepy_import,解决moviepy批量导入的骚写法。

此外,moviepy打包还有另外一个问题,因为moviepy使用了imageio_ffmpeg这个库,而imageio_ffmpeg会使用ffmpeg,但我们打包时,没有将ffmpeg文件打包进去,moviepy在运行时便会报错。

浏览imageio_ffmpeg目录,发现它自己会安装对应版本的ffmpeg。

pyinstaller打包,python,java,mysql,大数据,人工智能

找到moviepy报错位置,其实是imageio_ffmpeg库的_utils.py文件中的get_ffmpeg_exe()方法,如下图:

pyinstaller打包,python,java,mysql,大数据,人工智能

其实就是找不到ffmpeg而报错,我的解决方法是手动设置一下:

pyinstaller打包,python,java,mysql,大数据,人工智能

结尾

嗯,目前我笔记里有记录的坑就上文中这些了,一个体会是,阅读源码和阅读文档的能力很重要,特别是资料比较少的情况。

以上,我是二两,下篇文章见。文章来源地址https://www.toymoban.com/news/detail-543574.html

到了这里,关于pyinstaller打包技巧的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • python打包Windows.exe程序(pyinstaller)

    python打包Windows.exe程序(pyinstaller) pip install pyinstaller 使用pip命令来安装pyinstaller模块。 -F: pyinstaller -F hello.py -p hello2.py -D: pyinstaller -D hello.py -p hello2.py -i : pyinstaller -i tb.ico -F hello.py -p hello2.py 其中前一个文件hello是主文件,后一个文件是会被调用到的文件,可以有多个。

    2024年02月13日
    浏览(55)
  • 【Python】pyinstaller全新的打包方案,堪称完善!

    如果我要写一个 Python 项目,打包成 exe 运行(方便在没有 Python 的电脑上使用),我需要打包出的根目录结构美观,没有多余的、杂乱的依赖文件在那里碍眼,而且需要在发现 bug 时,我还需要能够修改里面的代码后,无需再次打包,就能正常运行,该怎么做呢? 就以一个

    2024年02月16日
    浏览(37)
  • Python pyinstaller打包exe最完整教程

    python提供了多种方法用于将普通的*.py程序文件编译成exe文件(有时这里的“编译”也称作“打包”)。exe文件即可执行文件,打包后的*.exe应用不用依赖python环境,可以在他人的电脑上运行。 pyinstaller是一个第三方模块,专用于python程序的exe打包。此外python还有一些别的方法

    2024年02月08日
    浏览(47)
  • Python PyInstaller将程序打包为exe程序

    1.执行 pip install pyinstaller,结果如下图  2.然后执行 pyinstaller -F -w Hello.py 执行完之后会产生两个目录 在dist目录下就是可执行文件,双击即可看到效果

    2024年02月04日
    浏览(44)
  • python pyinstaller打包常见问题(一):无法生成exe文件/打包闪退

    小游戏程序,本地环境能正常运行 程序调用了wav文件,即音效资源文件 程序调用wav路径正确,也是采用绝对路径 程序制作完成后,进行了以下三步打包操作: 在需要打包的程序的目录上,我进入终端输入以下命令进行打包: 2.1、打开生成的snake.spec文件 2.2、修改Analysis 的

    2024年01月22日
    浏览(70)
  • 【Python三种打包方式】分别使用PyInstaller & setupTools & 拷贝环境实现项目打包

    pyinstaller 和 setuptools 打包有什么区别(来自 ChatGPT 的答案) pyinstaller 和 setuptools 都是 Python 中常用的打包工具,但它们的主要目的和工作方式略有不同。 pyinstaller 是一个可以将 Python 代码 打包成一个可执行文件的工具 ,它会将你的 Python 代码和所有依赖项打包成一个单独的可

    2024年02月03日
    浏览(49)
  • 【Python】Pyinstaller打包Linux运行文件,暴露配置文件

    Pyinstaller可以将python程序打包成可执行文件,在windows上是exe文件,在linux上是二进制可执行文件。 工作中有需求是把本地python工程打包成后台可运行的服务,考虑到部署环境的不同,可以使用docker镜像的方式,也可以使用pyinstaller打包成可执行文件: docker镜像的好处是运行起

    2024年02月05日
    浏览(40)
  • PyInstaller 完美打包 Python 脚本,输出结构清晰、便于二次编辑的打包程序

    如果我要写一个 Python 项目,打包成 exe 运行(方便在没有 Python 的电脑上使用),我需要打包出的根目录结构美观,没有多余的、杂乱的依赖文件在那里碍眼,而且需要在发现 bug 时,我还需要能够修改里面的代码后,无需再次打包,就能正常运行,该怎么做呢? 就以一个

    2024年02月07日
    浏览(43)
  • 采用pycharm在虚拟环境使用pyinstaller打包python程序

    一年多以前,我写过一篇博客描述了如何虚拟环境打包,这一次有所不同,直接用IDE pycharm构成虚拟环境并运行pyinstaller打包 之前的博文: 虚拟环境venu使用pyinstaller打包python程序_伊玛目的门徒的博客-CSDN博客 第一步: pycharm建立项目,创建一个虚拟环境。   第二步: 在项目

    2024年02月12日
    浏览(43)
  • 使用pyinstaller打包python文件遇到的问题和解决方法

    情况1 :当所使用的代码都在一个.py文件中,且该代码中没有调用其他文件和import自己写的函数时 例如: 打包下面这个检查输入的ip是否符合规范的程序ipcheck.py,程序中只Import了自带的库re 下载pyinstaller 使用Pyinstaller打包。先进入该程序所在的文件夹,在文件资源管理器的文

    2024年02月06日
    浏览(55)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包