适用身手!Pyinstaller打包身手!

3个月前 (11-21 18:47)阅读3回复0
xx
xx
  • 管理员
  • 注册排名6
  • 经验值131325
  • 级别管理员
  • 主题26265
  • 回复0
楼主

当我们利用Python开发好法式需要打包成exe时,支流的做法即是利用pyinstaller,那玩意,看似简单,其实挺费事的,坑比力多,特殊是涉及到比力复杂的库时,别的一个费事的工作是,打包失败后,搜刮到的良多处理计划是没有效果的。

前一段时间,我用Python开发了视频同步助手,也是用pyinstaller打包的,此中涉及到opencv-python、ffmpeg、moviepy等包,嗯,那个过程比力磨人,在我共同pyinstaller源码与其文档后,掌握了一些身手,本文简单总结笔录一下,期看对你有所搀扶帮助。

动态导进问题

假设你项目中利用了opencv-python库,简单操纵pyinstaller打包,很随便呈现打包胜利了,却无法运行exe的情状,如下图:

从报错细节来看,它让你查抄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在打包时,会将项目标依靠也打包进来,但不包罗下面几种情状:

实现了__import__办法的类实例,在项目中利用时,无法被pyinstaller检测

通过importlib.import_module办法导进的库,无法被pyinstaller检测

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

嗯,pyinstaller存在那些局限,而良多出名的库却大量呈现上面的三种情状,好比Django、opencv-python。

怎么办?文档给出了4种处理计划:

通过pyinstaller号令行打包时,通过响应的设置装备摆设参数,给出额外的信息

将项目修改成利用import关键字导进的形式

编写spec文件,给出额外信息,那与第1种办法不异,号令行上指定的参数,等价于spec设置装备摆设文件中的设置装备摆设

利用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-hooks-contrib 是社区庇护的pyinstaller hooks机造

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

当我们打包opencv-python时,需要重视opencv-python的版本,因为差别版本的opencv-python,需要hook的位置可能会改动,我们看到pyinstaller opencv-python相关的hook代码中的正文也能够看出其版本要求:

颠末屡次尝试,下面的版本关系能够让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个用处:

当你期看将数据文件与打包法式绑缚在一路时

当你期看包罗运行时库时(DLL、SO等文件)

当你期看将Python run-time options添加到可施行文件时

当您想创建一个包罗合并的公共模块的多法式包时

用处3与用处4没有在现实项目中利用过,所以不讨论,我们次要来看看用处1与用处2。

我们能够利用下面号令创建spec文件:

pyi-makespec main.py

下面是【无感视频同步助手】的spec文件,比拟于创建出的默认spec文件,内容多会多一些,定见你间接从我那里复造出往用。

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

importjson

importos

importsys

importPyInstaller.config

# 存放最末打包成app的相对途径

buildPath = 'build'

PyInstaller.config.CONF[ 'distpath'] = buildPath

# 存放打包成app的中间文件的相对途径

cachePath = os.path.join(buildPath, 'cache')

ifnotos.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.s,

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,但实正运行营业逻辑时,会报错:

颠末加日记重打包后阐发可知,它鄙人面位置报错:

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:

moviepy的做者偷懒,间接通过exec来批量导进需要的库,不成为不骚。

怎么处理?

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

然后再项目进口py文件中,import moviepy_import,处理moviepy批量导进的骚写法。

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

阅读imageio_ffmpeg目次,发现它本身会安拆对应版本的ffmpeg。

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

其实就是找不到ffmpeg而报错,我的处理办法是手动设置一下:

结尾

嗯,目前我条记里有笔录的坑就上文中那些了,一个别会是,阅读源码和阅读文档的才能很重要,特殊是材料比力少的情状。

进门: 最全的零根底学Python的问题 | 零根底学了8个月的Python |实战项目 | 学Python就是那条捷径

干货:爬取豆瓣短评,片子《后来的我们》 | 38年NBA更佳球员阐发 |从万寡等待到口碑扑街!唐探3令人失看 | 笑看新倚天屠龙记 | 灯谜答题王 | 用Python做个海量蜜斯姐素描图 | 碟中谍那么火,我用机器进修做个迷你选举系统片子

兴趣:弹球游戏 | 九宫格 | 标致的花 | 两百行Python《天天酷跑》游戏!

AI:会做诗的机器人 | 给图片上色 | 揣测收进 | 碟中谍那么火,我用机器进修做个迷你选举系统片子

小东西: Pdf转Word,轻松搞定表格和水印! | 一键把html网页保留为pdf! |再见PDF提取收费! | 用90行代码打造最强PDF转换器,word、PPT、excel、markdown、html一键转换 | 造造一款钉钉低价机票提醒器! |60行代码做了一个语音壁纸切换器天天看蜜斯姐! |

年度爆款案牍

1). 卧槽!Pdf转Word用Python轻松搞定 !

2).学Python实香!我用100行代码做了个网站,帮人PS游览图片,赚个鸡腿食

3).首播过亿,火爆全网,我阐发了《披荆斩棘的姐姐》,发现了那些奥秘

4). 80行代码!用Python做一个哆来A梦分身

5).你必需掌握的20个python代码,短小精悍,用途无限

6). 30个Python奇淫身手集

7). 我总结的80页《菜鸟学Python精选干货.pdf》,都是干货

8). 再见Python!我要学Go了!2500字深度阐发 !

9).发现一个舔狗福利!那个Python爬虫神器太爽了,主动下载妹子图片

0
回帖

适用身手!Pyinstaller打包身手! 期待您的回复!

取消