⚙️

GitHubトレンドをスクレイピングしてBigQueryに蓄積してみる(前編)

に公開

はじめに

GCP Professional Data Engineer(PDE)の学習にあたり、ついでに今回はスクレイピングを覚えてみようと考えました。GitHubトレンドを題材にデータ収集基盤を構築しました。

🎯 この記事のゴール

✅ GitHubトレンドをBeautifulSoupでスクレイピング
✅ Cloud Functionsを2段構成で組む設計
✅ BigQueryのパーティション+クラスタリング設計

🏗️ 全体アーキテクチャ

[Cloud Scheduler] → [CF①スクレイピング] → [GCS] → [CF②] → [BigQuery]
                                              ↑ (GCSトリガー)

Phase 1:スクレイピング実装

初めてのスクレイピングだったので、基本の4ステップを意識しました。
ローカルでまずはデータが取れることを確認します。
https://github.com/trending
今回のターゲットです。実際はひとまず日本語データを取ります。

スクレイピングの基本4ステップ

① HTMLを取得

import requests
response = requests.get("https://github.com/trending/python?since=daily")
response.raise_for_status()

② パーサーを作成

from bs4 import BeautifulSoup
soup = BeautifulSoup(response.text, "html.parser")

※「パーサー」は、構造を持たないテキストを“意味のある構造”に変換する仕組み。
BeautifulSoupでの "html.parser" はHTMLをオブジェクトとして扱えるようにする“翻訳者”のような存在です。とのことです。

③ 要素を探す

Chrome DevToolsで、各リポジトリが<article class="Box-row">で囲まれていることを確認。

④ データを抽出

for article in soup.select("article.Box-row"):
    h2 = article.find("h2", class_="h3")
    link = h2.find("a") if h2 else None
    desc = article.find("p", class_="col-9")
    stars_today = article.find("span", string=lambda s: s and "star" in s)

    repositories.append({
        "title": link.get_text(strip=True) if link else "",
        "url": f"https://github.com{link.get('href')}" if link else "",
        "description": desc.get_text(strip=True) if desc else "",
        "today_stars": int(stars_today.text.split()[0].replace(",", "")) if stars_today else 0,
        "collected_at": datetime.now().isoformat()
    })

属性がわからないところは開発者ツールモードでChromeで探しました。

Phase 2:Cloud Functionsへデプロイ

Cloud Functions ①:スクレイピング→GCS

gcloud functions deploy scrape-github-trending \
  --runtime python312 --trigger-http

JSONファイルを格納します。

Cloud Functions ②:GCS→BigQuery

gcloud functions deploy load-to-bigquery \
  --trigger-event-filters="type=google.cloud.storage.object.v1.finalized" \
  --trigger-event-filters="bucket=$BUCKET_NAME" \

google.cloud.storage.object.v1.finalizedにより、GCSアップロード完了時に自動実行されます。

⏰ 定期実行

gcloud scheduler jobs create http github-trending-daily \
  --schedule="0 7 * * *"

BigQueryテーブル設計

こちらは学習用にパーティショニングとクラスタリングを機能追加しました。

CREATE OR REPLACE TABLE `project.dataset.github_trending_p`
PARTITION BY DATE(collected_at)
CLUSTER BY source, language, title
AS SELECT * FROM `project.dataset.github_trending`;

パーティション:日別集計の高速化、古いデータ削除時のコスト削減。日付ごとにテーブルを分けるイメージ。
クラスタリング:言語別検索の最適化。クラスタリングを設定すると、データが特定の列順で物理的に並ぶそうです。

ChatGPTのまとめも貼っておきます。

IAM設定

各Cloud Functionsに専用サービスアカウントを作成し、最小権限を付与:

  • CF①Storage Object Creator
  • CF②Eventarc Event Receiver, Storage Object Viewer, BigQuery Data Editor, BigQuery Job User

Eventarc Event ReceiverはGCSトリガーを受け取るために必須でした。

まとめ

技術的な学び

  • スクレイピングの基本4ステップ(HTML取得→パース→要素探索→データ抽出)を体系的に実装
  • Cloud Run Functionsはローカル開発して動くことを確認後、デプロイするのがよい
  • GCSトリガーで非同期処理を実現、Pub/Subは不要
  • パーティション+クラスタリングでBigQuery性能を最大化

開発期間:約2日で本番稼働するシステムが完成しました。

次回予告

後編では、Dataflowでのバッチ処理、Looker Studioでの可視化など、PDE資格の実践的なスキルセットを掘り下げたいと思います。

おわりに

「手を動かして学ぶ」ことの重要性を実感した開発でした。特にスクレイピングの基本4ステップは、他のWebサイトへの応用も効くはずです。

この記事がGCPでのデータ基盤構築やPDE資格取得を目指す方の参考になれば幸いです。最後まで読んでいただき、ありがとうございました!

Accenture Japan (有志)

Discussion