簡潔な回答
PythonからSERP APIを呼び出すには?
https://serpcrypto.com/api/v1/searchにGETリクエストを送信し、requestsまたはhttpxを使い、Authorization: Bearerヘッダーにキー、paramsに検索クエリを設定して、response.json()を読み取ります。SerpCryptoは成功した検索1回につき1クレジットを$0.30/1K検索から課金し、失敗した呼び出しのリトライは無料です。暗号資産で支払い、KYC不要。以下のコードはrequestsまたはhttpxのみ必要です。
Pythonのセットアップ概要
| インストール | pip install requestsまたはpip install httpx |
|---|---|
| キー | 環境変数SERPCRYPTO_API_KEY |
| ヘッダー | Authorization: Bearer <key> |
| タイムアウト | 60〜90秒: 検索はライブで実行されます |
| リトライ | 429、502、504のみ、バックオフ付き。エラーは無料 |
| 並列検索 | GET /creditsから最大concurrency_limit |
再利用可能なPythonクライアントをセットアップするには?
ヘッダーにキーを設定し、3つの一時的エラーに対するリトライポリシーを持つrequests.Sessionを1つ作成します。セッションは接続を再利用するので、検索のループでTLSハンドシェイクに費やす時間が減ります。ファイルをserp_client.pyとして保存してください。次の例ではこれをインポートします。
urllib3のRetryは、各試行前に長く待機し、Retry-Afterヘッダーが送信された場合はそれに従います。400、401、402はリトライしません。これらは再試行ではなく修正が必要です。
"""serp_client.py: a small, reusable client for the SerpCrypto SERP API (requests)."""
import os
import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
API_URL = "https://serpcrypto.com/api/v1/search"
CREDITS_URL = "https://serpcrypto.com/api/v1/credits"
def make_session():
session = requests.Session()
session.headers["Authorization"] = "Bearer " + os.environ["SERPCRYPTO_API_KEY"]
retry = Retry(
total=4,
backoff_factor=1.0, # waits about 1 s, 2 s, 4 s between attempts
status_forcelist=(429, 502, 504),
allowed_methods=("GET",),
respect_retry_after_header=True,
)
session.mount("https://", HTTPAdapter(max_retries=retry))
return session
SESSION = make_session()
def search(q, **params):
"""Run one search (1 credit if it succeeds) and return the parsed JSON."""
r = SESSION.get(API_URL, params={"q": q, **params}, timeout=90)
r.raise_for_status()
return r.json()
def credits():
"""Free: credits left, used today and the concurrency limit."""
r = SESSION.get(CREDITS_URL, timeout=30)
r.raise_for_status()
return r.json()
if __name__ == "__main__":
data = search("project management software", gl="us", hl="en")
for item in data.get("organic_results", []):
print(item["position"], item["link"])
print(credits())10件を超える結果を取得するには?
次のページを1つずつ要求します。1ページあたり約10件のオーガニック結果です。Googleは2025年9月にnum=100を尊重しなくなって以降、この件数を返しています。追加の各ページにはさらに1クレジットが必要です。pagination.next_pageが欠落したらすぐに停止します。これ以上取得するものはなく、クレジットを節約できます。
ほとんどのランキング追跡作業では、1ページ目または最初の3ページで十分です。クリックがそこに集中するためです。1つのキーワードで30件の結果は3クレジットかかります。
from serp_client import search
def top_results(q, pages=3, **params):
"""Collect organic results over several pages: each page is 1 credit."""
rows = []
for page in range(1, pages + 1):
data = search(q, page=page, **params)
for item in data.get("organic_results", []):
rows.append({"page": page, "position": item["position"], "title": item["title"], "link": item["link"]})
if not data.get("pagination", {}).get("next_page"):
break # no further page: stop early and save credits
return rows
rows = top_results("crm for small business", pages=3, gl="gb", hl="en")
print(len(rows), "results")多数の検索を並列で実行するには?
httpx.AsyncClientをasyncio.Semaphoreとともに使用し、アカウントの制限に合わせてサイズを設定します。スクリプトは無料クレジットのエンドポイントからconcurrency_limitを読み取るので、サポートが制限を引き上げるとそれに適応します。制限を超える検索はどのみち429になるため、セマフォでそれらの試行を無駄にしません。
各タスクは一時的エラーを徐々に長くなる間隔でリトライし、4回失敗するとNoneを返すので、1つの厄介なクエリがバッチをブロックすることはありません。
"""Run many searches in parallel without exceeding the account's concurrency limit."""
import asyncio
import os
import httpx
API_URL = "https://serpcrypto.com/api/v1/search"
CREDITS_URL = "https://serpcrypto.com/api/v1/credits"
HEADERS = {"Authorization": "Bearer " + os.environ["SERPCRYPTO_API_KEY"]}
async def search_one(client, gate, q):
async with gate: # at most N searches at the same time
for attempt in range(4):
r = await client.get(API_URL, params={"q": q, "gl": "us", "hl": "en"})
if r.status_code in (429, 502, 504):
await asyncio.sleep(2 ** attempt)
continue
r.raise_for_status()
return q, r.json()
return q, None
async def main(queries):
async with httpx.AsyncClient(headers=HEADERS, timeout=90) as client:
limits = (await client.get(CREDITS_URL)).json()
gate = asyncio.Semaphore(limits["concurrency_limit"])
results = await asyncio.gather(*(search_one(client, gate, q) for q in queries))
for q, data in results:
first = (data or {}).get("organic_results", [{}])[0].get("link")
print(f"{q!r}: {first}")
asyncio.run(main(["best vpn router", "home espresso machine", "4k monitor for coding"]))日次ランキングをCSVファイルに保存するには?
結果ごとに1行を追加し、日付、キーワード、順位、リンク、APIが適用した設定を記録します。独自の変数ではなくsearch_parametersからglとdeviceを読み取ることで、ファイルには実際に使用された内容が記録されます。
cronまたはWindowsタスクスケジューラで1日1回スクリプトを実行します。モバイルで3つのキーワードは1日3クレジット、月約90クレジットです。
import csv
from datetime import date
from serp_client import search
KEYWORDS = ["standing desk", "ergonomic chair", "monitor arm"]
FIELDS = ["day", "keyword", "position", "title", "link", "gl", "device"]
with open("rankings.csv", "a", newline="", encoding="utf-8") as fh:
writer = csv.DictWriter(fh, fieldnames=FIELDS)
if fh.tell() == 0:
writer.writeheader()
for kw in KEYWORDS:
data = search(kw, gl="gb", hl="en", device="mobile")
applied = data["search_parameters"]
for item in data.get("organic_results", []):
writer.writerow({
"day": date.today().isoformat(),
"keyword": kw,
"position": item["position"],
"title": item["title"],
"link": item["link"],
"gl": applied["gl"],
"device": applied["device"],
})どのPython HTTPクライアントを使うべきですか?
スクリプトやcronジョブにはrequestsを使いましょう。シンプルで、リトライアダプターが成熟しています。非同期コードが必要な場合、たとえばWebアプリ、エージェント、数百キーワードのバッチ処理にはhttpxを使いましょう。どちらも同じリクエストを送り、同じJSONを受け取ります。APIはどちらを選んでも関係ありません。
どちらのライブラリでも、極端に短いタイムアウトは避けてください。5秒で諦めるクライアントは、まだ実行中だった検索を再送してしまい、二重に支払う可能性があります。
スクリプトのコストはいくらになりますか?
結果ではなく検索回数を数えます。成功した1回の呼び出しが1クレジットです。500キーワードを1ページずつ、毎日30日間実行するジョブは15,000回の検索になります。25,000検索パック($18.75)なら余裕があり、プリペイドの検索クレジットに有効期限はありません。未使用の検索は、使用するまでアカウントに残ります。
コードからは上のcredits()ヘルパーで残高を確認できます。これは無料です。
Pythonに関する質問
PyPIにSerpCryptoのパッケージはありますか?
いいえ。サンプルは広く使われている2つのライブラリ、requestsまたはhttpxでHTTPS endpointを呼び出すので、インストールや更新が必要なものはありません。上のクライアントは約40行で、あなた自身が管理できます。
このコードはどのPythonバージョンに対応していますか?
Python 3.9以降です。asyncのサンプルはPython 3.7から利用可能なasyncio.runを使い、それ以外は標準ライブラリとrequestsまたはhttpxのみを使います。
Jupyter notebookからAPIを使えますか?
はい。Jupyterを起動する前にSERPCRYPTO_API_KEYを設定するか、notebook内でgetpassを使ってキーを読み込めば、保存されたセルに残りません。notebook内ではasyncio.run(main(...))の代わりにawait main(...)を使ってください。
結果をpandas DataFrameに変換するには?
結果の辞書のリストをpandas.DataFrame(data["organic_results"])に渡します。各フィールドが列になり、dateのような省略可能なフィールドが欠けている場合は空のセルになります。