You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Tkinter与Pytube的YouTube下载器TypeError错误求助

YouTube视频下载器TypeError错误解决指南

嘿,我来帮你搞定这个问题!你遇到的TypeError: unsupported operand type(s) for -: 'int' and 'NoneType'错误,主要是两个小细节没处理好,咱们一步步捋清楚:

错误原因分析

  1. 进度回调函数参数不匹配
    Pytube的on_progress_callback回调函数现在的标准参数格式是(stream, chunk, bytes_remaining),但你写的progress函数参数是stream= None, chunk=None, file_handle = None, remaining=None,参数顺序和名称不对,导致remaining拿到的是None。当你执行fileSizeInBytes - remaining时,就触发了“整数减None”的类型错误。

  2. 480p视频选择的小疏忽
    在选择480p视频的代码里,你写了selectVideo = yt.streams.filter(progressive=True, file_extension='mp4').last,这里的last是一个方法,必须加括号调用last(),不然selectVideo会变成一个方法对象而不是实际的视频流对象,后续也会引发问题。

修复方案

1. 修改进度回调函数

把progress函数改成下面这样,参数完全对应Pytube的要求:

def progress(stream, chunk, bytes_remaining):
    # 计算已下载百分比
    percent = (100 * (fileSizeInBytes - bytes_remaining)) / fileSizeInBytes
    print('{:.2f}% downloaded'.format(percent))

2. 修复480p视频选择代码

把480p选项里的last改成last():

elif (choice == downloadChoices[2]):
    print('480p video is downloading...')
    loadingLabel.config(text='480p video file downloading...')
    selectVideo = yt.streams.filter(progressive=True, file_extension='mp4').last()  # 这里加括号

完整修复后的代码

from tkinter import *
from tkinter import ttk
from tkinter import filedialog
from pytube import YouTube

FolderName = ''
fileSizeInBytes = 0
MaxFileSize = 0

def openDirectory():
    global FolderName
    FolderName = filedialog.askdirectory()
    if (len(FolderName)> 1):
        fileLocationLabelError.config(text=FolderName, fg='green')
    else:
        fileLocationLabelError.config(text='Please Choose Folder', fg='red')

def DownloadFile():
    global MaxFileSize,fileSizeInBytes
    choice = youtubeChoices.get()
    video = youtubeEntry.get()
    if (len(video)>1):
        youtubeEntryError.config(text='')
        print(video,'at',FolderName)
        yt = YouTube(video,on_progress_callback=progress)
        print('video name is:\n\n',yt.title)

        if (choice == downloadChoices[0]):
            print('1080p video is downloading...')
            loadingLabel.config(text='1080p video file downloading...')
            selectVideo =yt.streams.filter(progressive=True).first()
        elif (choice == downloadChoices[1]):
            print('720p video is downloading...')
            loadingLabel.config(text='720p video file downloading...')
            selectVideo =yt.streams.filter(progressive=True).first()
        elif (choice == downloadChoices[2]):
            print('480p video is downloading...')
            loadingLabel.config(text='480p video file downloading...')
            selectVideo = yt.streams.filter(progressive=True, file_extension='mp4').last()  # 修复:添加括号
        elif (choice == downloadChoices[3]):
            print('3gp file is downloading...')
            selectVideo = yt.streams.filter(file_extension='3gp').first()
        elif (choice == downloadChoices[4]):
            print('Audio file is downloading...')
            selectVideo = yt.streams.filter(only_audio=True).first()

        fileSizeInBytes = selectVideo.filesize
        MaxFileSize = fileSizeInBytes / 1024000
        MB = str(MaxFileSize) + 'MB'
        print('File size = : {:.2f}MB'.format(MaxFileSize))  # 优化显示格式
        # 开始下载
        selectVideo.download(FolderName)
        print('Downloaded on : {}'.format(FolderName))
        complete()
    else:
        youtubeEntryError.config(text='Please paste youtube link', fg='red')

# 修复:调整回调函数参数匹配Pytube要求
def progress(stream, chunk, bytes_remaining):
    percent = (100 * (fileSizeInBytes - bytes_remaining)) / fileSizeInBytes
    print('{:.2f}% downloaded'.format(percent))

def complete():
    loadingLabel.config(text='Download completed')

root = Tk()
root.title('YouTube video Downloader')
root.grid_columnconfigure(0,weight=1)

youtubeLinkLabel = Label(root,text='Please paste youtube link here..', fg='blue',font=('Agency FB',30))
youtubeLinkLabel.grid()

youtubeEntryvar = StringVar()
youtubeEntry = Entry(root,width=50, textvariable=youtubeEntryvar)
youtubeEntry.grid(pady=(0,20))

youtubeEntryError = Label(root,fg='red', text='',font=('Agency FB',20))
youtubeEntryError.grid(pady=(0,10))

SaveLabel = Label(root,text='Where to download file?',fg='blue',font=('Agency FB',20,'bold'))
SaveLabel.grid()

SaveEntry = Button(root,width=20,bg='green',fg='white', text='Choose folder',font=('Arial',15), command=openDirectory)
SaveEntry.grid()

fileLocationLabelError = Label(root,text='',font=('Agency FB',20))
fileLocationLabelError.grid(pady=(0,0))

youtubeChooseLabel = Label(root,text='Please choose what to download:', font=('Agency FB',20))
youtubeChooseLabel.grid()

downloadChoices = ['Mp4 1080p', 'Mp4 720p', 'Mp4 480p', 'Video 3gp', 'song mp3']
youtubeChoices = ttk.Combobox(root,values=downloadChoices)
youtubeChoices.grid()

downloadButton = Button(root,text='Download',width=15,bg='green', command=DownloadFile)
downloadButton.grid()

loadingLabel = ttk.Label(root,text='App developed by |> CID', font=('Agency FB',20))
loadingLabel.grid()

root.mainloop()

额外小优化

我还帮你调整了文件大小的打印格式,从{:00.00f}改成了{:.2f},这样能显示更合理的小数位数,比如97.5MB而不是只显示整数97。

内容的提问来源于stack exchange,提问作者Aynur Jumageldiyeva

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.09 00:07:38