AI

Google Cloud Run を使用したサーバーレス ウェブスクレイピング パイプラインの構築方法

Google Cloud上でインフラからスケジュールされたデータ収集まで、完全に自動化されたサーバーレスウェブスクレイピングパイプラインを構築するための実践ガイド。
4 分読
Google Cloud Run serverless scraping workflows

Google Cloud上でCloud Run、Firestore、BigQuery、Workflows、Cloud Schedulerを使用したサーバーレススクレイピングパイプライン構築の手順ガイド。

この記事では以下の内容を学びます:

  • – ウェブスクレイピングパイプラインにサーバーレスアーキテクチャが適している理由
  • 必要なGoogle Cloudインフラをゼロから設定する方法。
  • – Cloud RunへのプライベートスクレイパーサービスとパブリックAPIサービスのデプロイ方法
  • Cloud Workflowsでスクレイピング実行をオーケストレーションし、Cloud Schedulerで自動化する方法
  • FirestoreとBigQueryを使用したスクレイピングデータの保存とクエリ方法
  • パイプライン全体がエンドツーエンドで機能していることを検証する方法。

さあ始めましょう!

サーバーレススクレイピングパイプラインを構築する理由

ほとんどのスクラッピングチュートリアルはスクリプト作成で終わります。HTMLを取得し、いくつかのフィールドをパースする程度です。しかし本番環境でスクレイパーを運用するには、より難しい質問への答えが必要です:データはどこに保存されるのか?スケジュールで実行するには?後で結果をクエリするには?スクレイパーが稼働していない時のコストを抑えるには?

そこでサーバーレスが活躍します。Google Cloud Runはサービスがリクエストを処理している時だけ課金されます。管理すべきサーバーも、夜間にお金を燃やすアイドル状態のコンピューティングリソースも不要です。これにジョブ追跡用のFirestore、分析用のBigQuery、オーケストレーション用のCloud Workflowsを組み合わせれば、アイドル時はゼロにスケールし、オンデマンドで起動するデータパイプラインアーキテクチャが実現します。

このガイドの終わりまでに、以下の環境を構築します:

  1. Cloud Run 上のプライベートスクレイパーサービス(実際のスクレイピングを実行)
  2. データを公開するCloud Run上のパブリックAPIサービス
  3. ジョブの状態と結果を追跡するFirestoreコレクション。
  4. 分析用にクエリ可能なBigQueryテーブル
  5. スクレイピング実行全体を調整するCloud Workflow。
  6. cronスケジュールでこれをトリガーするCloud Schedulerジョブ。

アーキテクチャの理解

コマンドの実行を始める前に、各要素の連携方法を確認しておくと理解が深まります。当初このシステムを構築する際、適切なアーキテクチャの検討に多くの時間を費やしましたので、その流れをご説明します。

cloud-flow

スケジューラーがワークフローをトリガーします。ワークフローがスクレイパーを呼び出します。スクレイパーがURLを訪問し、コンテンツを取得し、結果をFirestoreとBigQueryの両方に書き込みます。その後、APIサービスがそれらのストアから読み取り、パブリックエンドポイントを通じてデータを公開します。

この連鎖の各リンクが機能すれば、本番環境で信頼できるシステムが構築できます。

前提条件

開始前に、以下の準備が整っていることを確認してください:

  1. Googleアカウント
  2. 課金設定済みのGCPプロジェクト(費用は最小限ですが、課金が有効である必要があります)。
  3. Node.js 18 以降。
  4. マシンにインストール済みのgcloudCLI。

簡単な動作確認を実行してください:

node --version
npm --version
gcloud --version

3つすべてにバージョン番号が表示されれば、準備完了です。

Google Cloudプロジェクトの設定

Cloud Consoleにアクセスし、新しいプロジェクトを作成します。ここではcloud-run-スクレイパー という名前を使用しましたが、ご自身のユースケースに合わせて任意の名前を付けてください。

手順は以下の通りです:

  1. プロジェクト名を入力します。
  2. [作成]をクリックします。
  3. 生成されたプロジェクトID(例:cloud-run-スクレイパー-123456)をコピーします。このIDはガイド全体で必要になります。
  4. 請求」に移動し、プロジェクトに請求アカウントをリンクします。

画面は次のようになります:

setting-up-project

シェル設定

プロジェクトIDを至る所でコピー&ペーストする必要がないよう、事前にいくつかの環境変数を設定することをお勧めします。これによりコマンドが整理され、再利用可能になります:

