「見たいYouTubeチャンネルが多すぎて、時間が足りない」と感じていませんか。
私も情報収集のために多くのチャンネルを登録していますが、毎日すべてを視聴するのは困難でした。
そこで、PythonとGemini APIを使い、お気に入りのチャンネルが更新されたら自動で動画を要約し、Markdownファイルとして出力する仕組みを作りました。この方法で、動画の概要を素早く把握し、視聴時間を大幅に短縮できています。
この記事では、「PythonとGeminiAPIを使ってYouTubeの情報収集を効率化したい」「特定チャンネルの動画を自動で要約させたい」と考えている方に向けて、私が実践している具体的なスクリプトと、その仕組みを解説します。
PythonとGemini APIでYouTubeを自動要約してみた
まずは、今回構築するシステムで何ができるのか、どのような技術を使うのかを整理します。
この記事でできること
この記事で紹介するPythonスクリプトを実行すると、以下の4つが自動で可能になります。
- 指定したYouTubeチャンネルの最新動画を定期的にチェックします。
- 新しい動画がアップロードされていたら、その動画の字幕データを取得します。
- 取得した字幕と動画情報をGemini APIに送信し、日本語の要約を生成させます。
- 生成された要約を、動画情報と共にMarkdownファイルとして指定フォルダに保存します。
使う技術(Python/Gemini API/YouTube Transcript API)
今回のシステムは、3つの主要な技術で成り立っています。
- Python: メインとなるプログラミング言語です。各種APIを連携させ、全体の処理を自動化するスクリプトを記述します。
- Gemini API: Googleが提供する最新の生成AIモデルです。今回は、YouTubeの字幕データから高精度な要約を生成するためにGeminiAPIを利用します。
- YouTube Data API v3: Googleが提供するAPIで、特定チャンネルの動画リストや、動画の詳細情報(タイトル、説明、統計など)を取得するために使います。
- YouTube Transcript API (Pythonライブラリ): YouTube動画の字幕データを簡単に取得できるサードパーティ製のPythonライブラリです。公式APIではありませんが、非常に便利です。
どんな課題を解決できるのか
この仕組みが解決するのは、ズバリ「情報収集の時短」です。
私自身、見たいyoutubeチャンネルが多すぎることが悩みでした。有益な情報が詰まった動画でも、1本あたり15分や30分、時には1時間を超えるものもあります。すべてを視聴していては、時間がいくらあっても足りません。
しかし、このシステムを導入してからは、動画がアップロードされたら自動で要約がMarkdownファイルに出力されるようになりました。
メモを読むだけで、動画の主要なポイントを5分ほどで把握できます。「これは詳しく見るべきだ」と判断した動画だけを、後でじっくり視聴すれば良いため、動画閲覧の時間を劇的に短縮できました。
YouTube要約スクリプトの仕組み
システムがどのような流れで動作するのか、その仕組みを分解して解説します。全体のプロセスは大きく4つのステップに分かれています。
YouTubeの字幕データを取得する方法
要約の元データとなる「字幕」の取得が、このシステムの肝です。
最初に、YouTube Data APIを使い、指定したチャンネルIDから最新の動画リストを取得します。次に、新しく発見した動画のIDを使い、YouTube Transcript APIにリクエストを送ります。
このライブラリが、動画に付与されている字幕データをテキストとして抽出してくれます。
字幕データが存在しない動画(例: 字幕オフ、音楽のみの動画)の場合、このステップはスキップされ、要約も主にタイトルと説明欄から生成されます。
Gemini APIに要約をリクエストする処理
字幕テキストが取得できたら、いよいよGemini APIの出番です。
取得した「動画タイトル」「動画の説明文」、そして「字幕テキスト」をひとまとめにします。これらを、あらかじめ定義したプロンプト(指示文)と一緒にGemini APIに送信します。
プロンプトには「以下の情報を要約してください」「主要ポイントを3点でまとめてください」といった具体的な指示を含めます。GeminiAPIは、受け取った情報を基に、自然な日本語の要約テキストを生成して返します。
メモ(テキストファイル)への書き出し処理
Gemini APIが生成した要約テキストを受け取ったら、それをローカルのファイルとして保存します。
今回のコードでは、読みやすさと管理のしやすさを考慮し、Markdown形式で出力します。
ファイルには、Geminiによる要約内容だけでなく、元の動画タイトル、投稿日、チャンネル名、動画URL、統計情報(再生回数など)も一緒に記録します。これにより、後からメモを見返したときに、元の動画をすぐに見つけ出せるようになります。
全体のコード構成と実行の流れ
全体の流れをまとめると、以下のようになります。
- スクリプトが起動します。
last_checked_videos.json(前回チェックした動画リスト)を読み込みます。youtube_config.json(APIキーやチャンネルID)を読み込みます。- YouTube Data APIで指定チャンネルの最新動画5件を取得します。
- 取得した動画IDと、前回チェックしたIDリストを比較し、新規動画(まだ処理していない動画)を見つけます。
- 新規動画が見つかった場合、1件ずつ処理ループに入ります。
- YouTube Transcript APIで字幕を取得します。
- Gemini APIでタイトル、説明、字幕を要約します。
- YouTube Data APIで動画の詳細情報(統計など)を取得します。
- 要約結果と動画情報をMarkdownファイルとして
summariesフォルダに保存します。 - 全ての新規動画の処理が終わったら、
last_checked_videos.jsonを最新の動画IDリストで上書き保存します。
このスクリプトを定期的に実行することで、チャンネルの更新を自動で追いかけられます。
実際のコード例と解説
お待たせしました。実際に動作するPythonコードを紹介します。
必要なライブラリと事前準備
このスクリプトを実行するには、いくつかの準備が必要です。
1. Pythonライブラリのインストール
以下のライブラリをpipでインストールしてください。
pip install google-api-python-client google-generativeai youtube-transcript-api2. APIキーの取得
- YouTube Data API v3 キー: Google Cloud Platform (GCP) コンソールから取得が必要です。「YouTube Data API v3」を有効化し、APIキーを発行します。
- Gemini API キー: Google AI Studio から無料で取得できます。
3. 設定ファイルの作成
スクリプトと同じ階層に、youtube_config.jsonという名前のファイルを作成し、以下の内容を記述します。YOUR_の部分はご自身の情報に書き換えてください。
{
"youtube_api_key": "YOUR_YOUTUBE_API_KEY",
"gemini_api_key": "YOUR_GEMINI_API_KEY",
"channel_ids": [
"UC_CHANNEL_ID_1",
"UC_CHANNEL_ID_2"
],
"output_folder": "summaries",
"gemini_model": "gemini-1.5-flash"
}channel_idsには、監視したいYouTubeチャンネルのID(UCから始まる文字列)をリスト形式で複数指定できます。
Pythonコード全文
以下が、YouTubeチャンネルを監視し、新規動画を自動要約するPythonスクリプトの全文です。
import os
import json
import time
import logging
from datetime import datetime, timedelta
from googleapiclient.discovery import build
import google.generativeai as genai
from youtube_transcript_api import YouTubeTranscriptApi
class YouTubeMonitor:
def __init__(self, config_path='youtube_config.json'):
# 設定ファイルから読み込み
with open(config_path, 'r', encoding='utf-8') as f:
config = json.load(f)
self.youtube_api_key = config['youtube_api_key']
self.gemini_api_key = config['gemini_api_key']
if 'channel_ids' in config:
if isinstance(config['channel_ids'][0], dict):
self.channel_ids = [ch['id'] for ch in config['channel_ids']]
else:
self.channel_ids = config['channel_ids']
elif 'channel_id' in config:
self.channel_ids = [config['channel_id']]
else:
raise ValueError("設定ファイルにchannel_idsまたはchannel_idが必要です")
gemini_model = config.get('gemini_model', 'gemini-1.5-flash')
# 出力フォルダ設定(デフォルトは'summaries')
self.output_folder = config.get('output_folder', 'summaries')
# YouTube API設定
self.youtube = build('youtube', 'v3', developerKey=self.youtube_api_key)
# Gemini API設定
genai.configure(api_key=self.gemini_api_key)
self.model = genai.GenerativeModel(gemini_model)
# 最後にチェックした動画IDを保存するファイル
self.last_check_file = 'last_checked_videos.json'
# ロギング設定
self.setup_logging()
def setup_logging(self):
"""ロギングの設定"""
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler('youtube_monitor.log', encoding='utf-8'),
logging.StreamHandler()
]
)
logging.info('YouTube監視システムを起動しました')
def get_latest_videos(self, channel_id, max_results=5):
"""特定チャンネルの最新動画を取得"""
try:
request = self.youtube.search().list(
part='snippet',
channelId=channel_id,
maxResults=max_results,
order='date',
type='video'
)
response = request.execute()
logging.info(f"チャンネル {channel_id} から {len(response['items'])} 件の動画を取得しました")
return response['items']
except Exception as e:
logging.error(f"YouTube API エラー (チャンネル: {channel_id}): {e}")
return []
def get_video_details(self, video_id):
"""動画の詳細情報を取得"""
try:
request = self.youtube.videos().list(
part='snippet,statistics',
id=video_id
)
response = request.execute()
if response['items']:
logging.info(f"動画詳細を取得しました: {video_id}")
return response['items'][0]
else:
logging.warning(f"動画詳細が見つかりません: {video_id}")
return None
except Exception as e:
logging.error(f"動画詳細取得エラー: {e}")
return None
def get_video_transcript(self, video_id):
"""動画の字幕を取得"""
try:
transcript = YouTubeTranscriptApi.get_transcript(video_id, languages=['ja', 'en'])
logging.info(f"字幕を取得しました: {video_id}")
return ' '.join([item['text'] for item in transcript])
except Exception as e:
logging.warning(f"字幕取得エラー({video_id}): {e}")
return None
def summarize_with_gemini(self, title, description, transcript=None):
"""Geminiを使って動画内容を要約"""
try:
# プロンプト作成
content = f"タイトル: {title}\n\n説明: {description}"
if transcript:
content += f"\n\n字幕内容:\n{transcript[:3000]}" # 字幕は3000文字まで
prompt = f"""
以下のYouTube動画の内容を日本語で要約してください。
要約は以下の形式で出力してください:
## 📹 動画要約
### 🎯 主要ポイント
- [主要な内容を3-5点でまとめる]
### 📝 詳細内容
[動画の詳細な内容説明]
### 🔍 キーワード
[関連するキーワードを3-5個]
---
動画情報:
{content}
"""
response = self.model.generate_content(prompt)
logging.info(f"Geminiで要約を生成しました: {title[:30]}...")
return response.text
except Exception as e:
logging.error(f"Gemini API エラー: {e}")
return None
def load_last_checked_videos(self):
"""最後にチェックした動画IDリストを読み込み"""
try:
if os.path.exists(self.last_check_file):
with open(self.last_check_file, 'r', encoding='utf-8') as f:
return set(json.load(f))
return set()
except Exception as e:
logging.error(f"前回チェックファイル読み込みエラー: {e}")
return set()
def save_last_checked_videos(self, video_ids):
"""チェックした動画IDリストを保存"""
try:
with open(self.last_check_file, 'w', encoding='utf-8') as f:
json.dump(list(video_ids), f, ensure_ascii=False, indent=2)
except Exception as e:
logging.error(f"チェックファイル保存エラー: {e}")
def save_summary_to_markdown(self, video_info, summary):
"""要約をMarkdownファイルに保存"""
try:
# 出力フォルダが存在しない場合は作成
os.makedirs(self.output_folder, exist_ok=True)
# ファイル名を作成(日時 + 動画タイトル)
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
safe_title = "".join(c for c in video_info['title'][:30] if c.isalnum() or c in (' ', '-', '_')).strip()
filename = f"{timestamp}_{safe_title}.md"
filepath = os.path.join(self.output_folder, filename)
# Markdownコンテンツを作成
markdown_content = f"""# {video_info['title']}
**投稿日**: {video_info['published_at']}
**チャンネル**: {video_info['channel_title']}
**動画URL**: https://www.youtube.com/watch?v={video_info['video_id']}
---
{summary}
---
## 📊 統計情報
- 視聴数: {video_info.get('view_count', 'N/A')}
- 高評価数: {video_info.get('like_count', 'N/A')}.
- コメント数: {video_info.get('comment_count', 'N/A')}
## 📝 動画説明
{video_info['description'][:500]}{'...' if len(video_info['description']) > 500 else ''}
"""
# ファイルに保存
with open(filepath, 'w', encoding='utf-8') as f:
f.write(markdown_content)
logging.info(f"要約を保存しました: {filepath}")
return filepath
except Exception as e:
logging.error(f"Markdown保存エラー: {e}")
return None
def check_for_new_videos(self):
"""全チャンネルの新規動画をチェックして要約を作成"""
print("新規動画をチェック中...")
last_checked = self.load_last_checked_videos()
all_new_videos = []
all_current_video_ids = set()
# 各チャンネルをチェック
for channel_id in self.channel_ids:
print(f"\nチャンネル {channel_id} をチェック中...")
latest_videos = self.get_latest_videos(channel_id)
for video in latest_videos:
video_id = video['id']['videoId']
all_current_video_ids.add(video_id)
if video_id not in last_checked:
all_new_videos.append(video)
if not all_new_videos:
print("\n新規動画はありませんでした。")
self.save_last_checked_videos(all_current_video_ids)
return
print(f"\n合計 {len(all_new_videos)}件の新規動画を発見しました。")
# 各新規動画を処理
for video in all_new_videos:
video_id = video['id']['videoId']
snippet = video['snippet']
print(f"\n処理中: {snippet['title']}")
video_details = self.get_video_details(video_id)
stats = video_details['statistics'] if video_details else {}
video_info = {
'video_id': video_id,
'title': snippet['title'],
'description': snippet['description'],
'published_at': snippet['publishedAt'],
'channel_title': snippet['channelTitle'],
'view_count': stats.get('viewCount', 'N/A'),
'like_count': stats.get('likeCount', 'N/A'),
'comment_count': stats.get('commentCount', 'N/A')
}
transcript = self.get_video_transcript(video_id)
summary = self.summarize_with_gemini(
video_info['title'],
video_info['description'],
transcript
)
if summary:
self.save_summary_to_markdown(video_info, summary)
else:
print(f"要約の作成に失敗しました: {video_info['title']}")
self.save_last_checked_videos(all_current_video_ids)
print("\n処理完了!")
if __name__ == "__main__":
# 設定ファイルから読み込んで監視システムを初期化
monitor = YouTubeMonitor('youtube_config.json')
monitor.check_for_new_videos()
ポイント解説(エラーハンドリング/APIキー管理)
このコードを運用する上で重要な点を2つ解説します。
APIキーの管理 (youtube_config.json)
コード内にAPIキーを直接書き込むのは非常に危険です。
今回のコードでは、youtube_config.jsonという別のファイルにAPIキーを書き出し、それをPythonスクリプトが読み込む形にしています。
youtube_config.jsonファイルは、GitHubなどのパブリックな場所に絶対にアップロードしないでください。
実行結果と出力サンプル
このスクリプトを実際に実行すると、ターミナルと出力フォルダ(summaries)にどのような結果が得られるかを紹介します。
YouTube動画を自動で要約した結果
スクリプトを実行すると、ターミナルには以下のようなログが表示されます。どのチャンネルをチェックし、どの動画を新規として処理したかがリアルタイムでわかります。
$ python your_script_name.py
2025-11-03 09:40:00,000 - INFO - YouTube監視システムを起動しました
新規動画をチェック中...
チャンネル UC_CHANNEL_ID_1 をチェック中...
2025-11-03 09:40:01,000 - INFO - チャンネル UC_CHANNEL_ID_1 から 5 件の動画を取得しました
チャンネル UC_CHANNEL_ID_2 をチェック中...
2025-11-03 09:40:02,000 - INFO - チャンネル UC_CHANNEL_ID_2 から 5 件の動画を取得しました
合計 1件の新規動画を発見しました。
処理中: 【新機能】Gemini 2.0 が発表されました!
2025-11-03 09:40:03,000 - INFO - 動画詳細を取得しました: video_id_example
2025-11-03 09:40:04,000 - INFO - 字幕を取得しました: video_id_example
2025-11-03 09:40:06,000 - INFO - Geminiで要約を生成しました: 【新機能】Gemini 2.0 が発表...
2025-11-03 09:40:06,100 - INFO - 要約を保存しました: summaries/20251103_094006_新機能Gemini 20 が発表.md
処理完了!生成されたメモファイルの例
summariesフォルダには、以下のようなMarkdownファイル(例: 20251103_094006_新機能Gemini 20 が発表.md)が生成されます。要約と動画情報が一つのファイルにまとまるため、後からの見返しや情報管理が非常に楽になります。
# 【新機能】Gemini 2.0 が発表されました!
**投稿日**: 2025-11-03T09:00:00Z
**チャンネル**: とあるITニュースチャンネル
**動画URL**: https://www.youtube.com/watch?v=video_id_example
---
## 📹 動画要約
### 🎯 主要ポイント
- Googleが新しいAIモデル「Gemini 2.0」を発表しました。
- 従来のモデルと比較し、推論能力と速度が大幅に向上しています。
- 特に日本語の処理精度が改善され、より自然な応答が可能になりました。
### 📝 詳細内容
今回の発表では、Gemini 2.0のアーキテクチャの変更点と、それによるパフォーマンス向上が中心に語られました。開発者向けには新しいAPIエンドポイントが提供され、Flashモデルもアップデートされています。動画では、実際のデモを交えながら新機能が紹介されています。
### 🔍 キーワード
- Gemini 2.0
- Google AI
- 生成AI
- 新機能
---
## 📊 統計情報
- 視聴数: 10500
- 高評価数: 2100.
- コメント数: 350
## 📝 動画説明
本日発表されたGoogleの最新AI、Gemini 2.0について速報でお伝えします!
(...以下、動画の説明文が続く)応用編|自分好みにカスタマイズする方法
提供したコードはあくまで基本形です。ここから、さらに自分好みにカスタマイズするアイデアを2つ紹介します。
出力形式をMarkdownにする
「生成されたメモファイルの例」で示したとおり、このスクリプトは既に出力形式としてMarkdownを採用しています。
Markdown形式の最大の利点は、Obsidian、Notion、VS Codeなど、多くのメモアプリやエディタでそのまま美しく表示・編集できる点です。
もし、save_summary_to_markdown関数のmarkdown_content変数を編集すれば、出力するMarkdownのフォーマットを自由に変更できます。例えば、見出しのレベルを変更したり、特定の情報を追加・削除したりするカスタマイズも簡単です。
自動でObsidianに保存する
もしあなたがメモアプリとしてObsidianを使用しているなら、かなり便利です。
ObsidianはローカルのMarkdownファイルを直接管理する(Vaultと呼ばれるフォルダを監視する)仕組みです。
したがって、youtube_config.jsonのoutput_folder設定を、あなたのObsidian Vault内の特定のフォルダ(例: "output_folder": "C:/Users/YourName/Documents/ObsidianVault/YouTubeSummaries")に変更するだけです。
これだけで、Pythonスクリプトが生成した要約メモが、自動的にObsidianのサイドバーに表示されるようになります。手動でファイルを移動する手間すら不要になり、完全な情報収集の自動化が実現します。
まとめ|GeminiとPythonで情報整理を自動化しよう
この記事では、PythonとGemini API、そしてYouTubeのAPIを組み合わせて、特定チャンネルの最新動画を自動で要約し、メモに出力するシステムを構築する方法を解説しました。
今回のポイントおさらい
今回のシステムのポイントは以下の3点です。
- APIの連携: YouTube Data APIで動画情報を取得し、YouTube Transcript APIで字幕を抽出し、Gemini APIで要約を生成する、という複数のサービスをPythonが繋ぎました。
- 差分チェック:
last_checked_videos.jsonファイルで処理済みの動画を管理し、新規動画のみを対象とすることで、無駄なAPI呼び出しを防ぎます。 - Markdown出力: 要約結果を汎用性の高いMarkdown形式で保存することで、Obsidianなどのナレッジベースとシームレスに連携できます。
私はこのスクリプト毎日自動で実行するように設定しております。要望があれば別記事にまとめようと思います。