Go×GCP

YouTube APIとBigQueryを連携!Goで作るトレンド解析アプリ【Cloud Runで定期実行】

本記事では、Go言語とGoogle Cloud Platform (GCP) を利用して、YouTubeのトレンドデータを収集、分析、可視化するアプリケーションの作り方を解説します。

具体的には、GoでYouTube APIからデータを取得してBigQueryに格納するWeb APIを構築し、Cloud Runサービスとしてデプロイ。Cloud Schedulerから定期的にAPIを呼び出す構成で、一連の流れをサンプルコード付きで詳しく紹介します。

この記事を読み終える頃には、GCPを使ったデータ収集・分析基盤の構築方法をマスターし、ご自身で応用的な開発を行うための知識が身に付いているはずです。

アプリ全体像:YouTubeTrendTrackerとは?

今回開発するアプリケーション「YouTubeTrendTracker」の目的は、特定のYouTubeチャンネルの動画データを定期的に収集し、そのトレンドを分析することです。

アプリ概要

このアプリは、以下の機能を持つシンプルなCloud Runサービスです。

  1. データ取得API: HTTPリクエストを受け取ると、YouTube Data API v3 を利用して指定チャンネルの動画情報を取得し、BigQueryに保存するGoのWeb APIです。

  2. コンテナ化: アプリケーションはDockerでコンテナ化され、Cloud Runでサーバーレスに実行されます。

  3. 定期実行: Cloud Schedulerを使い、cronのように定期的にCloud Runのエンドポイントを呼び出すことで、データ収集を自動化します。

  4. データ可視化: BigQueryに蓄積されたデータをLooker Studioに接続し、トレンドを可視化するダッシュボードを作成します。

アーキテクチャ図

アプリケーションの全体像は「Cloud Scheduler → Cloud Run → BigQuery」というシンプルな構成になります。

GitHubリポジトリ

本記事で紹介するコードは、すべて以下のGitHubリポジトリで公開しています。実際に動かしながら読み進めてみてください。

YouTube APIの準備

まずはデータの取得元となるYouTube Data API v3を利用するための準備から始めましょう。

APIキー取得方法

  1. GCPプロジェクトの選択: GCPコンソールにアクセスし、使用するプロジェクトを選択します。

  2. APIの有効化: 「APIとサービス」>「ライブラリ」に移動し、「YouTube Data API v3」を検索して有効にします。

  3. 認証情報の発行: 「APIとサービス」>「認証情報」に移動し、「認証情報を作成」>「APIキー」を選択します。

  4. APIキーの制限(推奨): 作成されたAPIキーには、不正利用を防ぐために制限をかけることを強く推奨します。「APIの制限」で「YouTube Data API v3」のみを許可し、「アプリケーションの制限」で「IPアドレス」などを設定しておくと、より安全です。

ここで取得したAPIキーは、後のGoアプリケーションの設定ファイルで使用します。

利用するエンドポイント

今回のアプリでは、主に以下の3つのエンドポイントを利用します。

  • Channels: list: チャンネルIDを元に、チャンネル情報(動画アップロード用の再生リストIDなど)を取得します。

  • PlaylistItems: list: アップロード動画の再生リストIDを使い、動画の一覧(Video ID)を取得します。

  • Videos: list: Video IDを使い、動画の詳細情報(タイトル、統計情報、タグなど)を取得します。

取得データの例

APIから取得できるデータは多岐にわたりますが、今回は主に以下のような情報を扱います。

  • 動画ID

  • タイトル

  • 公開日時

  • 再生回数

  • 高評価数

  • コメント数

  • タグ

これらのデータをBigQueryに格納し、分析の元データとします。

API制限の注意点

YouTube Data APIには、1日の利用クォータ(リクエスト上限)が設定されています。デフォルトでは「10,000ユニット/日」です。 各APIエンドポイントの呼び出しには、それぞれ異なるコスト(ユニット数)が設定されています。

  • list(読み取り): 1ユニット

  • update(書き込み): 50ユニット

今回のアプリは読み取りが中心ですが、多くのチャンネルや動画を頻繁に取得すると、上限に達する可能性があります。クォータの消費量はGCPコンソールの「APIとサービス」ダッシュボードから確認できるので、開発中は意識しておきましょう。

BigQueryの準備

次に、取得したデータを格納するBigQueryの準備を行います。

データセット・テーブル作成

