exe文件查看源代码_【Python记 #3】记一次python打包为.exe的经历

一、写在前面

仿佛已经有三周没有写文章了呢,期中考试在上个星期落下帷幕,又有时间来写点东西了。

这次文章是个副产品,本是因为同学们英语课有个配音作业要合并录音和原视频,但Pr门槛有些高,不便使用,于是顺手把前几次文章中合并音视频的函数拿出来用。其间考虑到并非所有同学都学了Python,同时安装moviepy库着实不太方便,于是着手打包成exe文件。

事情本应到此结束的,但是在使用pyinstaller打包的过程中出现了意料之外的情况,于是写了这篇记录,或许能帮助遇到同样问题的伙伴们。

二、背景知识

众所周知Python是解释型语言,这种类型的编程语言,会将代码一句一句直接运行,而不是编译生成为可执行文件后再运行,这也是为什么我们可以在交互环境下运行Python的原因。

这样却造成了通常意义上无法将Python生成为机器码发送给别人,即使是pyinstaller打包也只是同时将编译器、库和源代码一起打包,生成为自解压程序。运行这样生成的程序先有一个解压过程,然后再正常执行。

pyinstaller可以将python打包为exe,用 pip install pyinstaller 安装,在命令行中使用。命令为 pyinstaller -F .main.py关于pyinstaller的使用可以参考这篇文章:

知乎:别再问我怎么Python打包成exe了!

三、遇到的问题及原因

贴上代码(代码不是重点):

from moviepy.editor import VideoFileClip, AudioFileClip

print("使用指南:")
print("将需要合并的音频视频放在该exe文件同目录下,然后按照说明进行n")

video_name = input("输入视频名(带后缀名):")
audio_name = input("输入音频名(带后缀名):")

audio_start = int(input("输入需要音频的起始秒数:"))
audio_end = int(input("输入需要音频的结束秒数:"))
print("n注意截取的音频视频长度必须相同")
print("注意截取的音频视频长度必须相同")
print("注意截取的音频视频长度必须相同n")
video_start = int(input("输入需要视频的起始秒数:"))
video_end = int(input("输入需要视频的结束秒数:"))

video_clip = VideoFileClip(video_name)
audio_clip = AudioFileClip(audio_name)
video_clip = video_clip.subclip(video_start, video_end)
audio_clip = audio_clip.subclip(audio_start, audio_end)

video_clip = video_clip.set_audio(audio_clip)
video_clip.write_videofile("output.mp4")
print("nDone!输出视频output.mp4在源文件目录下n")

在.py目录下用cmd执行 pyinstaller -F .main.py命令生成exe文件,正常生成,没有报错。

但运行生成的文件时报了如下错误“AttributeError: module 'moviepy.audio.fx.all' has no attribute 'audio_fadein'“。为什么?

查阅相关资料后发现,moviepy 采用动态加载的方式,源代码中体现为在执行import moviepy 后才开始调用子库,而事先无法得知

21f1c2892e41a46a731404917cd142e5.png

pyinstaller无法很好地处理这种情况,导致最后打包出的exe缺少必要的库

四、解决方案

参考博客中的解决方案似乎有点问题,按照执行并不能解决问题,可能是版本问题,但思路非常值得借鉴。

找到moviepy库的文件位置(通常在python文件夹的site-packages文件夹下),目标是处理audio和video中的_init_文件。(记得备份moviepy文件夹,改完后恢复)

f5452557e79e161d1fab66eabb86b97d.png
audio部分

5301766ba4ed9e860cdd5e99708c6198.png
video部分

两个处理方案相近,不妨以video为例,

  1. 在exec("from ..%s import %s" % (name, name))这一行下加上一行print("from ..%s import %s" % (name, name)),目的是为了找出运行中究竟加载了哪些子库。运行编写的python代码,在最开头有这些输出内容:

d3e410dd58861b45ebfa70c014fbbccd.png
运行python文件输出的内容

2. 用输出的所有内容替换for循环那一段,相当于手动执行了加载子库的功能。

最后效果:

"""

3. 将相同过程对moviepy/audio/fx/all中的_init_.py做一遍,也进行替换

最后效果:

Loads all the fx !
Usage:
import moviepy.audio.fx.all as afx
audio_clip = afx.volume_x(some_clip, .5)
"""

import pkgutil

import moviepy.audio.fx as fx

__all__ = [name for _, name, _ in pkgutil.iter_modules(
    fx.__path__) if name != "all"]


from ..audio_fadein import audio_fadein
from ..audio_fadeout import audio_fadeout
from ..audio_left_right import audio_left_right
from ..audio_loop import audio_loop
from ..audio_normalize import audio_normalize
from ..volumex import volumex

4. 此时再用pyinstaller,打包出的exe就不会再出现却少库的问题。(记得把备份的moviepy复制回去)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值