GitHubトレンドをスクレイピングしてBigQueryに蓄積してみる(前編)
はじめに
GCP Professional Data Engineer(PDE)の学習にあたり、ついでに今回はスクレイピングを覚えてみようと考えました。GitHubトレンドを題材にデータ収集基盤を構築しました。
🎯 この記事のゴール
✅ GitHubトレンドをBeautifulSoupでスクレイピング
✅ Cloud Functionsを2段構成で組む設計
✅ BigQueryのパーティション+クラスタリング設計
🏗️ 全体アーキテクチャ
[Cloud Scheduler] → [CF①スクレイピング] → [GCS] → [CF②] → [BigQuery]
↑ (GCSトリガー)
Phase 1:スクレイピング実装
初めてのスクレイピングだったので、基本の4ステップを意識しました。
ローカルでまずはデータが取れることを確認します。
今回のターゲットです。実際はひとまず日本語データを取ります。

スクレイピングの基本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資格取得を目指す方の参考になれば幸いです。最後まで読んでいただき、ありがとうございました!
Discussion