Goアプリケーション側でデータセットとテーブルが存在しない場合に自動作成する処理を実装していますが、手動で作成する場合は以下の手順で行います。

  1. データセットの作成: BigQueryコンソールに移動し、プロジェクトの横にあるメニューから「データセットを作成」を選択します。

    • データセットID: youtube (任意)

    • ロケーション: asia-northeast1 (Tokyo) など、利用するリージョンを選択

  2. テーブルの作成: 作成した youtube データセットを選択し、「テーブルを作成」をクリックします。

    • テーブル名: video_trends (任意)

    • スキーマ: 後述するスキーマ定義をJSON形式で貼り付けます。

テーブルスキーマ設計

どのようなデータを格納するかを定義するスキーマは非常に重要です。今回は以下のようなスキーマを設計しました。

[
  {"name": "dt",           "type": "DATE",      "mode": "REQUIRED"},
  {"name": "channel_id",   "type": "STRING",    "mode": "REQUIRED"},
  {"name": "video_id",     "type": "STRING",    "mode": "REQUIRED"},
  {"name": "title",        "type": "STRING",    "mode": "NULLABLE"},
  {"name": "channel_name", "type": "STRING",    "mode": "NULLABLE"},
  {"name": "tags",         "type": "STRING",    "mode": "REPEATED"},
  {"name": "is_short",     "type": "BOOLEAN",   "mode": "NULLABLE"},
  {"name": "views",        "type": "INTEGER",   "mode": "NULLABLE"},
  {"name": "likes",        "type": "INTEGER",   "mode": "NULLABLE"},
  {"name": "comments",     "type": "INTEGER",   "mode": "NULLABLE"},
  {"name": "published_at", "type": "TIMESTAMP", "mode": "NULLABLE"},
  {"name": "created_at",   "type": "TIMESTAMP", "mode": "REQUIRED"}
]

ポイント:

  • dt: データを取得した日付を格納するパーティションキーです。DATE型にすることで、日別のデータ管理とクエリ効率が向上します。

  • tags: REPEATEDモード(配列)にすることで、1つの動画に付与された複数のタグをそのまま格納できます。

  • created_at: このレコードが作成されたタイムスタンプです。データの鮮度を保つために重要です。

IAM権限設定

Cloud RunサービスがBigQueryにデータを書き込むためには、適切なIAM権限が必要です。 Cloud Runサービスに紐付けるサービスアカウントには、少なくとも以下のロールを付与してください。

  • BigQuery データ編集者 (roles/bigquery.dataEditor): テーブルの作成やデータの書き込みを許可します。

  • BigQuery ジョブユーザー (roles/bigquery.jobUser): クエリジョブの実行を許可します。

また、Cloud Schedulerから認証付きのCloud Runサービスを呼び出す場合は、Scheduler用のサービスアカウントに Cloud Run起動元 (roles/run.invoker) ロールを付与する必要があります。

Goでの実装

このセクションでは、Cloud Runで動作するGoのHTTPサーバー実装について、主要な部分を抜粋して解説します。

HTTPハンドラの実装

アプリケーションのエントリーポイントは、HTTPリクエストを受け取ってデータ収集と保存処理をキックするハンドラです。cmd/fetcher/main.go に実装されています。

// main.go
func handler(w http.ResponseWriter, r *http.Request) {
    ctx := context.Background()

    // ... クライアント初期化などの準備 ...

    // データ取得と保存の実行
    f := fetcher.NewFetcher(ytClient, bqWriter)
    if err := f.FetchAndStore(ctx, channelIDs, cfg.App.MaxVideosPerChannel); err != nil {
        log.Error("An error occurred during the fetch and store process", err, nil)
        http.Error(w, "An error occurred during the fetch and store process", http.StatusInternalServerError)
        return
    }

    w.Header().Set("Content-Type", "application/json")
    json.NewEncoder(w).Encode(map[string]string{"status": "success"})
}

このhandler関数が、Cloud Schedulerからのリクエストのたびに実行され、一連のデータ処理を行います。

YouTube APIクライアントの実装

internal/youtube/client.go に、APIクライアントの初期化やチャンネル動画情報を取得するロジックが実装されています。

// internal/youtube/client.go
func (c *Client) FetchChannelVideos(ctx context.Context, channelID string, maxResults int64) ([]*Video, error) {
    // ... API呼び出しロジック ...

        // 4. 取得した情報を独自のVideo構造体に詰めて返す
        for _, item := range vResp.Items {
            // ... 統計情報の取得 ...
            pub, _ := time.Parse(time.RFC3339, item.Snippet.PublishedAt)

            // 動画の長さ(duration)からショート動画かどうかを判定
            duration, _ := parseISODuration(item.ContentDetails.Duration)
            isShort := duration <= 60*time.Second

            allVideos = append(allVideos, &Video{
                ID:          item.Id,
                Title:       item.Snippet.Title,
                // ... 他のフィールドのマッピング
            })
        }
    // ...
}

