使用Pytube下载YouTube视频时部分分辨率无法下载的问题
问题描述
我在用Python编写YouTube音视频下载脚本,视频下载功能存在异常:部分分辨率(如1080p)可正常下载,但选择480p这类分辨率时会报错:'NoneType' object has no attribute 'download'。我希望能下载视频支持的任意分辨率,请问下载脚本哪里有遗漏?
相关代码
下载函数:
def VideoDownload_mp4(url, res): try: yt = pytube.YouTube(url) folder = "YouTube Videos" video = yt.streams.get_by_resolution(resolution=res) video.download(folder) print("downloaded.") except Exception as e: print(f"Error: {e}")
获取可用分辨率的函数:
def GetVideoQuality(url): yt = pytube.YouTube(url) base_list = [] for stream in yt.streams: resolution = stream.resolution bitrate = stream.bitrate base_list.append({'resolution':resolution, 'bitrate':bitrate}) new_dict = {} fixed_list = [] for diccionario in base_list: resolution = diccionario['resolution'] bitrate = diccionario['bitrate'] if resolution is not None: if resolution not in new_dict: new_dict[resolution] = bitrate fixed_list.append(diccionario.copy()) else: if bitrate > new_dict[resolution]: new_dict[resolution] = bitrate fixed_list.remove([d for d in fixed_list if d['resolution'] == resolution][0]) fixed_list.append(diccionario.copy()) return fixed_list
示例参数:
- url =
"https://youtu.be/YEqWLCBrgic?si=Z245EINTenbGqasr" - res =
"720p"
问题原因
get_by_resolution()方法仅能匹配视频+音频合并的流,但YouTube的中低分辨率(如480p)往往没有合并流,而是拆分为纯视频流和纯音频流两个独立文件。此时get_by_resolution()找不到对应合并流,会返回None,调用download()自然触发报错。
另外你的分辨率获取脚本会列出所有带分辨率的流(包括纯视频流),但这些流无法通过get_by_resolution()获取,导致你选中的部分分辨率实际无对应合并流可下载。
解决方案
修改下载逻辑,优先匹配合并流;若不存在,则下载对应分辨率的纯视频流+最高质量音频流,再通过ffmpeg合并两者。
方案1:兼容合并流与分离流的下载函数
from pytube import YouTube import os import subprocess def VideoDownload_mp4(url, res): try: yt = YouTube(url) folder = "YouTube Videos" os.makedirs(folder, exist_ok=True) # 优先尝试下载对应分辨率的合并流 video_stream = yt.streams.filter(progressive=True, resolution=res).first() if video_stream: video_stream.download(folder) print(f"{res} 合并流下载完成") return # 无合并流时,下载纯视频流+音频流 # 获取对应分辨率的最高码率纯视频流 video_stream = yt.streams.filter(adaptive=True, resolution=res, only_video=True).order_by('bitrate').desc().first() # 获取最高质量音频流 audio_stream = yt.streams.filter(only_audio=True).order_by('bitrate').desc().first() if not video_stream: print(f"找不到 {res} 分辨率的视频流") return if not audio_stream: print("找不到音频流") return # 下载临时文件 video_path = video_stream.download(folder, filename_prefix="temp_video_") audio_path = audio_stream.download(folder, filename_prefix="temp_audio_") # 用ffmpeg合并视频与音频(需提前安装ffmpeg并加入系统PATH) output_filename = f"{yt.title}_{res}.mp4" output_path = os.path.join(folder, output_filename) subprocess.run([ "ffmpeg", "-i", video_path, "-i", audio_path, "-c:v", "copy", "-c:a", "aac", "-y", output_path ], check=True) # 删除临时文件 os.remove(video_path) os.remove(audio_path) print(f"{res} 视频+音频合并完成,保存至 {output_path}") except Exception as e: print(f"错误: {e}")
方案2:优化分辨率获取脚本(仅显示可直接下载的合并流)
如果你希望用户只选择存在合并流的分辨率,可以修改获取函数:
def GetVideoQuality(url): yt = YouTube(url) # 仅获取合并流的分辨率,去重后按清晰度从高到低排序 resolutions = sorted( list({stream.resolution for stream in yt.streams.filter(progressive=True) if stream.resolution}), key=lambda x: int(x[:-1]), reverse=True ) # 转换为原字典格式返回 fixed_list = [] for res in resolutions: stream = yt.streams.filter(progressive=True, resolution=res).order_by('bitrate').desc().first() fixed_list.append({'resolution': res, 'bitrate': stream.bitrate}) return fixed_list
注意事项
- 使用方案1的合并逻辑时,需提前安装
ffmpeg,并确保其在系统环境变量PATH中。 - pytube可能因YouTube接口更新出现兼容性问题,建议定期更新:
pip install --upgrade pytube
内容的提问来源于stack exchange,提问作者ZeloZalis
相关产品推荐
相关产品推荐

