YouTube データ活用

YouTube Data APIでチャンネルの動画一覧を取得してCSV保存する方法|Python

2023年12月27日

この記事では、YouTube Data API v3 を使って、指定したチャンネルのアップロード済み動画一覧を取得し、CSVとして保存する方法をPythonで解説します。

最終的には、チャンネルIDを指定して、動画ID・タイトル・公開日・再生回数・高評価数・コメント数・動画時間などを一覧化できる状態を目指します。取得した動画一覧は、投稿頻度の分析、人気動画の可視化、配信アーカイブの抽出、字幕・チャット分析の前処理などに活用できます。

この記事でできること

  • YouTubeチャンネルのアップロード済み動画一覧を取得する
  • チャンネルIDからuploadsプレイリストIDを取得する
  • uploadsプレイリストから動画IDをページング取得する
  • 動画ごとのタイトル・公開日・再生回数・動画時間などを取得する
  • 取得した動画一覧をDataFrame化する
  • CSVとして保存し、後続の分析に使える形にする
  • クォータを意識した取得方法を理解する

想定読者

  • YouTube Data APIでチャンネルの動画一覧を取得したい方
  • VTuberやYouTubeチャンネルの投稿傾向を分析したい方
  • 動画タイトル、公開日、再生回数などをCSVで整理したい方
  • 字幕・チャット・文字起こし分析の前処理として動画一覧を作りたい方

利用上の注意

YouTube Data APIは公式APIですが、利用時にはAPIキーの管理、クォータ制限、取得データの扱いに注意が必要です。

  • APIキーはコードに直書きしたまま公開しないでください。
  • 取得できる情報は、APIで取得可能な公開情報が中心です。
  • 非公開動画、個別ユーザーの視聴履歴、メールアドレスなどは取得できません。
  • APIリクエストにはクォータがあり、無効なリクエストでもクォータを消費します。
  • 取得データを公開する場合は、YouTubeの利用規約、著作権、プライバシーに配慮してください。

事前準備

この記事では、以下を用意します。

  • Google Cloudで作成したプロジェクト
  • YouTube Data API v3を有効化したAPIキー
  • Python 3.10以降
  • PowerShellまたはコマンドプロンプト

APIキーの発行がまだの場合は、先に以下の記事を確認してください。

YouTube Data API v3入門|APIキー発行からPythonで動画情報を取得するまで

必要なライブラリをインストールする

PythonからYouTube Data APIを呼び出し、取得結果をCSV保存するために、以下のライブラリを使います。

pip install -U google-api-python-client pandas python-dotenv isodate
  • google-api-python-client:YouTube Data APIを呼び出すために使用
  • pandas:取得結果をDataFrame化してCSV保存するために使用
  • python-dotenv:APIキーを .env から読み込むために使用
  • isodate:YouTube APIの動画時間を秒数に変換するために使用

.envにAPIキーを保存する

プロジェクトフォルダに .env ファイルを作成し、以下のようにAPIキーを保存します。

YOUTUBE_API_KEY=YOUR_API_KEY

YOUR_API_KEY の部分を、自分のAPIキーに置き換えてください。

.env ファイルは、GitHubなどの公開リポジトリにアップロードしないようにしてください。APIキー管理については、以下の記事でも詳しく整理しています。

APIキーを外部の設定ファイルで安全に管理する方法

なぜuploadsプレイリスト経由で取得するのか

YouTubeチャンネルがアップロードした動画は、内部的に uploadsプレイリスト にまとまっています。そのため、チャンネルの動画一覧を取得する場合は、以下の流れにすると安定して取得できます。

  1. channels.list でチャンネルの uploads プレイリストIDを取得する
  2. playlistItems.list でuploadsプレイリスト内の動画IDを取得する
  3. videos.list で各動画の詳細情報をまとめて取得する

search.list でも動画を探せますが、クォータ消費が大きく、検索結果としての取得になるため、チャンネルのアップロード済み動画一覧を作る用途ではuploadsプレイリスト経由の方が扱いやすいです。

動画IDとチャンネルIDの確認方法

動画IDの確認方法

YouTubeの動画IDは、動画URLに含まれる一意のIDです。

  • 通常URL:https://www.youtube.com/watch?v=VIDEO_IDv= 以降
  • 短縮URL:https://youtu.be/VIDEO_ID の末尾
  • Shorts:https://www.youtube.com/shorts/VIDEO_ID の末尾

チャンネルIDの確認方法

チャンネルURLが /channel/UC... 形式であれば、UC から始まる文字列がチャンネルIDです。

一方で、@handle 形式のURLでは、URLだけではチャンネルIDが分かりにくい場合があります。その場合は、動画IDからチャンネルIDを取得できます。

最小コード:動画IDからチャンネルIDを取得する

まずは、任意の動画IDから、その動画を投稿したチャンネルIDを取得する最小コードです。

import os

from dotenv import load_dotenv
from googleapiclient.discovery import build

load_dotenv()

api_key = os.getenv("YOUTUBE_API_KEY")
video_id = "dQw4w9WgXcQ"

