Watch-IP

Géolocalisation IP par lots avec Python

Enrichissez une liste d'IP via POST /v1/lookup par lots de 100, avec association des lignes, sortie par points de contrôle et repli en cas de 429 — appelé directement en HTTP, car le SDK Python officiel ne couvre pas ce point de terminaison.

Avant de commencer

  • Un compte Watch-IP et une clé secrète de recherche — POST /v1/lookup est réservé aux appels serveur à serveur ; ne l'appelez jamais depuis un navigateur et n'intégrez jamais la clé dans un client.
  • Python 3.9 ou supérieur.
  • Une liste locale d'IP à enrichir — ce guide les lit depuis un CSV avec une IP par ligne.

1. Pourquoi ce guide utilise du HTTP direct plutôt que le SDK

watch-ip-sdk, le paquet Python officiel, n'implémente que GET /v1/geo, le point de terminaison visiteur destiné au navigateur — il n'a aucune méthode pour POST /v1/lookup. Ce guide appelle l'API directement avec urllib de la bibliothèque standard, dans le même esprit sans dépendance que le SDK lui-même plutôt que d'en ajouter une nouvelle juste pour ce cas.

2. Lire et valider la liste d'entrée

Conservez la position de ligne d'origine de chaque IP afin qu'un résultat puisse être rattaché à l'enregistrement dont il provient — l'API renvoie les résultats dans le même ordre que celui dans lequel elle a reçu les IP, ce qui n'aide que si votre propre liste conserve cet ordre elle aussi.

Python

import csv

with open("ips.csv", newline="") as f:
    ips = [row[0].strip() for row in csv.reader(f) if row and row[0].strip()]

print(f"{len(ips)} IP chargées")

3. Découper en lots de 100

POST /v1/lookup accepte de 1 à 100 IP par appel et valide tout le lot avant de lancer la moindre recherche — une seule adresse malformée fait échouer tout le lot, donc validez la syntaxe des IP localement d'abord si votre liste d'entrée risque d'être sale.

Python

def chunk(items, size=100):
    for i in range(0, len(items), size):
        yield items[i : i + size]

4. Soumettre chaque lot et enregistrer les résultats par points de contrôle

Écrivez les résultats au fur et à mesure que chaque lot se termine plutôt que de tout garder en mémoire jusqu'à la fin, afin qu'un échec en cours de route sur une longue liste ne fasse pas perdre les lots déjà réussis. found: false signifie que l'IP est syntaxiquement valide mais n'a aucune entrée dans la base de données — un résultat normal, pas une erreur.

Python

import json
import time
import urllib.error
import urllib.request

API_URL = "https://api.watch-ip.com/v1/lookup"
SECRET_KEY = "YOUR_SECRET_KEY"

def lookup_batch(ips):
    request = urllib.request.Request(
        API_URL,
        data=json.dumps({"ips": ips}).encode(),
        headers={
            "Authorization": f"Bearer {SECRET_KEY}",
            "Content-Type": "application/json",
        },
    )
    with urllib.request.urlopen(request) as response:
        return json.load(response)["results"]

with open("results.jsonl", "a") as out:
    for batch in chunk(ips):
        try:
            results = lookup_batch(batch)
        except urllib.error.HTTPError as err:
            if err.code == 429:
                time.sleep(60)  # patienter jusqu'à la fin de la minute en cours
                results = lookup_batch(batch)
            else:
                raise
        for result in results:
            out.write(json.dumps(result) + "\n")

5. Reprendre une tâche partielle

Comme les résultats sont ajoutés lot par lot, redémarrer après un plantage nécessite seulement d'ignorer les IP déjà écrites dans results.jsonl plutôt que de resoumettre toute la liste — resoumettre une IP en double est facturé à nouveau, puisque chaque entrée d'un lot est mesurée individuellement plutôt que dédupliquée.

Python

done = set()
with open("results.jsonl") as f:
    for line in f:
        done.add(json.loads(line)["ip"])

remaining = [ip for ip in ips if ip not in done]

Erreurs et cas limites

Un 400 signifie que le lot comptait plus de 100 IP, une liste vide, ou une adresse malformée quelque part dedans — tout le lot échoue, pas seulement l'entrée fautive. Un 403 signifie qu'une clé publiable a été utilisée au lieu d'une clé secrète. Mélanger des adresses IPv4 et IPv6 dans le même lot ne pose aucun problème ; chacune est recherchée indépendamment, avec les mêmes champs annulables dans les deux cas.

Étape suivante

Voir la référence de recherche d'IP groupée pour le schéma exact de la réponse, et erreurs et limites de débit pour la liste complète des codes de statut que ce point de terminaison peut renvoyer.

Pages associées