ブログに戻ります

Google Search APIを使用してPythonでランクトラッカーを構築する方法

Isabella Garcia
Isabella Garcia

Web Data Collection Specialist

16-Sep-2026

TL;DR:

  • ランクトラッカーは時間経過に伴うパイプラインであり、1回のSERPリクエストではありません。 クエリ、場所、言語、デバイス、検索ドメイン、観察時間、ランク付けURL、および位置を保持する必要があります。
  • 生のSERP観察が必要なときは検索APIを使用してください。 キーワード発見、レポート、アラート、クライアントワークフローも必要なときは、フルSEOプラットフォームを使用してください。
  • ターゲットドメインをマッチングする前にホスト名を正規化してください。 www.example.com、スキームの違い、パス、およびサブドメインを明示的なポリシーに従って扱います。
  • 「未ランク」をデータとして記録します。 不在を位置ゼロに変換せず、昨日の位置を持ち越さないでください。
  • ランクとともにランク付けURLも保存します。 ドメインはランディングページが変更されてもその位置を保持することができます。
  • スクレイピング不要のGoogle検索APIは構造化された検索データを返します。 以下のPython実装はSERPをリクエストし、有機的結果を解析し、追加専用のCSVスナップショットを書き込みます。

ランクトラッカーが実際に測定するもの

ランクトラッカーは、特定の検索結果セットにおいて特定の時間にターゲットドメインがどこに表示されるかを観察します。

その定義は故意に狭いものです。位置はクエリ、国または場所、言語、Googleドメイン、デバイス、結果タイプ、およびページネーションの深さに依存します。1つの次元を変更すると、観察は異なる系列に属します。

信頼できる記録には少なくとも次のものが含まれているべきです:

  • キーワード
  • ターゲットドメイン
  • 観察された位置または明示的な未ランク状態
  • ランク付けURL
  • 結果タイトル
  • 国または場所設定
  • 言語
  • デバイス
  • Googleドメイン
  • 観察タイムスタンプ

トラッカーは、サンプリングされたSERPが普遍的なランクであることを示唆してはなりません。パーソナライズ、実験、インデックス変更、地域差は検索の一部です。

検索APIとランクトラッキングプラットフォームの比較

検索APIとランクトラッキングプラットフォームは、関連していますが異なるジョブを解決します。

必要 検索API ランクトラッキングプラットフォーム
生の有機的結果記録 強力にフィット プラットフォームモデルを通じて利用可能なことが多い
カスタムマッチングロジック 完全な制御 プラットフォームに依存
自分のデータベースとダッシュボード あなたが構築する 多くの場合含まれている
キーワード発見 別のワークフロー 多くの場合含まれている
ホワイトラベルレポート あなたが構築する 多くの場合含まれている
異常なサンプリングスケジュール 完全な制御 プラン依存
内部データとの統合 直接 エクスポートまたはAPI依存

ランク観察が内部製品、実験、またはデータウェアハウスへの1つの入力の場合はAPIを選択してください。アナリストが既製のインターフェースとレポートワークフローを必要とする場合はプラットフォームを選択してください。

Google検索APIリクエストモデル

スクレイピング不要のGoogle検索APIは検索パラメータを受け入れ、構造化データを返します。現在のGoogle検索APIのドキュメントは、クエリ、国、言語、Googleドメイン、結果タイプ、オフセット、結果数などの一般的なパラメータを文書化しています。

製品のコピーでは、現在の顧客向け名称であるGoogle検索APIを使用してください。安定したアクター名とAPIルートは、古い内部名称を保持することがあります。

このガイドで使用されているリクエストは、POSTから/api/v1/scraper/requestへのscraper.google.searchとのリクエストです。認証はx-api-tokenヘッダーに含める必要があります。入力はクエリと検索設定を一緒に保持し、すべてのレスポンスをそのサンプリング設定に追跡できるようにします。

Pythonでトラッカーを構築する

以下のスクリプトは4つの作業を行います:

  1. 各キーワードごとに1つのGoogle検索APIリクエストを送信します。
  2. ターゲットポリシーに一致する最初の有機的結果を見つけます。
  3. 追加専用のCSVスナップショットを書き込みます。
  4. ターゲットが見つからないときにブランクの位置とURLを保持します。

前提条件:ライブリクエストには、SCRAPELESS_API_KEYでScrapeless APIキーが必要です。マッチング、正規化、およびCSVロジックは、認証リクエストを行う前に保存されたレスポンスフィクスチャを使用してローカルでテストできます。

python Copy
import csv
import os
from datetime import datetime, timezone
from pathlib import Path
from urllib.parse import urlparse, urlunsplit

import requests

API_URL = "https://api.scrapeless.com/api/v1/scraper/request"


def normalized_host(value: str) -> str:
    candidate = value if "://" in value else urlunsplit(("https", value, "", "", ""))
    host = (urlparse(candidate).hostname or "").lower().rstrip(".")
    return host.removeprefix("www.")


def host_matches(result_url: str, target_domain: str, include_subdomains=True) -> bool:
    result_host = normalized_host(result_url)
    target_host = normalized_host(target_domain)
    if not result_host or not target_host:
        return False
    return result_host == target_host or (
        include_subdomains and result_host.endswith(f".{target_host}")
    )


def organic_results(payload: dict) -> list[dict]:
    if isinstance(payload.get("organic_results"), list):
        return payload["organic_results"]
    data = payload.get("data", {})
    if isinstance(data, dict) and isinstance(data.get("organic_results"), list):
        return data["organic_results"]
    return []


def find_rank(payload: dict, target_domain: str) -> dict:
    for fallback_position, item in enumerate(organic_results(payload), start=1):
        url = item.get("link") or item.get("url") or ""
        if host_matches(url, target_domain):
            return {
                "position": item.get("position", fallback_position),
                "ranking_url": url,
                "title": item.get("title", ""),
            }
    return {"position": None, "ranking_url": "", "title": ""}


def fetch_serp(keyword: str, *, gl="us", hl="en", device="desktop") -> dict:
    api_key = os.environ["SCRAPELESS_API_KEY"]
    response = requests.post(
        API_URL,
        headers={"x-api-token": api_key, "Content-Type": "application/json"},
        json={
            "actor": "scraper.google.search",
            "input": {
                "q": keyword,
                "gl": gl,
                "hl": hl,
                "google_domain": "google.com",
                "device": device,
                "start": 0,
            },
        },
        timeout=60,
    )
    response.raise_for_status()
    return response.json()


def append_snapshot(path: Path, row: dict) -> None:
    fields = [
        "observed_at", "keyword", "target_domain", "position",
        "ranking_url", "title", "gl", "hl", "device", "google_domain",
    ]
    exists = path.exists()
    with path.open("a", newline="", encoding="utf-8") as handle:
        writer = csv.DictWriter(handle, fieldnames=fields)
        if not exists:
            writer.writeheader()
        writer.writerow(row)


def track(keyword: str, target_domain: str, output="rank_history.csv") -> dict:
    settings = {"gl": "us", "hl": "en", "device": "desktop"}
    payload = fetch_serp(keyword, **settings)
    match = find_rank(payload, target_domain)
    row = {
        "observed_at": datetime.now(timezone.utc).isoformat(),
        "keyword": keyword,
        "target_domain": normalized_host(target_domain),
        "position": match["position"] or "",
        "ranking_url": match["ranking_url"],
        "title": match["title"],
        **settings,
        "google_domain": "google.com",
    }
    append_snapshot(Path(output), row)
    return row


if __name__ == "__main__":
    print(track("web scraping api", "scrapeless.com"))

標準ライブラリのurlparse ドキュメントは、ホスト名解析が文字列スライスではなくURLパーサーを使用するべき理由を説明します。スクリプトは、先頭のwww.のみを削除し、サブドメインをオプションとして受け入れます。そのポリシーは、マルチブランドドメインのトラッキングを開始する前に調整してください。

ポジションパーサーの検証

ライブクレジットを使用する前に、アカウントから実際のAPIレスポンスを1つ保存し、それに対してパーサーを実行します。少なくとも次のフィクスチャを含めてください:

フィクスチャ 期待される結果
正確な頂点ドメイン 一致した
www. バージョン 一致した
許可されたサブドメイン 一致した
example.com.attacker.test のような類似ドメイン 一致しない
形式が不正または存在しない結果URL 一致しない
サンプルページに目標が存在しない ポジションが空白; 状態はランク付けされていません

APIが明示的な position フィールドを提供する場合は、最初にページネーションを理解せずにリスト順からポジションを計算しないでください。後の結果ページでは、リストインデックス1はグローバルポジション1ではありません。提供されたポジションを保持するか、ページオフセットを意図的に追加してください。

書き換えずにストア履歴を保持する

追加のみのスナップショットは、1つの可変「現在のランク」テーブルよりも監査が容易です。後の変換は、キーワードと市場ごとに最新の行を選択できます。

CSVは個人トラッカーに適しています。生産サービスは、キーワード、ドメイン、国または場所、言語、デバイス、Googleドメイン、観測時間を区別するデータベースキーを使用する必要があります。 SQLiteテーブルのドキュメント は、コンパクトなローカルサービスには十分です。シリーズがダッシュボードやアラートにフィードされる場合、倉庫は役立ちます。ここで使用されているホスト名ポリシーを超えるURLアイデンティティルールについては、 URI一般構文標準 を参照してください。

positionranking_url の両方を保持してください。これらの変更は異なる意味を持ちます:

  • ポジションが変更され、URLが変更されない:同じランディングページが移動しました;
  • ポジションが変更されず、URLが変更される:Googleが異なるページを選択しました;
  • ポジションが空白:ドメインがサンプル結果の深さ内で見つかりませんでした;
  • ドメインから複数のURLが表示される:最良のポジションを保存し、オプションで詳細テーブルにすべての一致を保持します。

地域、言語、デバイス、時間を扱う

検索設定を次元として扱い、後で追加されたオプションのラベルとして考えないでください。

  • gl は国のコンテキストを示します。
  • hl はインターフェースの言語を制御します。
  • google_domain はGoogleプロパティを選択します。
  • device はサポートされている場合、デスクトップとモバイルの観測を区別します。
  • 正確なロケーション設定は、国よりも狭い市場をモデル化できます。
  • タイムスタンプはストレージでUTCを使用し、表示のためだけに変換する必要があります。

同じチャートラインの下で、市レベルのシリーズと国レベルのシリーズを混同しないでください。同様に、モバイルの結果がデスクトップの観測を静かに置き換えてはなりません。

サンプリング時間も重要です。1つの限られたウィンドウで比較可能なキーワードグループを実行します。バッチが数時間に及ぶ場合、全仕事のための1つの日付ではなく、各リクエストのタイムスタンプを保存します。

古い価格を公開せずにコストを計算する

安定した計算は、コピーした計画額よりも有用です:

monthly requests = keywords × markets × devices × pages sampled × runs per month

その後、現在のアカウントレートと失敗処理ポリシーを適用します。オペレーションチームが請求書を説明できるように、計画リクエストを繰り返しおよび失敗した試行から区別します。実装時には、コードが古くなる前に数値を埋め込むのではなく、Scrapelessの価格設定 を確認してください。

Scrapelessでスクレイピングを開始する

Scrapelessであなたのウェブスクレイピングと自動化ワークフローを強化しましょう!
今日サインアップして、$5の無料クレジットを獲得してください — クレジットカード不要

Scrapeless Dashboard で今すぐ無料クレジットを請求してください。

生産チェックリスト

  • パーサーが消費するフィールドのスキーマ契約を固定します。
  • APIキーを秘密マネージャーまたは環境変数に保持します。
  • 一時的なサービス障害の後は、限られたリクエストのみを繰り返します。無限ループしないでください。
  • 各観測の横にリクエスト設定を保存します。
  • ランク付けされていないものをリクエスト失敗から区別します。
  • 数値ポジションだけでなく、ランキングURLを追跡します。
  • パーサー回帰テスト用に、1つの削除された応答フィクスチャを保持します。
  • 適用可能な条件、プライバシー要件、地元の法律を尊重します。
  • SEOの動きにアラートを通知する前に、欠落バッチおよびスキーマのドリフトについてアラートを発します。

結論

有用なランクトラッカーは、規律ある観測システムです。Scrapeless Google Search APIは構造化されたSERPレコードを提供します;その価値は明示的なマッチング、完全な検索次元、追加のみの履歴、および存在しない結果の正直な取り扱いにあります。

1つのキーワード、1つの市場、1つのデバイス、および1つの検証されたフィクスチャから始めてください。シリーズが安定したら、バッチを拡大し、CSVまたはデータベースをダッシュボードに接続します。隣接するワークフローについては、Google Search APIガイドを参照してください。


最初のSERPスナップショットを構築する

実装の助けとデータパイプラインパターンのためにScrapelessコミュニティに参加してください: Discord · Telegram.
無料アカウントを作成し、app.scrapeless.comで1つの制限付きクエリを実行し、トラッカーのスケジュール設定の前に保存されたレスポンスを検証してください。


FAQ

Q: ランクトラッカーAPIとは何ですか?

ランクトラッカーAPIは、ソフトウェアが保存して分析できる検索結果やランク観測を提供します。SERP APIは生の結果レコードを返します。一専用のランクトラッキングAPIは、プロジェクト、履歴、アラート、およびレポートも提供する場合があります。

Q: 自ドメインのオーガニック結果での位置をどうやって調べますか?

オーガニック結果の各URLをURLパーサーで解析し、ホスト名を正規化し、明示的なエイペックス/サブドメインポリシーを適用し、最初に一致した結果の提供された位置を返します。部分文字列の一致を避けてください。

Q: ドメインが欠けている場合、どの位置を保存すべきですか?

サンプリングされた深さに対して、nullまたは空白の位置に加えて、明示的な未ランク状態を保存します。ゼロを使用せず、前回の観測を持ち越さないでください。

Q: ランクトラッカーはどのくらいの頻度で実行すべきですか?

データがサポートする決定に基づいてリズムを選択します。日次サンプリングはアクティブなSEO監視には一般的ですが、より遅い戦略的報告には少ない頻度が必要です。一貫性や比較可能な設定が、最大の頻度よりも重要です。

Q: このスクリプトは普遍的なGoogleランキングを証明しますか?

いいえ。定義されたクエリ、市場、言語、デバイス、ドメイン、深さ、および時間設定に対して1つの構造化された観測を記録します。検索結果は、そのサンプリング設定の外では変動する可能性があります。

Scrapelessでは、適用される法律、規制、およびWebサイトのプライバシーポリシーを厳密に遵守しながら、公開されているデータのみにアクセスします。 このブログのコンテンツは、デモンストレーションのみを目的としており、違法または侵害の活動は含まれません。 このブログまたはサードパーティのリンクからの情報の使用に対するすべての責任を保証せず、放棄します。 スクレイピング活動に従事する前に、法律顧問に相談し、ターゲットウェブサイトの利用規約を確認するか、必要な許可を取得してください。

最も人気のある記事

カタログ