Réponse rapide
Comment appeler une API SERP depuis Python ?
Envoyez une requête GET à https://serpcrypto.com/api/v1/search avec requests ou httpx, votre clé dans l'en-tête Authorization: Bearer et la requête dans params, puis lisez response.json(). SerpCrypto facture 1 crédit par recherche réussie, à partir de 0,30 $US/1K requêtes, et les retries des appels échoués sont gratuits. Payez en crypto, sans KYC. Le code ci-dessous ne nécessite que requests ou httpx.
Configuration Python en un coup d'œil
| Installation | pip install requests ou pip install httpx |
|---|---|
| Clé | Variable d'environnement SERPCRYPTO_API_KEY |
| En-tête | Authorization: Bearer <key> |
| Délai d'expiration | 60 à 90 secondes : une recherche s'exécute en direct |
| Retry | 429, 502 et 504 uniquement, avec backoff ; les erreurs sont gratuites |
| Recherches en parallèle | Jusqu'à concurrency_limit depuis GET /credits |
Comment configurer un client Python réutilisable ?
Créez un requests.Session avec la clé dans ses en-têtes et une politique de retry pour les trois erreurs temporaires. Une session réutilise les connexions, donc une boucle de recherches passe moins de temps sur les handshakes TLS. Enregistrez le fichier sous serp_client.py ; les exemples suivants l'importent.
Retry de urllib3 attend plus longtemps avant chaque nouvelle tentative et respecte un en-tête Retry-After s'il en est envoyé. Il ne réessaie jamais 400, 401 ou 402, qui demandent une correction, pas une seconde tentative.
"""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())Comment récupérer plus de 10 résultats ?
Demandez les pages suivantes une par une. Environ 10 résultats organiques par page, comme Google les sert depuis qu'il n'honore plus num=100 en septembre 2025 ; chaque page supplémentaire coûte un crédit de plus. Arrêtez-vous dès que pagination.next_page est absent : il n'y a plus rien à récupérer, et vous gardez les crédits.
Pour la plupart des travaux de suivi de classement, la première page ou les trois premières pages suffisent, car les clics s'y concentrent. Trente résultats pour un mot-clé coûtent trois crédits.
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")Comment lancer de nombreuses recherches en parallèle ?
Utilisez httpx.AsyncClient avec un asyncio.Semaphore dimensionné à la limite de votre compte. Le script lit concurrency_limit depuis l'endpoint des crédits gratuits, il s'adapte donc quand le support augmente votre limite. Les recherches au-delà de la limite recevraient de toute façon 429 ; le sémaphore évite de gaspiller ces tentatives.
Chaque tâche réessaie les erreurs temporaires avec une pause croissante et renvoie None après quatre échecs, ainsi une requête récalcitrante ne bloque jamais le lot.
"""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"]))Comment enregistrer les classements quotidiens dans un fichier CSV ?
Ajoutez une ligne par résultat, avec le jour, le mot-clé, la position, le lien et les paramètres appliqués par l'API. Lire gl et device depuis search_parameters plutôt que depuis vos propres variables garantit que le fichier consigne ce qui a réellement été utilisé.
Lancez le script une fois par jour avec cron ou le Planificateur de tâches Windows. Trois mots-clés sur mobile coûtent trois crédits par jour, environ 90 par mois.
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"],
})Quel client HTTP Python choisir ?
Utilisez requests pour les scripts et les tâches cron : il est simple et son adaptateur de retry est mature. Utilisez httpx quand vous avez besoin de code async, comme une web app, un agent ou un lot de centaines de mots-clés. Les deux envoient la même requête et reçoivent le même JSON ; l'API ne se soucie pas de celui que vous choisissez.
Évitez les timeouts très courts avec l'une ou l'autre bibliothèque. Un client qui abandonne après cinq secondes peut renvoyer une recherche encore en cours et payer les deux.
Combien va coûter mon script ?
Comptez les recherches, pas les résultats : un appel réussi vaut un crédit. Un traitement de 500 mots-clés, une page chacun, chaque jour pendant 30 jours, représente 15 000 recherches. Sur le pack 25 000 recherches (18,75 $US), il reste de la marge, et Les crédits de recherche prépayés n'expirent jamais : les requêtes inutilisées restent sur votre compte jusqu'à ce que vous les utilisiez.
Vérifiez le solde depuis le code avec le helper credits() ci-dessus ; cela ne coûte rien.
Questions Python
Existe-t-il un package SerpCrypto sur PyPI ?
Non. Les exemples appellent l'endpoint HTTPS avec requests ou httpx, deux bibliothèques très répandues, donc il n'y a rien de notre côté à installer ni à mettre à jour. Le client ci-dessus fait environ 40 lignes et il est à vous.
Quelles versions de Python ce code prend-il en charge ?
Python 3.9 et versions ultérieures. L'exemple async utilise asyncio.run, disponible depuis Python 3.7, et le reste n'utilise que la bibliothèque standard plus requests ou httpx.
Puis-je utiliser l'API depuis un notebook Jupyter ?
Oui. Définissez SERPCRYPTO_API_KEY avant de lancer Jupyter, ou lisez la clé avec getpass dans le notebook pour qu'elle ne finisse pas dans une cellule sauvegardée. Dans un notebook, utilisez await main(...) au lieu de asyncio.run(main(...)).
Comment transformer les résultats en DataFrame pandas ?
Passez la liste des dictionnaires de résultats à pandas.DataFrame(data["organic_results"]). Chaque champ devient une colonne ; les champs optionnels absents comme date deviennent des cellules vides.