【個人開発】サーバー代0円!GitHub ActionsとPythonで「完全自動更新」なWebサイトを作る技術(Google Maps & Threads API活用)
はじめに
前回は、Next.js 16を使って 「札幌の作業カフェ検索サイト」 を1週間で爆速開発した話をしました。
今回はその 「続編(第2回)」 です。
個人開発をしていて、こんな悩みはありませんか?
- 「データの更新がめんどくさい…」
- 「サーバー代をこれ以上払いたくない…」
- 「APIキーの管理、ちょっと怖い…」
これらを 「GitHub Actions + Python」 の組み合わせで、完全無料&サーバーレス で解決した技術的な裏側を解説します。
初心者の方でも真似できるように、コード付きで備忘録として残します。
🏗️ 全体アーキテクチャ
今回のサイトは Next.js (Vercel) で動いていますが、バックエンド(DBサーバーなど)は持っていません。
その代わりに、GitHub Actions を「定期実行される簡易サーバー」として利用 しています。
【データの流れ】
- 毎日/毎週: GitHub Actions がスケジュール通りに起動
- Python: 外部API (Google Maps / Custom Search) を叩いて最新データを取得
-
Git: 差分があれば、リポジトリの
jsonファイルを直接書き換えて Commit & Push - Vercel: メインブランチの更新を検知して、自動でサイトを再ビルド・デプロイ
これで、「寝ている間に勝手にサイトの情報が最新になる」 仕組みの完成です。
🛠️ 実践1:Google Maps評価の自動更新 (毎日実行)
カフェの「星の数」や「口コミ数」は信頼性の命です。ここが古いとユーザーが離れます。
やったこと
Google Places API を使って、登録されている全カフェの rating と user_ratings_total を取得・更新します。
Pythonスクリプトのポイント (update_ratings.py)
# APIリクエストを「最小限」にする工夫
# 毎回テキスト検索すると料金がかかるので、一度取得した「place_id」を保存して使い回す。
def get_place_details(place_id):
url = f"https://maps.googleapis.com/maps/api/place/details/json"
params = {
"place_id": place_id,
"fields": "rating,user_ratings_total", # 必要な情報だけ指定して節約!(重要)
"key": os.environ["GOOGLE_MAPS_API_KEY"]
}
# ... (リクエスト処理)
このスクリプトを、GitHub Actions で 毎日 朝9:00 (JST) に動かします。
GitHub Actions の設定 (.github/workflows/update_data.yml)
on:
schedule:
# 日本時間 9:00 は UTC 0:00
- cron: '0 0 * * *'
jobs:
update:
runs-on: ubuntu-latest
permissions:
contents: write # リポジトリへの書き込み権限を与える
steps:
- uses: actions/checkout@v4
# Python環境のセットアップ
- uses: actions/setup-python@v5
with:
python-version: '3.10'
# データの更新実行
- name: Run Update Script
env:
# ここでGitHub Secretsに登録したキーを読み込む(後述)
GOOGLE_MAPS_API_KEY: ${{ secrets.GOOGLE_MAPS_API_KEY }}
run: python scripts/update_ratings.py
# 変更があれば自動コミット
- uses: stefanzweifel/git-auto-commit-action@v5
with:
commit_message: "chore: update cafe ratings"
これで、毎朝自動でロボットが働き、サイトを最新の状態に保ってくれます。
🛠️ 実践2:Threadsのトレンド自動発掘 (週1実行)
次に、「新しいカフェ情報の収集」です。
InstagramやThreadsにはスクレイピング対策がありますが、「Google Custom Search API」 を使うことで、正攻法でアプローチします。
アイデア
- Threadsには検索APIがない
- Google検索で
site:threads.net "札幌" "カフェ"と検索すれば、新しい投稿が見つかるのでは? - 見つかったら 自動でPull Requestを作成 し、管理者がボタンを押すだけで追加できるようにする。
Pythonスクリプト (discover_influencers.py)
# Google Custom Search APIを使用
def search_threads(query):
url = "https://www.googleapis.com/customsearch/v1"
params = {
'key': API_KEY,
'cx': SEARCH_ENGINE_ID, # 検索エンジンID
'q': query,
'dateRestrict': 'w1' # 「過去1週間」の投稿に限定
}
# ... (JSON解析してユーザー情報を抽出)
GitHub Actions で Pull Request を自動作成
更新をそのままコミットするのではなく、「人間が確認してからマージしたい」 ので、PR作成アクションを使います。
# 変更があった場合のみ実行
- name: Create Pull Request
uses: peter-evans/create-pull-request@v6
with:
token: ${{ secrets.GITHUB_TOKEN }}
title: "🤖 AIが新しいThreadsインフルエンサーを見つけました"
body: "確認して問題なければMergeしてください!"
branch: "ai/influencer-discovery"
これで、毎週金曜日に「新しいカフェの話題」がPRとして届くようになりました。体験として最高です。
🔐 セキュリティ・ファースト (最重要)
個人開発でもセキュリティは手抜き厳禁です。特にAPIキーが流出すると 高額請求のリスク があります。
1. APIキーは絶対にコードに書かない
.env ファイルも .gitignore に入れてコミットしないこと。
Python側では必ず環境変数から読み取ります。
# NG (絶対にダメ!)
# API_KEY = "AIzaSy..."
# OK
import os
API_KEY = os.environ.get("GOOGLE_MAPS_API_KEY")
2. GitHub Secrets を使う
リポジトリの Settings > Secrets and variables > Actions にキーを登録します。
これで、コード上にはキーが現れず、Actions実行時のみメモリ上に展開されます。
3. Google Cloud側で「API制限」をかける (忘れがち!)
万が一キーが漏れても被害を最小限にするため、Google Cloud Console で以下の制限を必ずかけます。
-
Application restrictions (アプリケーションの制限):
- 本当はIP制限などをしたいが、GitHub ActionsのIPは変わるので難しい。
- 最低限、他の怪しいサイトで使われないよう監視する。
-
API restrictions (APIの制限):
- このキーで使えるAPIを 「Places API」 と 「Custom Search API」 だけに限定する。
- これなら、もし漏れても「勝手にサーバーを立てられる」などの被害は防げます。
まとめ
「サーバーレス × GitHub Actions × Python」 の構成は、個人開発において最強のパートナーです。
- 維持費ゼロ (APIの無料枠内なら)
- メンテナンスフリー (一度作れば勝手に動く)
- 高セキュリティ (Secrets管理)
「データの更新が面倒で更新が止まった個人アプリ」にならないよう、最初にこの自動化の仕組みを入れておくのがオススメです!