目录
目录
4.1.1 模块找不到的错误 —— ModuleNotFoundError
4.1.4 'pyinstaller' 不是内部或外部命令……
一、小知识
1.1 exe文件?
EXE File英文全名executable file ,译作可执行文件,可移植可执行 (PE) 文件格式的文件,它可以加载到内存中,并由操作系统加载程序执行,是可在操作系统存储空间中浮动定位的可执行程序。
1.2为什么要打包为 exe ?
众所周知,Python 程序的运行必须要有 Python 的环境,(因为Python 是解释性语言,它与 C 或者 C++ 等编译型语言不同,C 或者 C++ 都是要编译再运行的。)但是程序编出来怎么方便的给别人使用呢?为了便捷,在电脑上可不安装环境下运行各类文件,这时我们就要将 Python 程序打包为 exe 文件。
1.3打包模块
用 Python 的 Pyinstaller 模块进行打包
网上教程众多,不墨迹,直接实战
二、打包实战
2.1直接在虚拟环境下进行
打开 Anaconda Prompt,激活环境,直接安装好打包库当然可以重新创建一个比较干净的环境,这样打包起来文件会小一些。
2.2切换命令行进入文件路径
因为你要打包的文件在对应的文件夹里面,而 Pyinsatller 一开始是不知道要打包的文件在哪里的,所以要直接切换命令行的路径到目标文件夹路径,使得后面的步骤中,Pyinstaller 可以找到对应的文件。
cd 你程序的路径目录
这里我的打包文件夹放在了桌面上,文件夹名为 py脚本,要打包的 Python 文件在 脚本文件夹内,名为 videocat.py 。于是我的文件夹路径为
2.3代码示例
在代码中有输入输出,压缩率等参数是需要设置的,那就要考虑到打包后的输入输出
2.4修改一下输入输出
把原先写死的路径都换成input让用户自己灵活输入和保存,增加一点点细节即可
import cv2
import argparse
import os
def process_video(i_video, o_video, num, size):
cap = cv2.VideoCapture(i_video)
num_frame = cap.get(cv2.CAP_PROP_FRAME_COUNT) #获取总帧数
print(num_frame)
expand_name = '.jpg'
if not cap.isOpened():
print("Please check the path.")
return
cnt = 0
count = 0
while True: #1:
ret, frame = cap.read()
cnt += 1
if cnt % num == 0:
count += 1
cv2.imwrite(os.path.join(o_video, str(count) + expand_name), frame,[int(cv2.IMWRITE_JPEG_QUALITY), size]) # 设置保存参数,保证高画质---- 默认95
if not ret:
break
cap.release() #释放视频流对象
while True: # 用户设置阶段
try:
i_video_path = input('请输入你的视频文件所在路径(如:F:/新建文件夹,注意是/斜杠和英文冒号):') # 获取视频文件路径
if not os.path.exists(i_video_path): # 判断文件路径是否存在
print('你输入的文件路径有误,请重新输入!')
else:
print('————文件路径匹配成功!🚀🚀————')
break
except NameError:
print('重输路径')
while True:
try:
video_name = input('请输入你的mp4视频文件名(不需要加后缀,如:我的视频):') # 获取视频文件名
video = i_video_path + "/" + video_name + ".mp4" # 格式 avi
if not os.path.exists(video) or video_name == '':
print('你输入的文件名有误,请重新输入!')
if os.path.exists(video) and video_name != '':
print('————视频文件匹配成功!————')
break
except ValueError:
print('重置路径!')
while True:
try:
o_video_path = input('请输入保存视频文件所在路径(如:F:/新建文件夹,注意是/斜杠和英文冒号):') # 获取视频文件路径
if not os.path.exists(o_video_path): # 判断文件路径是否存在
print('文件不存在,请重新输入!')
else:
print('————文件路径匹配成功!🚀🚀————')
break
except NameError:
print('重来')
while True:
try:
num = int(input('请输入你想要的帧数):')) # 获取用户的帧率需求,只限数字
if num < 0:
print('帧数不能为负!')
elif num == 0:
print('帧数不能为0!')
else:
print('————截图速率已成功设置为' + str(num) + '帧一张!🚀————')
break
except ValueError:
print('————截图速率已自动设置为默认的' + str(num) + '帧一张!————')
break
while True:
try:
size = int(input('请输入你想要的图片压缩质量,不输入则默认设置为100):'))
if size < 0:
print('不能为负!')
elif size == 0:
print('不能为0!')
else:
print('————压缩比已成功设置为' + str(size) + '!🚀————')
break
except ValueError:
print('默认压缩质量' + str(size) + 'quality')
break
process_video(video, o_video_path, num, size)
2.5打包环节
把输入输出写好了整个程序就可以开始打包,
在环境中使用刚刚安装好的库命令
Pyinstaller -option1 -option2 -待打包文件
例如pyinstaller -F xx.py
命令大概有如下部分
参数选项 | 描述 |
-F, -onefile | 只生成一个单个文件(只有一个 exe 文件) |
-D, -onedir | 打包多个文件,在dist中生成很多依赖文件,适合以框架形式编写工具代码,这样代码易于维护 |
-K, –tk | 在部署时包含 TCL/TK |
-a, -ascii | 不包含编码在支持 Unicode 的 Python 版本上默认包含所有的编码 |
-d, -debug | 产生 debug 版本的可执行文件 |
-w, -windowed, -noconsole | 使用 Windows 子系统执行 当程序启动的时候不会打开命令行(只对 Windows 有效) |
-c, -nowindowed, -console | 使用控制台子系统执行(默认)(只对 Windows 有效) pyinstaller -c xxxx.py pyinstaller xxxx.py --console |
-s, -strip | 可执行文件和共享库将 run through strip 注意 Cygwin 的 strip 往往使普通的 win32 Dll 无法使用 |
-X, -upx | 如果有 UPX 安装(执行 Configure.py 时检测),会压缩执行文件( Windows 系统中的 DLL 也会) |
-o DIR, -out=DIR | 指定 spec 文件的生成目录,如果没有指定,而且当前目录是 PyInstaller 的根目录,会自动创建一个用于输出( spec 和生成的可执行文件)的目录 如果没有指定,而当前目录不是 Pyinstaller 的根目录,则会输出到当前的目录下 |
-p DIR, -path=DIR | 设置导入路径(和使用 PYTHONPATH 效果相似) 可以用路径分割符( Windows 使用分号,Linux 使用冒号)分割,指定多个目录 也可以使用多个 -p 参数来设置多个导入路径,让 pyinstaller 自己去找程序需要的资源 |
-i -icon=<FILE.ICO> | 将 file.ico 添加为可执行文件的资源(只对 Windows 系统有效),改变程序的图标 |
-i -icon=<FILE.EXE,N> | 将 file.exe 的第 n 个图标添加为可执行文件的资源(只对 Windows 系统有效) |
-v FILE, -version=FILE | 将 verfile 作为可执行文件的版本资源(只对 Windows 系统有效) |
-n NAME, -name=NAME | 可选的项目(产生的 spec 的)名字 如果省略,第一个脚本的主文件名将作为 spec 的名字 |
太多参数太麻烦那直接走起,
比如我就打包单个程序然后加上自己的图标,
其中Pyinstaller的参数,其中-F参数代表制作独立的可执行程序。
-w是指程序启动的时候不会打开命令行。
最后的-i car.ico就是指设置自己的图标图案,
pyinstaller -F -i car.ico videocat.py
2.6制作图标
因为默认打包图片是下图这样的
直接引用这个博主this和推荐的网站ICO转换器 - ICO图片格式在线转换 - 迅捷PDF转换器在线版(https://app.xunjiepdf.com/img2icon/)来生成ico图标
选一下格式,选一下尺寸,转换完得到ico图标,用刚刚的命令直接打包
看到successfully即成功打包完毕。
2.7打包位置
回到最初切换的文件夹里,我们可以看到,多了下面三个文件(build 文件夹、dist 文件夹和 spec 文件):
exe 文件就在新生成的 dist 文件夹里面。
有可能文件比较大,这就是说创建给干净的环境好一些,毕竟打包时把库文件都带过来了。需要较小文件包的话可以自行删除不需要的库文件。
2.8检查exe文件
找到项目中的 dist 文件夹,运行打包好的exe文件,输入路径,成功截取。
三、疑难情况
3.1打包过程
如果程序内有输出内容,或者输入内容,比如路径相关,要开启控制台,不用隐藏,不然可能出现下列问题:
raise error(exception.winerror, exception.function, exception.strerror)
win32ctypes.pywin32.pywintypes.error: (225, 'BeginUpdateResourceW', '无法成功完成操作,因为文件包含病毒或潜在的垃圾软件 。')
起始就是没有打开控制台,输入了-w命令造成的
3.2复习一遍常用命令
1. 只打一个py文件 --onefile
1 |
|
2. 添加图标文件夹 --add-data
1 |
|
3. 不带控制台 -w 或 --noconsole
1 |
|
4. 排除某些依赖 --exclude-module xxpackagename 如果有多个,就重复
1 |
|
5. 设定exe的logo.ico
1 |
|
3.3图标未显示问题
有人可能发现图标并未更改,还是默认的蟒蛇,
不用担心,这是windows图标显示的问题,在文件查看中选择大图标/中图标即可,这就刚刚生成的ico图标大小问题。
更改大小图标,这不就来了。
最后附上其人的小建议,参考文章
四、其他建议
4.1.1 模块找不到的错误 —— ModuleNotFoundError
这与你的打包方式有关,有些打包方式会出现这种情况,了解 Pyinstaller 的机制会有一定帮助。
Pyinstaller 打包后程序运行机制和直接用 Python 解释器相比,在源代码文件查找方面有一点不同,Python 解释器是在工程目录下查找源代码文件和资源文件,但是 Pyinstaller 如果是将所有文件打包成一个可执行文件,而没有其他的文件,那么它会运行前将源代码文件和资源文件重新生成出来,放在用户临时文件夹中,然后修改工程目录的根目录地址为那个临时文件夹路径,这样 Python 就能找到对应的文件。如果你没有打包好,导致文件没有被打包进 exe,就无法被重新生成,也就导致了 ModuleNotFoundError。
当然,如果你本就不打算将源代码文件和资源文件放进可执行文件里面,而是像一般的软件一样,分别放在各个文件夹中,那就没啥事了,不用考虑上面的情况。此时你出现这种报错,纯粹就是真的缺少对应的模块,如果是用虚拟环境打包的,可能是虚拟环境缺少对应的模块,如果不是,那么可能是你不小心把什么东西给删除了。
4.1.2 图形化程序运行没反应,但也没有报错
此时应该看看你打包时有没有加上 -w 命令。-w 的作用是将运行时出现的终端隐藏,但是所有的报错信息一般都是出现那里面的,你把它隐藏了肯定就看不到了,因此你应该将这个命令删去后打包,然后运行,查看报错信息,彻底解决问题后再重新进行打包(此时再把 -w 命令加回来)
4.1.3 语法错误 —— SyntaxError
这种情况,先看看源代码有没有问题(别搞成下面的其他情况中的第一种了),如果没有问题,那可能是你在打包时使用的 Python 版本与源代码运行时版本不一致导致的。简单说,出现了比较高级的语法,低版本 Python 无法解释。比如 Python3.12 用于简化泛型的类型形参语法语法,Python3.11 的类型匹配语法 match 和 Python3.8 的海象运算符等。
但也并不是说高版本就一定能解决问题,或许这个语法错误是解决了,但可能出现一些不兼容的问题,一般是第三方模块导致的,比如第三方包 scipy 的 API 曾经就大幅度修改过。使用对应版本的 Python 解释器非常重要!
4.1.4 'pyinstaller' 不是内部或外部命令……
这种情况一般是你电脑上安装的 Python 非全局环境下的(你可以理解为环境变量有问题)。网上有很多方法解决这个问题,但大多都是要你去改环境变量,这样太麻烦了!既然操作系统无法直接调用它,那让 Python 解释器调用它不就行了?
很简单,Python 的环境变量一般不会有问题,这样写,用全局环境下的 Python 去调用其第三方模块 pyinstaller 即可: