Bright Data で SEO 順位調査を自動化する完全ガイド 2026 - SERP API で毎日ランキングを取得する実装手順
Bright Data SERP API を使った SEO 順位調査の自動化手順を、抽出ロジック・保存先・スケジューラ・アラート・コスト試算まで実運用目線で整理しました。
SEO 順位調査を毎日自動で回す現実解は、Bright Data SERP API + スケジューラ + データウェアハウスの組み合わせです。本記事では最小構成 (GitHub Actions + Sheets + Slack) と本格運用 (Cloud Scheduler + BigQuery + Looker Studio) の 2 パターンを軸に、抽出ロジック・保存先・コスト試算まで実装目線で整理します。
SEO 順位調査を自動化する全体像と Bright Data の位置づけ
SEO 順位調査の自動化は、以下の 5 層で考えると設計が楽になります。
- SERP 取得層: 検索結果ページを構造化 JSON で取得する API
- 抽出層: レスポンスから対象ドメインの順位 (
organic_position) を抽出 - 保存層: 日次・キーワード単位の履歴を蓄積するストレージ
- スケジューラ層: 毎日決まった時刻に取得ジョブを起動する仕組み
- 可視化・通知層: ダッシュボード表示と順位変動の Slack/Email 通知
Bright Data SERP API は (1) の SERP 取得層を担う API で、Google / Bing / Yandex / DuckDuckGo の検索結果を country / language / device / location パラメータで細かく指定して取得できます。SERP API そのものの認証手順・パラメータ詳細・コスト全般は Bright Data SERP API を Python で実装する完全ガイド 2026 で網羅しているので、本記事ではそこから先の (2)〜(5) を中心に扱います。
なぜ Bright Data SERP API を選ぶか
順位調査用途で見た SERP API 選定のポイントは 3 つです。
- 地域・デバイスの細かさ: country だけでなく location (市区町村) を指定できるため、ローカル SEO や複数地域の店舗集客分析で再現性のある結果が取れる
- 構造化フィールドの網羅:
organic_resultsだけでなくfeatured_snippetpeople_also_askknowledge_graphadsまで揃っており、2026 年に重要度が増している AI Overview の出現有無まで構造化レスポンスから判定できる - エンタープライズ SLA: 自社レポーティングを社内に出すレベルの安定性が求められる場面で、SLA 付き API があるのは大きい
DataForSEO や SerpApi も同じレイヤーの製品で、最終的にはコストとデータ品質の両面で比較するのが定石です。Bright Data は IP プール規模と KYC 済み IP の運用ポリシーで信頼性は高めですが、超低単価という競争軸では DataForSEO や Serper.dev のような新興プレイヤーに分があります。Bright Data 自体を価格軸で評価したい場合は Bright Data 料金プラン早見表 2026 も合わせて確認してください。
公式コミュニティでも、Bright Data SERP API は競争の激しいキーワードでも高い成功率と地域別の精度で評価されているという声が出ています。

SERP API のレスポンスから順位を抽出するロジック
SERP API の認証・パラメータ・レスポンス構造の全体像は Bright Data SERP API を Python で実装する完全ガイド 2026 で網羅していますので、本記事では「取得済みレスポンスから順位 (organic_position) をどう抽出して継続活用するか」に焦点を絞ります。実装そのものより、抽出後の正規化と「順位なし」の扱いを揃えるほうが、毎日蓄積するデータの品質を大きく左右します。
最小実装 — Python で organic_position を取り出す
下記は SERP API のレスポンスを受け取った後、対象ドメインの順位だけを取り出す最小ヘルパーです。API 呼び出し部分の詳細は前述のリンク先を参照してください。
import urllib.parse
from typing import Optional
def extract_rank(serp_response: dict, target_domain: str) -> Optional[dict]:
"""SERP API レスポンスから対象ドメインの順位を抽出する。"""
target_host = urllib.parse.urlparse(f"https://{target_domain}").netloc.lower()
for item in serp_response.get("organic_results", []):
item_host = urllib.parse.urlparse(item.get("link", "")).netloc.lower()
if item_host.endswith(target_host):
return {
"position": item.get("position"),
"matched_url": item.get("link"),
"featured_snippet": bool(serp_response.get("featured_snippet")),
"people_also_ask_count": len(serp_response.get("people_also_ask", []) or []),
}
return {"position": None, "matched_url": None,
"featured_snippet": bool(serp_response.get("featured_snippet")),
"people_also_ask_count": len(serp_response.get("people_also_ask", []) or [])}
endswith でホスト比較することでサブドメイン (blog.example.com) も拾え、featured_snippet と people_also_ask のフラグも同時に保存できるようにしています。Bright Data SERP API は Web Unlocker 由来の高い成功率があるため、抽出側の例外処理は最小限で済むことが多いです。
正規化と「順位なし」の扱い
順位データを毎日蓄積するうえで、最低限揃えておくべき正規化ルールがあります。
- クエリの正規化:
strip()→ 全角半角統一 → 小文字化。同じ意味のクエリでpositionが日替わりでブレるのを防ぐ - 「順位なし」の扱い: top 20 に入らない場合、
position = Noneで保存。SQL でIS NULLで集計しやすくなる - 複数 URL がヒットする場合: 自社ドメインで複数 URL が上位に出ているケースは、最上位 1 件のみを
positionとして記録し、サブ位置は別カラム (例:secondary_positions JSON) に持つ - SERP feature 出現フラグ: AI Overview 出現有無や People Also Ask の件数を
bool/intで同時に持つ。2026 年は順位 1 位でも AI Overview の影響でクリック率が落ちる場面が増えており、後から再分析できる形で残しておく
データを継続保存する設計 — Google Sheets / BigQuery / Postgres
抽出した順位データは、用途と規模に応じて保存先を変えるのが定石です。本節では Google Sheets と BigQuery、そして Postgres の 3 パターンを、実装サンプル付きで整理します。
構成パターンと使い分け
| 規模 | 推奨保存先 | 推奨スケジューラ | ダッシュボード |
|---|---|---|---|
| 100 KW 以下・1〜2 地域 | Google Sheets | GitHub Actions | Looker Studio (Sheets 接続) |
| 1,000 KW・複数地域・履歴 1 年以上 | BigQuery | Cloud Scheduler + Cloud Functions | Looker Studio (BigQuery 接続) |
| 10,000 KW 超・社内アプリ連携 | Postgres (Cloud SQL / Supabase) | EventBridge + Lambda or 自社 Cron | Metabase / Redash |
100 KW 以下なら Sheets で十分、非エンジニアでも編集できる利点が大きいです。1,000 KW 超になるとセル数が膨らんで Sheets ではクエリ性能が頭打ちになるため、BigQuery に移すのが定石です。10,000 KW 超で社内アプリと結合する必要が出てきたら、Postgres 側に貯めて Metabase で見るほうがチーム運用に馴染みます。
実装面では弊社でも、Bright Data の Residential プロキシを使ったホテル価格追跡サービス Tra-bell を Bright Data 上で運用しており、その経験から SERP API も同じインフラに同居させると認証管理と運用負荷の集約が楽になることが多いと感じています。
サンプル A: Python → Google Sheets
最小構成として、抽出済みの行を Google Sheets に追記するパターンです。サービスアカウントの JSON 鍵で認証する前提です。
import datetime as dt
import os
import gspread
from google.oauth2.service_account import Credentials
SCOPES = ["https://www.googleapis.com/auth/spreadsheets"]
SHEET_ID = os.environ["RANK_SHEET_ID"]
SHEET_TAB = "rank_history"
def get_sheet():
creds = Credentials.from_service_account_file(
os.environ["GOOGLE_APPLICATION_CREDENTIALS"], scopes=SCOPES
)
client = gspread.authorize(creds)
return client.open_by_key(SHEET_ID).worksheet(SHEET_TAB)
def append_rank(row: dict) -> None:
sheet = get_sheet()
sheet.append_row(
[
dt.date.today().isoformat(),
row["query"],
row["target_domain"],
row["country"],
row["device"],
row["location"] or "",
row["position"] if row["position"] is not None else "",
"Y" if row["featured_snippet"] else "",
row["people_also_ask_count"],
row["matched_url"] or "",
],
value_input_option="USER_ENTERED",
)
Sheets はカラム順を保ちつつ append するだけなので、Looker Studio の接続もコネクタ 1 つで終わります。100 KW × 30 日 = 3,000 行程度なら 1 シートで完結します。
サンプル B: Python → BigQuery (Cloud Scheduler 連携前提)
本格運用するなら BigQuery に貯めるのが楽です。google-cloud-bigquery で INSERT します。
import datetime as dt
import os
from google.cloud import bigquery
PROJECT = os.environ["GCP_PROJECT"]
DATASET = "seo_rank"
TABLE = "rank_history"
client = bigquery.Client(project=PROJECT)
table_ref = f"{PROJECT}.{DATASET}.{TABLE}"
def insert_rank(rows: list[dict]) -> None:
payload = []
for row in rows:
payload.append(
{
"date": dt.date.today().isoformat(),
"query": row["query"],
"target_domain": row["target_domain"],
"country": row["country"],
"device": row["device"],
"location": row["location"],
"position": row["position"],
"featured_snippet": row["featured_snippet"],
"people_also_ask_count": row["people_also_ask_count"],
"matched_url": row["matched_url"],
}
)
errors = client.insert_rows_json(table_ref, payload)
if errors:
raise RuntimeError(f"BigQuery insert errors: {errors}")
# DDL (BigQuery コンソール側で 1 回作成)
# CREATE TABLE seo_rank.rank_history (
# date DATE NOT NULL,
# query STRING NOT NULL,
# target_domain STRING NOT NULL,
# country STRING NOT NULL,
# device STRING NOT NULL,
# location STRING,
# position INT64,
# featured_snippet BOOL,
# people_also_ask_count INT64,
# matched_url STRING
# )
# PARTITION BY date
# CLUSTER BY query, country, device;
PARTITION BY date と CLUSTER BY query, country, device を付けておくと、後段の集計クエリ (前日比 delta、移動平均、地域別比較) が極めて速くなります。BigQuery 側のコストも WHERE date BETWEEN ... で常にパーティションプルーニングが効くので、月額数 USD で収まるケースが多いです。
サンプル C: Node.js → Postgres + Slack Webhook 通知
Node.js で組む場合の Postgres 保存 + Slack 通知サンプルです。順位が前回より 5 位以上落ちたら Slack に通知する形にしています。
import axios from "axios";
import pg from "pg";
const { Client } = pg;
const SLACK_WEBHOOK_URL = process.env.SLACK_WEBHOOK_URL;
const pgClient = new Client({ connectionString: process.env.DATABASE_URL });
await pgClient.connect();
async function saveAndNotify(row) {
const previous = await pgClient.query(
`SELECT position FROM rank_history
WHERE query = $1 AND target_domain = $2 AND country = $3 AND device = $4
ORDER BY date DESC LIMIT 1`,
[row.query, row.target_domain, row.country, row.device],
);
await pgClient.query(
`INSERT INTO rank_history
(date, query, target_domain, country, device, location, position,
featured_snippet, people_also_ask_count, matched_url)
VALUES (CURRENT_DATE, $1, $2, $3, $4, $5, $6, $7, $8, $9)`,
[
row.query,
row.target_domain,
row.country,
row.device,
row.location,
row.position,
row.featured_snippet,
row.people_also_ask_count,
row.matched_url,
],
);
const prevPos = previous.rows[0]?.position;
const currPos = row.position;
if (prevPos != null && currPos != null && currPos - prevPos >= 5) {
await axios.post(SLACK_WEBHOOK_URL, {
text:
`:warning: "${row.query}" (${row.country}/${row.device}) の順位が ` +
`${prevPos}位 → ${currPos}位 に低下しました`,
});
}
}
Postgres + Slack Webhook の組み合わせは、初期構築が 1 日で済むのが利点です。AWS Lambda 上で動かす場合は Bright Data + Lambda の運用パターンが AWS Lambda × Bright Data でサーバーレス スクレイピング基盤を構築する方法 2026 で詳しく整理されており、SERP API の呼び出しもほぼ同じ構成で組めます。
毎日自動実行のスケジューラ設計
順位調査は「毎日決まった時刻に確実に走る」ことが価値の源泉です。本節では Cron / GitHub Actions / Cloud Scheduler / EventBridge の 4 つを、想定規模別に整理します。
想定規模別の選択肢
| 規模 | スケジューラ | 実行先 | 設定の手間 |
|---|---|---|---|
| 小 (100 KW 以下) | GitHub Actions | リポジトリ内のスクリプト | 1〜2 時間 |
| 中 (1,000 KW) | Cloud Scheduler | Cloud Functions / Cloud Run Jobs | 半日 |
| 大 (10,000 KW 超) | EventBridge | Lambda + SQS | 1〜2 日 |
| 自社サーバー前提 | Cron | EC2 / 社内マシン | 30 分 |
GitHub Actions の長所はリポジトリと地続きでスクリプトとスケジュールを管理できること、無料枠で 2,000 分 / 月使えることです。Cloud Scheduler は GCP 課金が前提ですが、Cloud Functions と組み合わせて 99.9% 程度の信頼性が確保できます。
X 上の開発者コミュニティでも、SERP API + スケジューラ + データウェアハウスの 3 点セットでスモールスタートし、規模に応じて段階的に拡張するパターンが現実解として共有されています。
GitHub Actions の例
最も手軽な GitHub Actions の例です。毎日 JST 9:00 に Python スクリプトを実行します。
# .github/workflows/rank-tracker.yml
name: SEO Rank Tracker
on:
schedule:
- cron: "0 0 * * *" # 毎日 UTC 00:00 = JST 9:00
workflow_dispatch:
jobs:
fetch-rank:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install dependencies
run: pip install httpx gspread google-auth
- name: Run rank fetcher
env:
BRIGHT_DATA_API_TOKEN: ${{ secrets.BRIGHT_DATA_API_TOKEN }}
BRIGHT_DATA_SERP_ZONE: ${{ secrets.BRIGHT_DATA_SERP_ZONE }}
GOOGLE_APPLICATION_CREDENTIALS: ${{ secrets.GCP_SA_JSON_PATH }}
RANK_SHEET_ID: ${{ secrets.RANK_SHEET_ID }}
run: python scripts/fetch_rank.py
シークレット 4 種類を GitHub の Secrets に登録するだけで起動します。GitHub Actions は祝日や年末年始でも問題なく動き、ジョブが失敗したら GitHub から通知が来るので、運用負荷は最小です。
Cloud Scheduler + Cloud Functions の例
GCP 上で BigQuery と組み合わせるなら Cloud Scheduler が最短です。Terraform で組むと再現性が高くなります。
resource "google_cloud_scheduler_job" "rank_tracker" {
name = "seo-rank-tracker"
description = "Trigger SEO rank tracker every day at 09:00 JST"
schedule = "0 0 * * *"
time_zone = "Etc/UTC"
attempt_deadline = "320s"
http_target {
http_method = "POST"
uri = google_cloudfunctions2_function.rank_tracker.service_config[0].uri
oidc_token {
service_account_email = google_service_account.scheduler_invoker.email
}
}
}
Cloud Functions 側では、Python の SERP API 呼び出しと insert_rank() を呼ぶだけのハンドラを用意すれば完了です。実行時間が 9 分以内に収まらない場合 (10,000 KW 超など) は Cloud Run Jobs に切り替え、SQS / Pub/Sub と組み合わせて分散実行する形にします。
EventBridge + Lambda の例
AWS 環境で組むなら EventBridge が定石です。
{
"Source": "aws.events",
"DetailType": "Scheduled Event",
"ScheduleExpression": "cron(0 0 * * ? *)"
}
Lambda の同時実行数を 10〜20 に設定し、SQS に投入したキーワードを並列で処理する形にすれば、10,000 KW 規模でも 10〜15 分で全件取得が終わります。Bright Data SERP API 側のレート制限に当たらないよう、Lambda の Reserved Concurrency で並列度をコントロールするのが安全です。

アラートとダッシュボード — Slack / Discord / Email + Looker Studio / Metabase
毎日順位を取得しても、「何が起きたか」がチームに届かなければ意味がありません。本節ではアラートとダッシュボードの組み方を整理します。
アラート設計の基本ルール
- 閾値ベース: 順位が前日比 -5 以上、または top 10 → 圏外などの落差で発火
- 頻度制限: 同じキーワードで連続して通知が飛ばないよう、24 時間に 1 件まで
- チャンネルの使い分け: 致命的な順位低下は
#seo-alertsに Slack 通知、軽微な変動は週次サマリのみで Email 送信 - AI Overview 出現アラート: 順位 1 位でも AI Overview の影響を受けるため、AI Overview の新規出現も別アラートで通知
Slack 通知の最小サンプル
Slack Incoming Webhook を使った最小サンプルです。BigQuery のスケジュールクエリで delta を計算し、結果を Cloud Functions が読んで Slack に流すパターンが弊社の標準です。
import os
import httpx
from google.cloud import bigquery
SLACK_WEBHOOK_URL = os.environ["SLACK_WEBHOOK_URL"]
client = bigquery.Client()
SQL = """
WITH today_rank AS (
SELECT query, country, device, position
FROM `seo_rank.rank_history`
WHERE date = CURRENT_DATE()
),
yesterday_rank AS (
SELECT query, country, device, position
FROM `seo_rank.rank_history`
WHERE date = DATE_SUB(CURRENT_DATE(), INTERVAL 1 DAY)
)
SELECT
t.query,
t.country,
t.device,
y.position AS prev_position,
t.position AS curr_position,
t.position - y.position AS delta
FROM today_rank t
JOIN yesterday_rank y USING (query, country, device)
WHERE y.position IS NOT NULL
AND t.position IS NOT NULL
AND t.position - y.position >= 5
"""
for row in client.query(SQL).result():
text = (
f":warning: 「{row.query}」({row.country}/{row.device}) "
f"順位が {row.prev_position}位 → {row.curr_position}位 に低下 (delta={row.delta})"
)
httpx.post(SLACK_WEBHOOK_URL, json={"text": text}, timeout=10)
Discord も同じ Incoming Webhook 形式で送れます。Email は SendGrid / SES のテンプレ送信に置き換えれば対応可能ですが、運用負荷を考えると Slack に集約するのが現実的です。
ダッシュボードの構成例
可視化の選択肢は以下のとおりです。
- Google Sheets + Looker Studio: 100 KW 以下の小規模運用。Sheets コネクタで直結できる。導入工数は半日
- BigQuery + Looker Studio: 1,000 KW 以上のスタンダード構成。BigQuery のスケジュールクエリで集計済みテーブルを作り、Looker Studio から見ると速い
- Postgres + Metabase: 自社アプリと統合する場合や、SQL を直接書きたいケース。社内エンジニア向け
- Postgres + Redash: チーム共有のダッシュボードを作りたい中規模組織向け
ダッシュボードに最低限載せたい指標は「平均順位の推移」「圏外キーワード件数」「AI Overview 出現キーワード件数」「上昇 / 下降の前日差ランキング」の 4 つです。これらを 1 枚にまとめておくと、朝の SEO ミーティングの素材として 5 分で共有できます。
コスト見積もりとまとめ
最後に、SERP API 利用時の月額コストを試算する考え方と、実装パターン別の月額目安をまとめます。
コスト試算の式
順位調査の月額リクエスト数は次の式で計算できます。
月額リクエスト数
= キーワード数 × 地域数 × デバイス数 × 実行頻度 × 30 日
たとえば 1,000 KW × 3 地域 × 2 デバイス × 日次 = 18 万リクエスト / 月、SERP API 標準単価 $3 / 1k で月額約 $540 (≒¥81,000) です。月 100 万リクエストを超えるとボリュームディスカウントが適用され、30〜50% 値引きされます。
実装パターン別の月額目安
| 構成 | キーワード数 | 地域 × デバイス | 月額リクエスト | 月額コスト (SERP API のみ) |
|---|---|---|---|---|
| 最小: GitHub Actions + Sheets | 50 | 1 × 1 | 1,500 | $5 前後 (≒¥750) |
| 小規模: GitHub Actions + BigQuery | 200 | 2 × 2 | 24,000 | $72 前後 (≒¥10,800) |
| 中規模: Cloud Scheduler + BigQuery | 1,000 | 3 × 2 | 180,000 | $540 前後 (≒¥81,000) |
| 大規模: EventBridge + Lambda + Postgres | 5,000 | 5 × 2 | 1,500,000 | $3,000 前後 (≒¥450,000、コミットメント割引で半額余地あり) |
SERP API 単価以外のインフラ費用 (GitHub Actions 無料枠、BigQuery ストレージ $0.02/GB/月、Cloud Functions 実行費用 < $5/月 など) は誤差レベルですが、月額予算が $1,000 を超える規模では年間契約コミットメントの交渉余地が出てきます。
コスト最適化の 4 ステップ
- キャッシュ層を必ず挟む: 同じ (query, country, language, device) は 24 時間キャッシュ
num_resultsを絞る: 監視対象が top 20 で十分なら 20 に固定。num_results=100は無駄が大きい- 失敗リクエストのリトライ上限: 3〜5 回までで打ち切り、無限ループを防止
- モニタリング: 月次で「課金リクエスト数 / 全リクエスト数」を計測し、想定との乖離を早期発見
弊社では、Bright Data の Residential プロキシをホテル価格追跡サービス Tra-bell でも運用しており、SERP API と Residential プロキシを 1 つの基盤で組み合わせて運用するノウハウがあります。SEO 順位調査 + 国内 EC 価格モニタリングを同じ Bright Data 契約で回す設計に興味があれば、別記事として Bright Data で国内 EC データパイプラインを設計するガイド 2026 もあわせてご覧ください。
まとめ
Bright Data SERP API を使った SEO 順位調査の自動化は、SERP 取得・抽出・保存・スケジューラ・可視化通知の 5 層で組むのが定石でした。最小構成なら GitHub Actions + Google Sheets + Slack Webhook で 1 日で立ち上がり、本格運用なら Cloud Scheduler + BigQuery + Looker Studio で 1,000 KW 規模が月額 $540 前後で運用できます。Bright Data SERP API の認証・パラメータ詳細は Bright Data SERP API を Python で実装する完全ガイド 2026 で網羅していますので、本記事と合わせて読むと実装のステップが順に揃います。順位データはコンテンツ運用の意思決定そのものなので、まずは小さく立ち上げて、3〜6 か月で BigQuery への移行を見据えるのが現実的な進め方です。
※情報は 2026-05-22 時点の内容です。最新情報は公式サイトをご確認ください。
※本記事には PR を含みます。
よくある質問
関連記事

Bright Data SERP API を Python で実装する完全ガイド 2026 - 認証・パラメータ・コスト設計