export PROJECT_ID="YOUR_PROJECT_ID"
export REGION="us-central1"
export REPO_NAME="cloud-run-scraper-repo"
export BQ_DATASET="scraper_data"
export BQ_TABLE="scraped_results"

次にgcloudをプロジェクトに設定します:

gcloud config set project "$PROJECT_ID"
gcloud config set run/region "$REGION"

認証を行います(ブラウザが開きます):

gcloud auth login
gcloud auth application-default login

必要なAPIの有効化

Google Cloud で多くの人がつまずく点として、必要な API を明示的に有効化しないと何も動作しないことが挙げられます。これはブレーカーを切り替えるようなものと考えてください。以下のコマンドを一度実行すれば完了です:

gcloud services enable 
  run.googleapis.com 
  cloudbuild.googleapis.com 
  workflows.googleapis.com 
  artifactregistry.googleapis.com 
  cloudscheduler.googleapis.com 
  bigquery.googleapis.com 
  firestore.googleapis.com 
  secretmanager.googleapis.com

以下のコマンドで全てが有効化されていることを確認できます:

gcloud services list --enabled | rg "run.googleapis.com|cloudbuild.googleapis.com|workflows.googleapis.com|artifactregistry.googleapis.com|cloudscheduler.googleapis.com|bigquery.googleapis.com|firestore.googleapis.com"
carbon

Firestore の設定

ジョブ追跡データの保存と結果のスクレイピングには、ネイティブモードのFirestoreが必要です:

gcloud firestore databases create --location="$REGION" --type=firestore-native

このプロジェクトに既にFirestoreが設定されている場合は、この手順をスキップできます。データベースが既に存在するというエラーが発生します。

アーティファクト レジストリの作成

アーティファクト レジストリは Docker イメージの保管場所です。GCP 上のプライベート コンテナ レジストリと考えてください:

gcloud artifacts repositories create "$REPO_NAME" 
  --repository-format=docker 
  --location="$REGION" 
  --description="Docker images for cloud-run-スクレイパー"

次に、Docker に認証方法を指示します:

gcloud auth configure-docker "$REGION-docker.pkg.dev"

BigQueryの設定

次に、スクレイピングされたデータを格納するBigQueryデータセットとテーブルを作成します。これがパイプライン全体の有用性です。構造化されたETLパイプラインフローにより、スクレイピングされた全データに対してSQLクエリを実行し、トレンドの抽出、ソース別のフィルタリング、ダッシュボード構築が可能になります。

データセットを作成:

bq --location="$REGION" mk -d "$PROJECT_ID:$BQ_DATASET"

次に、スクレイパーで使用するスキーマでテーブルを作成します:

bq mk --table 
  "$PROJECT_ID:$BQ_DATASET.$BQ_TABLE" 
  url:STRING,title:STRING,content:STRING,scraped_at:TIMESTAMP,job_id:STRING,source:STRING,metadata:STRING

動作確認:

bq show "$PROJECT_ID:$BQ_DATASET.$BQ_TABLE"

IAM権限の設定

この部分は最もエキサイティングではありませんが、非常に重要です。Cloud Runサービスは、Firestore、BigQuery、および相互通信を行うための権限が必要です。これらのIAMバインディングがないと、明確な説明のない不可解な403エラーが発生します。

まず、コンピューティングサービスアカウントを取得します:

PROJECT_NUMBER=$(gcloud projects describe "$PROJECT_ID" --format="value(projectNumber)")
COMPUTE_SA="${PROJECT_NUMBER}[email protected]"
echo "$COMPUTE_SA"

次に必要なロールを付与します:

gcloud projects add-iam-policy-binding "$PROJECT_ID" 
  --member="serviceAccount:${COMPUTE_SA}" 
  --role="roles/datastore.user"

gcloud projects add-iam-policy-binding "$PROJECT_ID" 
  --member="serviceAccount:${COMPUTE_SA}" 
  --role="roles/bigquery.dataEditor"

gcloud projects add-iam-policy-binding "$PROJECT_ID" 
  --member="serviceAccount:${COMPUTE_SA}" 
  --role="roles/bigquery.jobUser"

gcloud projects add-iam-policy-binding "$PROJECT_ID" 
  --member="serviceAccount:${COMPUTE_SA}" 
  --role="roles/run.invoker"

gcloud projects add-iam-policy-binding "$PROJECT_ID" 
  --member="serviceAccount:${COMPUTE_SA}" 
  --role="roles/workflows.invoker"