youtube = build("youtube", "v3", developerKey=api_key)

response = youtube.videos().list(
    part="snippet",
    id=video_id,
).execute()

items = response.get("items", [])

if items:
    channel_id = items[0]["snippet"]["channelId"]
    channel_title = items[0]["snippet"]["channelTitle"]
    print("channel_id:", channel_id)
    print("channel_title:", channel_title)
else:
    print("video not found")

ここで取得した channel_id を、次のコードの CHANNEL_ID として使います。

実用コード:チャンネルの動画一覧を取得してCSV保存する

以下は、指定したチャンネルのuploadsプレイリストから動画IDを取得し、動画ごとの詳細情報をCSV保存する実用コードです。

from pathlib import Path
import os
from time import sleep

import isodate
import pandas as pd
from dotenv import load_dotenv
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError


load_dotenv()

API_KEY = os.getenv("YOUTUBE_API_KEY")
CHANNEL_ID = "UCxxxxxxxxxxxxxxxx"  # ここを対象チャンネルIDに置き換え

if not API_KEY:
    raise ValueError("YOUTUBE_API_KEY が設定されていません。")


def get_uploads_playlist_id(youtube, channel_id: str) -> str:
    """チャンネルIDからuploadsプレイリストIDを取得する。"""
    response = youtube.channels().list(
        part="contentDetails",
        id=channel_id,
    ).execute()

    items = response.get("items", [])

    if not items:
        raise ValueError("チャンネルが見つかりませんでした。")

    return items[0]["contentDetails"]["relatedPlaylists"]["uploads"]


def get_video_ids_from_playlist(
    youtube,
    playlist_id: str,
    max_pages: int | None = None,
    page_size: int = 50,
) -> list[str]:
    """playlistItems.listでプレイリスト内の動画IDを取得する。"""
    video_ids = []
    page_token = None
    page_count = 0

    while True:
        response = youtube.playlistItems().list(
            part="contentDetails",
            playlistId=playlist_id,
            maxResults=min(page_size, 50),
            pageToken=page_token,
        ).execute()

        for item in response.get("items", []):
            video_id = item["contentDetails"]["videoId"]
            video_ids.append(video_id)

        page_token = response.get("nextPageToken")
        page_count += 1

        if not page_token:
            break

        if max_pages is not None and page_count >= max_pages:
            break

        sleep(0.1)

    return video_ids


def chunk_list(values: list[str], size: int) -> list[list[str]]:
    """リストを指定件数ごとに分割する。"""
    return [values[i:i + size] for i in range(0, len(values), size)]


def fetch_video_details(youtube, video_ids: list[str]) -> pd.DataFrame:
    """videos.listで動画詳細を50件ずつ取得する。"""
    rows = []

    for batch in chunk_list(video_ids, 50):
        response = youtube.videos().list(
            part="snippet,statistics,contentDetails,liveStreamingDetails",
            id=",".join(batch),
        ).execute()

        for item in response.get("items", []):
            snippet = item.get("snippet", {})
            statistics = item.get("statistics", {})
            content_details = item.get("contentDetails", {})
            live_details = item.get("liveStreamingDetails", {})

            duration_iso = content_details.get("duration")
            duration_sec = None

            if duration_iso:
                duration_sec = int(isodate.parse_duration(duration_iso).total_seconds())

            rows.append({
                "video_id": item.get("id"),
                "title": snippet.get("title"),
                "published_at": snippet.get("publishedAt"),
                "channel_id": snippet.get("channelId"),
                "channel_title": snippet.get("channelTitle"),
                "view_count": int(statistics["viewCount"]) if "viewCount" in statistics else None,
                "like_count": int(statistics["likeCount"]) if "likeCount" in statistics else None,
                "comment_count": int(statistics["commentCount"]) if "commentCount" in statistics else None,
                "duration_sec": duration_sec,
                "is_live_like": bool(live_details),
            })

        sleep(0.1)

    return pd.DataFrame(rows)


def main():
    youtube = build("youtube", "v3", developerKey=API_KEY)

    try:
        uploads_playlist_id = get_uploads_playlist_id(youtube, CHANNEL_ID)
        print("uploads_playlist_id:", uploads_playlist_id)

        video_ids = get_video_ids_from_playlist(youtube, uploads_playlist_id)
        print("video count:", len(video_ids))

        df = fetch_video_details(youtube, video_ids)

        if df.empty:
            print("動画情報を取得できませんでした。")
            return

        df = df.sort_values("published_at", ascending=False).reset_index(drop=True)

        output_dir = Path("youtube_data")
        output_dir.mkdir(parents=True, exist_ok=True)

        csv_path = output_dir / f"{CHANNEL_ID}_videos.csv"
        df.to_csv(csv_path, index=False, encoding="utf-8-sig")

        print(f"saved: {csv_path}")
        print(df.head(10).to_string(index=False))

    except HttpError as e:
        print("HTTP Error:", e)
    except Exception as e:
        print("Error:", e)


if __name__ == "__main__":
    main()

