Python YouTube API脚本调试:解决KeyError及优化需求
问题分析与解决方案
错误原因
你的KeyError: 'videoId'是因为YouTube Data API的search.list接口返回的结果不仅包含视频,还可能包含频道、播放列表等类型条目,这些条目的id字段里没有videoId,只有channelId或playlistId,直接提取会报错。
另外原脚本还有几个逻辑问题:
youtube_search函数中,return videos_with_view_counts之后的代码永远不会执行- 返回的
videos_with_view_counts仅包含视频ID和观看数,但main函数里试图访问snippet等不存在的字段,会引发新错误 - 当前用
search.list是搜索特定关键词的结果,并非全平台热门视频
修复与优化方案
1. 核心修复:过滤视频类型条目
在提取videoId前,先判断条目类型为youtube#video:
ids = [item["id"]["videoId"] for item in search_response["items"] if item["id"]["kind"] == "youtube#video"]
2. 全平台热门视频抓取
改用videos.list接口,指定chart="mostPopular"参数,直接获取全YouTube热门视频,无需搜索关键词:
videos_response = youtube.videos().list( part="snippet,statistics,channelStatistics", chart="mostPopular", maxResults=options.max_results, regionCode="US" # 可指定地区,默认全球 ).execute()
3. 加权排序实现
自定义权重公式(可按需调整),例如:加权分 = 观看数*0.5 + 点赞数*0.3 + 频道订阅数*0.2
对视频列表按加权分降序排序(热门内容在前)
4. 其他优化
- 将API密钥改为命令行参数传入,避免硬编码
- 处理缺失字段(如部分视频无点赞数,设默认值0)
- 写入总观看数到单独文件
- 完善API请求错误处理
完整优化脚本
import csv import os import argparse from googleapiclient.discovery import build from googleapiclient.errors import HttpError def get_top_youtube_videos(api_key, max_results, region_code="US"): youtube = build( "youtube", "v3", developerKey=api_key ) try: # 获取全平台热门视频,包含标题、统计数据、频道订阅数 videos_response = youtube.videos().list( part="snippet,statistics,channelStatistics", chart="mostPopular", maxResults=max_results, regionCode=region_code ).execute() except HttpError as e: print(f"API请求错误: {e}") return [] videos_data = [] total_views = 0 for item in videos_response["items"]: # 提取基础信息 video_id = item["id"] title = item["snippet"]["title"] view_count = int(item["statistics"].get("viewCount", 0)) like_count = int(item["statistics"].get("likeCount", 0)) # 频道订阅数 subscriber_count = int(item["channelStatistics"].get("subscriberCount", 0)) total_views += view_count # 计算加权分(权重可自定义) weighted_score = (view_count * 0.5) + (like_count * 0.3) + (subscriber_count * 0.2) videos_data.append({ "title": title, "videoId": video_id, "viewCount": view_count, "likeCount": like_count, "subscriberCount": subscriber_count, "weightedScore": weighted_score }) # 按加权分降序排序 videos_data.sort(key=lambda x: x["weightedScore"], reverse=True) return videos_data, total_views def main(): parser = argparse.ArgumentParser(description='抓取YouTube热门视频并分析') parser.add_argument("--api-key", required=True, help="YouTube Data API密钥") parser.add_argument("--max-results", type=int, default=25, help="返回结果数量") parser.add_argument("--region-code", default="US", help="地区代码,如CN、US") args = parser.parse_args() # 获取视频数据 videos_data, total_views = get_top_youtube_videos(args.api_key, args.max_results, args.region_code) if not videos_data: print("未获取到视频数据") return # 写入CSV文件 csv_path = 'top_youtube_videos.csv' try: if os.path.exists(csv_path): os.remove(csv_path) except OSError: pass with open(csv_path, 'w', encoding='utf-8', newline='') as csvfile: fieldnames = ['title', 'videoId', 'viewCount', 'likeCount', 'subscriberCount', 'weightedScore'] writer = csv.DictWriter(csvfile, fieldnames=fieldnames) writer.writeheader() for video in videos_data: print(f"标题: {video['title']}") print(f"观看数: {video['viewCount']:,}") print(f"点赞数: {video['likeCount']:,}") print(f"频道订阅数: {video['subscriberCount']:,}") print(f"加权分: {video['weightedScore']:.2f}") print(f"视频ID: {video['videoId']}\n") writer.writerow(video) # 写入总观看数到文件 with open('total_views.txt', 'w') as f: f.write(f"总观看数: {total_views:,}") print(f"数据已写入 {csv_path} 和 total_views.txt") if __name__ == "__main__": main()
关键说明
- API调用:使用
videos.list的chart=mostPopular直接获取热门视频,比search.list更匹配你的需求 - 字段处理:用
.get()方法处理可能缺失的统计字段,避免KeyError - 加权排序:权重比例可根据分析需求调整,比如若更看重订阅数,可提高其权重占比
- 命令行参数:通过
--api-key传入密钥,更安全灵活 - 编码处理:写入CSV时指定
encoding='utf-8',避免非ASCII字符乱码
内容的提问来源于stack exchange,提问作者puppet_master
相关产品推荐
相关产品推荐