これは5つのロールバインディングです。それぞれがサービスアカウントに特定の操作を許可します:Firestoreの読み取り/書き込み、BigQueryへの挿入、Cloud Runサービスの呼び出し、ワークフローのトリガーです。

依存関係のインストール

リポジトリのルートディレクトリから、両サービスの依存関係をインストールします:

npm --prefix scraper-service install
npm --prefix api-service install

スクレイパーサービスのデプロイ

これはパイプライン全体の主力です。URLを訪問し、コンテンツを取得し、結果をFirestoreとBigQueryに書き込むサービスです。スクレイパーでより複雑なボット対策シナリオを処理したい場合は、Bright Dataのスクレイピングブラウザのようなツールを検討する価値があります。クラウドベースのブラウザ自動化を大規模に行うのに適しています。

プライベートサービスとしてデプロイします。--no-allow-unauthenticatedフラグに注意してください。ワークフローからのリクエストなど、認証済みリクエストのみが呼び出せます:

gcloud run deploy scraper-service 
  --source ./scraper-service 
  --region "$REGION" 
  --memory 2Gi 
  --cpu 2 
  --timeout 300 
  --no-allow-unauthenticated 
  --set-env-vars NODE_ENV=production

デプロイ完了後にURLを取得:

SCRAPER_URL=$(gcloud run services describe scraper-service --region "$REGION" --format='value(status.url)')
echo "$SCRAPER_URL"

このURLを保存してください。ワークフロー設定で必要になります。

APIサービスのデプロイ

APIサービスはパイプラインの公開側です。FirestoreとBigQueryから読み込み、エンドポイントを露出させることで、あなたやフロントエンドがスクレイピングされたデータにアクセスできるようにします:

gcloud run deploy api-service 
  --source ./api-service 
  --region "$REGION" 
  --memory 512Mi 
  --cpu 1 
  --timeout 60 
  --allow-unauthenticated 
  --set-env-vars NODE_ENV=production

URLを取得:

API_URL=$(gcloud run services describe api-service --region "$REGION" --format='value(status.url)')
echo "$API_URL"

デプロイ済みサービスのテスト

いよいよ本番サービスの動作確認です。IPブロックやレート制限といったウェブスクレイピングの課題はサーバーレス環境でも発生し得るため、事前に対策を検討しておくことをお勧めします。

APIサービスに対して以下を試してみてください:

curl -s "$API_URL/"
curl -s "$API_URL/jobs?limit=10"
curl -s "$API_URL/analytics/summary"

スクレイパーは非公開サービスであるため、認証トークンを渡す必要があります:

curl -s -X POST 
  -H "Authorization: Bearer $(gcloud auth print-identity-token)" 
  -H "Content-Type: application/json" 
  -d '{"url":"http://books.toscrape.com"}' 
  "$SCRAPER_URL/scrape"

ページ上の特定の要素をターゲットにしたい場合は、カスタムCSSセレクタを渡すこともできます:

curl -s -X POST 
  -H "Authorization: Bearer $(gcloud auth print-identity-token)" 
  -H "Content-Type: application/json" 
  -d '{"url":"http://books.toscrape.com","selectors":{"title":"h1, h2","content":"p, article"}}' 
  "$SCRAPER_URL/scrape"

ワークフローの設定

ワークフローはスクレイパーをスケジュールに紐付けるものです。これはYAMLファイルであり、Cloud Workflowsにリスト内の各URLに対してスクレイパーを呼び出すよう指示します。

workflows/scrape-pipeline.yamlを開き、scraper_urlをスクレイパーデプロイメントステップで取得したURLに設定します。

次にデプロイします:

gcloud workflows deploy scrape-pipeline 
  --location "$REGION" 
  --source workflows/scrape-pipeline.yaml 
  --service-account "$COMPUTE_SA"

スケジューラジョブの作成

ここでパイプラインが完全に自動化されます。UTC 午前6時に毎日ワークフローを実行するcronジョブを設定します:

gcloud scheduler jobs create http scrape-pipeline-daily 
  --location "$REGION" 
  --schedule "0 6 * * *" 
  --uri "https://workflowexecutions.googleapis.com/v1/projects/${PROJECT_ID}/locations/${REGION}/workflows/scrape-pipeline/executions" 
  --http-method POST 
  --oauth-service-account-email "$COMPUTE_SA" 
  --oauth-token-scope "https://www.googleapis.com/auth/cloud-platform" 
  --message-body '{"argument":"{"urls":["http://books.toscrape.com","http://quotes.toscrape.com"]}"}'

ジョブが既に存在し、更新のみを行う場合:

gcloud scheduler jobs update http scrape-pipeline-daily 
  --location "$REGION" 
  --schedule "0 6 * * *" 
  --uri "https://workflowexecutions.googleapis.com/v1/projects/${PROJECT_ID}/locations/${REGION}/workflows/scrape-pipeline/executions" 
  --http-method POST 
  --oauth-service-account-email "$COMPUTE_SA" 
  --oauth-token-scope "https://www.googleapis.com/auth/cloud-platform" 
  --message-body '{"argument":"{"urls":["http://books.toscrape.com","http://quotes.toscrape.com"]}"}'

最初のフルテストの実行

スケジューラーを待機しないでください。ワークフローを手動でトリガーし、パイプライン全体の実行を確認します:

gcloud workflows run scrape-pipeline 
  --location "$REGION" 
  --data '{"urls":["http://books.toscrape.com","http://quotes.toscrape.com"]}'

実行状況は以下で監視できます:

gcloud workflows executions list scrape-pipeline --location "$REGION"

1~2分待ちます。実行結果がSUCCEEDED と表示されれば、データが Firestore と BigQuery に流れ込んでいるはずです。

データの確認

では、データが実際に所定の場所に到達したか確認しましょう。

BigQueryで行数を確認します:

bq query --use_legacy_sql=false "SELECT COUNT(*) AS total_rows FROM `${PROJECT_ID}.${BQ_DATASET}.${BQ_TABLE}`"

最新のスクレイピング結果を確認:

bq query --use_legacy_sql=false "SELECT source, url, scraped_at, job_id FROM `${PROJECT_ID}.${BQ_DATASET}.${BQ_TABLE}` ORDER BY scraped_at DESC LIMIT 10"

コンソールで Firestore を確認してください。jobsresults の 2 つのコレクションが表示されるはずです。

次にAPIを実行し、全データが読み取れることを確認します:

curl -s "$API_URL/jobs?limit=1"

レスポンスからjobIdを取得し、さらに掘り下げます:

curl -s "$API_URL/jobs/YOUR_JOB_ID"
curl -s "$API_URL/results/YOUR_JOB_ID"

これらがすべてデータを返す場合、パイプラインはエンドツーエンドで動作しています。

Cloud Build による CI/CD

リポジトリには、両サービスのビルドとデプロイを一括処理するcloudbuild.yamlファイルが含まれています。変更をデプロイする際は以下を実行してください:

gcloud builds submit --config cloudbuild.yaml .

この単一コマンドで両Dockerイメージをビルドし、Artifact Registryにプッシュ後、両Cloud Runサービスをデプロイします。単一パイプラインを超える拡張を検討中なら、主要ウェブスクレイピングツールの概要を確認し、このクラウド基盤を補完する多様なソリューションを調査してください。

最終チェックリスト

完了前に以下の検証手順を実行してください:

  1. gcloud run services list --region us-central1で両方のサービスが表示されることを確認してください。
    carbon (1)
  2. gcloud workflows describe scrape-pipeline --location us-central1でワークフローの詳細が返されるはずです。
    carbon (2)
  3. gcloud scheduler jobs list --location us-central1でスケジューラジョブが表示されるはずです。
    carbon (3)
  4. Firestoreにジョブ結果のコレクションが存在すること。
  5. BigQueryテーブルには行が存在するはずです。
  6. APIの/jobsエンドポイントは実際のレコードを返すはずです。

これら6つの項目すべてが正常に動作している場合、もはやデモを実行しているわけではありません。スケジュールに従ってスクレイピングを行い、2か所にデータを保存し、パブリックAPIを通じて提供する、本物のパイプラインを運用していることになります。

まとめ

本ガイドでは、Google Cloud 上で完全なサーバーレス ウェブスクレイピング パイプラインを構築する手順を解説しました。インフラストラクチャの設定、2 つの Cloud Run サービスのデプロイ、Cloud Workflows によるウェブスクレイピング実行のオーケストレーション、Cloud Scheduler による全プロセスの自動化について取り上げました。

インフラの維持管理よりもマネージドなアプローチを好む場合は、Bright Dataの事前収集済みデータセット やスクレイパー Studioを活用し、任意のウェブサイトを既製のデータパイプラインに変換できます。また、ScrapyとAWSを用いたサーバーレススクレイピングのガイドを参照すれば、異なるクラウドプロバイダーにおける類似アーキテクチャの構築方法を確認できます。プロジェクトをクローンし、自身のターゲットURLを差し替えれば、スクレイピングパイプラインを稼働させられます。