このコードを実行すると、指定したチャンネルの動画一覧が youtube_data フォルダにCSVとして保存されます。

取得できる列の例

上記コードでは、以下のような列を取得します。

列名内容
video_id動画ID
title動画タイトル
published_at公開日時
channel_idチャンネルID
channel_titleチャンネル名
view_count再生回数
like_count高評価数
comment_countコメント数
duration_sec動画時間(秒)
is_live_likeライブ配信またはアーカイブ配信の可能性があるか

is_live_like は、liveStreamingDetails が含まれているかどうかを見た簡易フラグです。ライブ配信やアーカイブ配信の候補を探す補助として使えますが、厳密な分類には追加確認が必要です。

実行結果の例

実行すると、以下のようなCSVを作成できます。

video_idtitlepublished_atview_countlike_countcomment_countduration_secis_live_like
AbCdEf12345【告知】新プロジェクト始動2025-08-10T12:00:03Z1523405342421482false
GhIjKl67890配信アーカイブ:夏祭りコラボ2025-07-29T15:00:11Z9832012314535217260true
MnOpQr24680Shorts:切り抜き名場面2025-07-20T09:12:00Z42012150211828false

保存したCSVは、Excel、Googleスプレッドシート、Python、Looker Studioなどで集計・可視化できます。

簡単な集計例

取得したCSVを使うと、投稿本数や再生回数の傾向を簡単に確認できます。

import pandas as pd

df = pd.read_csv("youtube_data/UCxxxxxxxxxxxxxxxx_videos.csv")

df["published_at"] = pd.to_datetime(df["published_at"])
df["published_month"] = df["published_at"].dt.to_period("M").astype(str)

monthly = (
    df.groupby("published_month")
      .agg(
          video_count=("video_id", "count"),
          total_views=("view_count", "sum"),
          avg_views=("view_count", "mean"),
      )
      .reset_index()
)

print(monthly.tail())

このように月別に集計すると、投稿頻度や再生回数の変化を確認できます。VTuberチャンネルや配信チャンネルの場合は、配信アーカイブ、Shorts、通常動画を分けて見ると、より詳しい傾向分析につながります。

クォータを意識した取得のポイント

YouTube Data APIにはクォータ制限があります。動画一覧を取得する場合は、以下を意識すると無駄なクォータ消費を抑えやすくなります。

  • playlistItems.list で動画IDを取得する
  • videos.list で最大50件ずつ詳細情報を取得する
  • search.list を多用しない
  • 必要以上に同じチャンネルを何度も取得しない
  • 定期取得する場合は、前回取得分との差分更新を検討する

search.list は便利ですが、クォータ消費が大きいため、チャンネルのアップロード済み動画一覧を作る用途では、uploadsプレイリスト経由の取得が扱いやすいです。

つまずきやすいポイント

チャンネルIDではなくハンドル名を指定している

channels.listid に指定するのは、UC から始まるチャンネルIDです。@handle やチャンネルURL全体をそのまま入れても取得できません。

APIキーが読み込めていない

YOUTUBE_API_KEY が設定されていません。 と表示される場合は、.env ファイルの配置場所やキー名を確認してください。

APIが有効化されていない

Google Cloud側でYouTube Data API v3を有効化していない場合、APIキーが正しくてもエラーになります。Google Cloud Consoleの「APIとサービス」から有効化済みか確認してください。

取得件数が少ない

テスト用に max_pages を指定している場合、取得ページ数で止まります。全件取得したい場合は、max_pages=None のまま実行してください。

一部の統計情報が空になる

動画によっては、高評価数やコメント数など一部の統計情報が取得できない場合があります。コードでは、存在しない項目を None として扱うようにしています。

Shortsを完全には判定できない

動画時間が短いからといって、必ずShortsとは限りません。Shorts判定には、動画時間だけでなく、URL形式や画面比率なども確認する必要があります。本記事のコードでは、Shorts推定までは行わず、後続分析で分類しやすいように動画時間を取得しています。

取得した動画一覧の活用例

  • 月別の投稿本数を集計する
  • 再生回数が多い動画を抽出する
  • 配信アーカイブ候補を抽出する
  • Shorts候補と通常動画を分けて傾向を見る
  • 字幕取得やWhisper文字起こしの対象動画を選ぶ
  • pytchatでチャットを取得する対象配信を選ぶ

動画一覧をCSVで持っておくと、YouTube Data APIだけで完結する分析だけでなく、字幕・チャット・文字起こしデータと組み合わせた分析にも発展させやすくなります。

次に読む記事

まとめ

この記事では、YouTube Data API v3を使って、指定したチャンネルのアップロード済み動画一覧を取得し、CSVとして保存する方法を紹介しました。

uploadsプレイリスト経由で動画IDを取得し、videos.list で詳細情報をまとめて取得することで、投稿日時、再生回数、動画時間などを一覧化できます。取得した動画一覧は、投稿頻度の分析、人気動画の抽出、字幕・チャット・文字起こし対象の選定など、YouTubeデータ分析の土台として活用できます。

-YouTube, データ活用