parseISODurationの実装について

コード内で呼び出されているparseISODurationは、YouTube APIが返すISO 8601形式の動画時間(例: PT1M30S)を、Goのtime.Duration型に変換するためのヘルパー関数です。Goの標準ライブラリtime.ParseDurationPTといったプレフィックスに対応していないため、以下のように簡単な文字列置換で対応しています。

// parseISODuration converts a YouTube ISO 8601 duration (e.g., "PT1M30S") into a time.Duration.
func parseISODuration(isoDuration string) (time.Duration, error) {
    s := strings.TrimPrefix(isoDuration, "P")
    replacer := strings.NewReplacer("T", "", "H", "h", "M", "m", "S", "s")
    s = replacer.Replace(s)
    return time.ParseDuration(s)
}

BigQueryクライアントの実装

internal/storage/bq.go に、BigQueryへの書き込み処理が実装されています。

// internal/storage/bq.go
func (w *BigQueryWriter) EnsureTableExists(ctx context.Context) error {
    // ...
            schema, _ := bigquery.SchemaFromJSON(getSchemaJSON())
    // ...
}

getSchemaJSONの実装について

EnsureTableExists内で呼び出されているgetSchemaJSONは、テーブルスキーマをJSON形式のバイト配列として返すヘルパー関数です。実際のアプリケーションでは外部の.jsonファイルから読み込むのが一般的ですが、このサンプルでは簡潔さのためにGoのコード内に直接埋め込んでいます。

func getSchemaJSON() []byte {
    return []byte(`[
      {"name": "dt", "type": "DATE", "mode": "REQUIRED"},
      {"name": "channel_id", "type": "STRING", "mode": "REQUIRED"},
      // ... other fields
    ]`) 
}

Cloud Runへのデプロイと定期実行

作成したGoのWeb APIを、サーバーレス環境であるCloud Runにデプロイし、Cloud Schedulerから定期的に呼び出す設定を行います。

Dockerfile

まず、アプリケーションをコンテナ化するためのDockerfileを用意します。

# (Dockerfileの内容は変更なし)
# Stage 1: builder
FROM golang:1.25.0-alpine AS builder
...
# Stage 2: runner
FROM gcr.io/distroless/base-debian12
...
ENTRYPOINT ["/srv/fetcher"]

Cloud Runへのデプロイ

次に、作成したDockerイメージをArtifact Registryにプッシュし、そのイメージを使ってCloud Runサービスをデプロイします。

# 1. gcloudの認証設定 (初回のみ)
gcloud auth configure-docker asia-northeast1-docker.pkg.dev

# 2. Dockerイメージのビルドとプッシュ
export IMAGE_URI=asia-northeast1-docker.pkg.dev/YOUR_PROJECT_ID/youtube-trend/fetcher:latest
docker build -t $IMAGE_URI .
docker push $IMAGE_URI

# 3. Cloud Runへデプロイ
gcloud run deploy youtube-fetcher \
  --image=$IMAGE_URI \
  --platform=managed \
  --region=asia-northeast1 \
  --allow-unauthenticated \
  --service-account=YOUR_SERVICE_ACCOUNT@YOUR_PROJECT_ID.iam.gserviceaccount.com

Cloud Schedulerで定期実行

最後に、Cloud SchedulerからデプロイしたCloud Runのエンドポイントを定期的に呼び出すジョブを作成します。ここでは、OIDC認証を用いて安全にサービスを呼び出します。

gcloud scheduler jobs create http youtube-fetch-job \
  --schedule="0 */1 * * *" \
  --uri="https://youtube-fetcher-xxxxxxxx-an.a.run.app/" \
  --http-method=GET \
  --oidc-service-account-email=SCHEDULER_SERVICE_ACCOUNT@YOUR_PROJECT_ID.iam.gserviceaccount.com

より柔軟な連携を行いたい場合は、Cloud Workflowsを介してCloud Runを呼び出すことも可能です。以下は最小構成のworkflow.yamlの例です。

# workflow.yaml
main:
  steps:
    - call_cloud_run:
        call: http.get
        args:
          url: https://youtube-fetcher-xxxxxxxx-an.a.run.app/
          auth:
            type: OIDC
        result: res

