我使用 CustomTkinter 和 Pytube 制作了一个小项目,通过简单的 GUI 下载 YouTube 视频。
如果我双击或使用终端,程序在 IDE 和 Windows 中作为 .py 文件运行时为零错误。
然后我继续使用 auto-py-to-exe 将文件转换为 .exe 文件。我按照 CustomTkinter 网站上的说明进行操作,尽管遇到了一些麻烦,但我还是设法完成了整个过程。
最终的 .exe 文件确实会运行,但只运行一会儿,然后再次关闭。通过从基于文件目录的 cmd 终端运行 .exe,我收到一条错误消息:
Traceback (most recent call last):
File "PyInstaller\hooks\rthooks\pyi_rth_pkgres.py", line 158, in <module>
File "PyInstaller\hooks\rthooks\pyi_rth_pkgres.py", line 36, in _pyi_rthook
File "PyInstaller\loader\pyimod02_importers.py", line 419, in exec_module
File "pkg_resources\__init__.py", line 77, in <module>
ModuleNotFoundError: No module named 'pkg_resources.extern'
[55288] Failed to execute script 'pyi_rth_pkgres' due to unhandled exception!
我无法找到解决方案,所以我到了这里。
您知道什么可能导致此错误吗?或者如果这确实是程序无法正常运行的原因?
完整代码:
import tkinter
import customtkinter
#from pytubefix import YouTube
from tkinter import filedialog
from moviepy.editor import *
from pathvalidate import sanitize_filename
#from pytubefix import Playlist
#from pytubefix.cli import on_progress\
from pytube import *
app = customtkinter.CTk(fg_color="black")
app.geometry("700x550")
app.title("YouTube Download")
app.after(201, lambda :app.iconbitmap("normally would show the path to the file but removed for privacy"))
font = customtkinter.CTkFont(family='Trade Gothic LT Bold Condensed No. 20', size=30)
font2 = customtkinter.CTkFont(family='Trade Gothic LT Bold Condensed No. 20', size=20)
menu = ''
currenttype = ''
def MainMenuGUI():
menu = 'main'
title.grid_forget()
finishLabel.grid_forget()
Vprogbar.grid_forget()
link.grid_forget()
download.grid_forget()
backbutton.grid_forget()
pPercent.grid_forget()
app.grid_rowconfigure(0, weight=1)
app.grid_rowconfigure(1, weight=1)
app.grid_rowconfigure(2, weight=1)
app.grid_columnconfigure(0, weight=1)
app.grid_columnconfigure(1, weight=1)
WhatLabel.grid(row=0, column=0, columnspan=2, padx=100, pady=50)
Videobutton.grid(row=1, column=1, sticky=customtkinter.W, padx=50)
AudioButton.grid(row=1, column=0, sticky=customtkinter.E, padx=50)
PVideobutton.grid(row=2, column=1, sticky=customtkinter.W, padx=50, pady=50)
PAudioButton.grid(row=2, column=0, sticky=customtkinter.E, padx=50, pady=50)
def mp4_to_mp3(mp4, mp3):
mp4_without_frames = AudioFileClip(mp4)
mp4_without_frames.write_audiofile(mp3)
mp4_without_frames.close() # function call mp4_to_mp3("my_mp4_path.mp4", "audio.mp3")
def DownloadGUI(dtype):
global menu
menu = dtype
global currenttype
currenttype = dtype
WhatLabel.grid_forget()
Videobutton.grid_forget()
AudioButton.grid_forget()
PVideobutton.grid_forget()
PAudioButton.grid_forget()
Vprogbar.grid_forget()
pPercent.grid_forget()
Pprogbar.grid_forget()
app.grid_rowconfigure(0, weight=100)
app.grid_rowconfigure(1, weight=10)
app.grid_rowconfigure(2, weight=1)
app.grid_rowconfigure(3, weight=100)
title.grid(row=0, column=0, columnspan=2, sticky=customtkinter.S)
link.grid(row=1, column=0, columnspan=2)
download.grid(row=2, column=0, columnspan=2, sticky=customtkinter.N)
finishLabel.grid(row=3, column=0, columnspan=2, sticky=customtkinter.N)
backbutton.grid(row=3, column=1, columnspan=1)
finishLabel.configure(text='')
if currenttype == "Video" or currenttype == "Audio":
title.configure(text="Insert a YouTube link")
download.configure(command=lambda: startdownload(dtype=currenttype))
else:
title.configure(text="Insert a playlist link")
download.configure(command=lambda: startdownloadP(dtype=currenttype))
link.delete(0, customtkinter.END)
def startdownload(dtype):
try:
ytlink = link.get()
ytobject = YouTube(ytlink, on_progress_callback=Vprog)
title.configure(text=ytobject.title)
finishLabel.configure(text="")
global menu
menu = str(dtype) + 'Download'
path = tkinter.filedialog.askdirectory(initialdir="/", mustexist=True, parent=app)
pPercent.grid(row=1, column=0, columnspan=2, sticky=customtkinter.S)
link.grid_forget()
download.grid_forget()
Vprogbar.grid(row=2, column=0, columnspan=2, sticky=customtkinter.N)
if dtype == "Video":
video = ytobject.streams.get_highest_resolution()
video.download(output_path=str(path))
elif dtype == "Audio":
audio = ytobject.streams.get_audio_only()
if os.path.exists(str(path) + "/" + sanitize_filename(audio.title) + ".mp4"):
audio.download(output_path=str(path), filename=sanitize_filename(audio.title) + "1" + ".mp4")
clip = AudioFileClip(str(path) + "/" + sanitize_filename(audio.title) + "1" + ".mp4")
clip.write_audiofile(str(path) + "/" + sanitize_filename(audio.title) + ".mp4"[:-4] + ".mp3")
clip.close()
if os.path.exists(str(path)+"/"+sanitize_filename(audio.title) + "1" + ".mp4"):
os.remove(str(path)+"/"+sanitize_filename(audio.title) + "1" + ".mp4")
else:
audio.download(output_path=str(path), filename=sanitize_filename(audio.title)+".mp4")
clip = AudioFileClip(str(path)+"/"+sanitize_filename(audio.title)+".mp4")
clip.write_audiofile(str(path)+"/"+sanitize_filename(audio.title)+".mp4"[:-4] + ".mp3")
clip.close()
if os.path.exists(str(path)+"/"+sanitize_filename(audio.title)+".mp4"):
os.remove(str(path)+"/"+sanitize_filename(audio.title)+".mp4")
finishLabel.configure(text="downloaded", text_color="white")
except:
finishLabel.configure(text="Download has failed", text_color="red")
title.configure(text="Insert a YouTube link")
Vprogbar.grid_forget()
link.grid(row=1, column=0, columnspan=2)
def startdownloadP(dtype):
vcount = 0
vccount = 0
playlink = Playlist(link.get())
path = tkinter.filedialog.askdirectory(initialdir="/", mustexist=True, parent=app)
pPercent.grid(row=1, column=0, columnspan=2, sticky=customtkinter.S)
ppPercent.grid(row=3, column=0, columnspan=2, sticky=customtkinter.N, pady=20)
link.grid_forget()
download.grid_forget()
Vprogbar.grid(row=2, column=0, columnspan=2, sticky=customtkinter.N)
Pprogbar.grid(row=3, column=0, columnspan=2, sticky=customtkinter.N, pady=10)
for _ in playlink.videos:
vcount += 1
Pprog(vcount, 0)
for vid in playlink.videos:
vccount += 1
Pprog(vcount, vccount)
vid.register_on_progress_callback(Vprog)
title.configure(text=vid.title)
global menu
menu = str(dtype) + 'Download'
if dtype == "VideoPlaylist":
video = vid.streams.get_highest_resolution()
video.download(output_path=str(path))
elif dtype == "AudioPlaylist":
audio = vid.streams.get_audio_only()
if os.path.exists(str(path) + "/" + sanitize_filename(audio.title) + ".mp4"):
audio.download(output_path=str(path), filename=sanitize_filename(audio.title) + "1" + ".mp4")
clip = AudioFileClip(str(path) + "/" + sanitize_filename(audio.title) + "1" + ".mp4")
clip.write_audiofile(str(path) + "/" + sanitize_filename(audio.title) + ".mp4"[:-4] + ".mp3")
clip.close()
if os.path.exists(str(path) + "/" + sanitize_filename(audio.title) + "1" + ".mp4"):
os.remove(str(path) + "/" + sanitize_filename(audio.title) + "1" + ".mp4")
else:
audio.download(output_path=str(path), filename=sanitize_filename(audio.title) + ".mp4")
clip = AudioFileClip(str(path) + "/" + sanitize_filename(audio.title) + ".mp4")
clip.write_audiofile(str(path) + "/" + sanitize_filename(audio.title) + ".mp4"[:-4] + ".mp3")
clip.close()
if os.path.exists(str(path) + "/" + sanitize_filename(audio.title) + ".mp4"):
os.remove(str(path) + "/" + sanitize_filename(audio.title) + ".mp4")
pPercent.grid_forget()
ppPercent.grid_forget()
Vprogbar.grid_forget()
Pprogbar.grid_forget()
finishLabel.grid(row=2, column=0, columnspan=2, sticky=customtkinter.N)
finishLabel.configure(text="All videos downloaded", text_color="white")
def Vprog(stream, chunk, bytes_remaining):
total_size = stream.filesize
bytes_downloaded = total_size - bytes_remaining
percentage_complete = bytes_downloaded / total_size * 100
per = str(int(percentage_complete))
pPercent.configure(text=per + "%")
pPercent.update()
Vprogbar.set(float(percentage_complete / 100))
pPercent.update()
Vprogbar.update()
def Pprog(total, current):
percentage_done = current / total * 100
per = str(int(percentage_done))
ppPercent.configure(text=per + "%")
Pprogbar.set(float(percentage_done / 100))
Pprogbar.update()
def Back():
if 'Download' in menu:
DownloadGUI(menu[:-8])
else:
MainMenuGUI()
urlvar = tkinter.StringVar()
title = customtkinter.CTkLabel(app, text="Insert a YouTube link", fg_color='White',corner_radius=10, padx=50, font=font)
link = customtkinter.CTkEntry(app, width=350, height=40, textvariable=urlvar)
finishLabel = customtkinter.CTkLabel(app, text="", text_color="white")
pPercent = customtkinter.CTkLabel(app, text="0%", text_color="white")
ppPercent = customtkinter.CTkLabel(app, text="0%", text_color="white")
Vprogbar = customtkinter.CTkProgressBar(app, width=400, progress_color="red")
Pprogbar = customtkinter.CTkProgressBar(app, width=400, progress_color="red")
download = customtkinter.CTkButton(app, text="Download", command=lambda: startdownload(dtype=currenttype), fg_color="#e8e6e6", text_color="black", hover_color='#c0c0c0')
Vprogbar.set(0)
Pprogbar.set(0)
backbutton = customtkinter.CTkButton(app, text_color='black', text="back", width=50, height=50, fg_color='#333333', hover_color='#c0c0c0', command=Back)
WhatLabel = customtkinter.CTkLabel(app, text="What would you like to download?", fg_color='White',corner_radius=10, padx=50, font=font)
Videobutton = customtkinter.CTkButton(app, text='Video', width=250, height=150, font=font2, fg_color='#b01214', hover_color='#590404', command=lambda: DownloadGUI(dtype='Video'))
AudioButton = customtkinter.CTkButton(app, text='Audio', width=250, height=150, font=font2, fg_color='#b01214', hover_color='#590404', command=lambda: DownloadGUI(dtype='Audio'))
PVideobutton = customtkinter.CTkButton(app, text='Video Playlist', width=250, height=150, font=font2, fg_color='#b01214', hover_color='#590404', command=lambda: DownloadGUI(dtype='VideoPlaylist'))
PAudioButton = customtkinter.CTkButton(app, text='Audio Playlist', width=250, height=150, font=font2, fg_color='#b01214', hover_color='#590404', command=lambda: DownloadGUI(dtype='AudioPlaylist'))
#https://www.youtube.com/watch?v=cPAlmXHMktA
#https://www.youtube.com/playlist?list=PLpi4n5vOXXFkJxTSD8VRuZ9phHmojXaP1
#https://www.youtube.com/watch?v=Ga2PA-vEiFk
#https://www.youtube.com/watch?v=QU8pe3dhz8s&list=PLpi4n5vOXXFkJxTSD8VRuZ9phHmojXaP1&index=10
MainMenuGUI()
app.mainloop()
我不知道该怎么办,因为说实话,我对我正在使用的库的背景情况没有太多了解,而且谷歌搜索这个问题似乎没有答案。
根据这篇博文,修复应该很容易。要么是这个:
这意味着特定模块(在本例中为“x”)未添加到包中。我在 pandas 库和 win32api 中的包中看到过这种情况;只要你能识别包(例如“x”),那么修复就很容易了。
要在 UI 中修复此问题,请打开高级选项卡并找到 --hidden-import 输入。只需将模块名称粘贴到此输入中,然后重新打包即可。如果仍然出现原来的错误,则说明您的操作不正确。
例如,如果您缺少 pandas._libs.tslib,请通过 --hidden-import 将“pandas._libs.tslib”添加到输入中。此外,您可以添加多个模块,例如 pandas._libs.tslib、win32api。 (有关更多信息,请参阅输入旁边的问号)。
或者这个:
或者,您可能已在一个 Python 环境中安装了 auto-py-to-exe(单个安装或 venv),并在不同的 Python 环境中安装了依赖包。请参阅 “如何管理多个 Python 发行版”,以获取有关如何确定您是否已执行此操作的帮助。