データ分析とクエリ例

BigQueryに蓄積したデータを使って、様々な分析が可能です。ここではいくつかのクエリ例を紹介します。

直近7日間の推移

特定の動画について、直近7日間の再生数といいね数の日ごとの伸びを、LAGウィンドウ関数を使ってvideo_stats_snapshotテーブルから直接計算します。さらに、日々の再生数の成長率(前日比)を計算する例も加えてみましょう。

-- 特定の動画の直近7日間の再生数といいね数の日次差分と成長率を取得
WITH daily_stats AS (
    -- ...
)
SELECT
    dt,
    video_id,
    title,
    views - prev_views AS delta_views,
    likes - prev_likes AS delta_likes,
    SAFE_DIVIDE(views - prev_views, prev_views) AS growth_rate
FROM daily_stats
WHERE dt >= DATE_SUB(CURRENT_DATE(), INTERVAL 7 DAY)
ORDER BY dt;

ショート動画の分析

is_shortフラグを使って、ショート動画と通常動画のパフォーマンスを比較するクエリも有用です。この is_short フラグは、Goアプリケーション側でYouTube APIから取得した動画の長さ(contentDetails.duration)をパースし、60秒以下の場合に true を設定しています。

-- ショート動画と通常動画のパフォーマンスを比較
SELECT
    is_short,
    COUNT(1) AS video_count,
    AVG(views) AS avg_views,
    SAFE_DIVIDE(SUM(likes), SUM(views)) AS likes_per_view
FROM `your-project-id.youtube.video_stats_snapshot`
WHERE dt = (SELECT MAX(dt) FROM `your-project-id.youtube.video_stats_snapshot`)
GROUP BY is_short;

このクエリ結果から、「ショート動画は通常動画に比べて平均再生数は低いが、1再生あたりのいいね数(エンゲージメント率)は高い」といった仮説を検証できます。この分析結果に基づき、「ショート動画で新規視聴者を獲得し、通常動画でファンを定着させる」といった戦略の有効性を評価できます。

Looker Studioで可視化

グラフ作成例

  • テーブル: title, views, likes などを指標として表示し、再生数順の動画ランキングを作成します。さらに、channel_namedt(日付)で絞り込むフィルタコントロールを追加したり、視聴者がディメンションを切り替えて(例:「タグ別」「チャンネル別」)データを探索できるように設定したりすると、よりインタラクティブなダッシュボードになります。

運用と拡張アイデア

  • Looker Studioの共有: 作成したダッシュボードは、URLリンクでチームメンバーに共有したり、特定のGoogleアカウントに編集権限を付与したりできます。定期的なレポートとしてPDF形式でメール送信する設定も可能で、「社内チームでの週次進捗会議の資料として活用する」「分析結果をクライアントにレポートとして提供する」といった具体的なビジネス活用に繋がります。

まとめ

本記事では、Go言語とGCPの各種サービスを連携させ、YouTubeのトレンドデータを収集、分析、可視化するアプリケーションの構築方法を、具体的なコードを交えながら解説しました。

この一連の流れを体験することで、単なるサービス紹介に留まらない、以下のような実践的なスキルが身に付いたはずです。

  • GCPによるデータ基盤設計スキル: Cloud Run, Cloud Scheduler, BigQuery, Looker Studioを組み合わせた、スケーラブルなデータパイプラインの構築能力。

  • GoでのAPIクライアント実装スキル: 公式ライブラリを使い、外部APIと連携する堅牢なアプリケーションを開発する能力。

  • SQLによるデータ分析スキル: BigQueryのウィンドウ関数や配列関数を駆使し、目的に応じたデータ抽出・集計を行う能力。

ぜひ、この記事を参考に、あなた独自のデータ分析アプリケーション開発に挑戦してみてください。本記事で解説した実装は、YouTubeマーケティングの効果測定や、競合チャンネルの動向調査といった具体的なSNS戦略にも応用できるはずです。

このシリーズでは、今後もGoとGCPを組み合わせた、より実践的なテーマを扱っていく予定です。ご期待ください。

  • この記事を書いた人

ふくまる

機械設計業をしていたが25歳でエンジニアになると決意して行動開始→ 26歳でエンジニアに転職→ 28歳でフリーランスエンジニアに→ 現在、34歳でフリーランス7年目 Go案件を受注中 Go,GCPが得意分野

-Go×GCP
-, , , , ,