Tutoriels en français

Géocoder des adresses françaises en Python avec l'API de la Géoplateforme (ex-API Adresse)

Tutoriels en français · · Publié le 2026-11-09

Plaque de rue parisienne émaillée vert et bleu nuit indiquant 9e arrondissement, rue Paul Escudier
Une plaque de rue parisienne : le géocodage fait le chemin inverse, de l'adresse vers le point sur la carte.

Pour placer des clients sur une carte, calculer des distances ou rattacher une adresse à sa commune, il faut d'abord la géocoder, c'est-à-dire la convertir en latitude et longitude. En France, le service public de référence s'appuie sur la Base adresse nationale (BAN). Il a changé d'adresse : l'ancienne API api-adresse.data.gouv.fr est dépréciée au profit du service de géocodage de la Géoplateforme de l'IGN, sur data.geopf.fr/geocodage. Il est gratuit et sans clé. Voici comment l'utiliser en Python, adresse par adresse puis pour un fichier entier.

Exemples exécutés le 9 novembre 2026 avec Python 3.13, requests 2.34 et pandas 3.0.5 ; les sorties sont réelles. Les blocs s'enchaînent dans un même fichier.

Ce qui a changé avec la Géoplateforme

La page de documentation d'adresse.data.gouv.fr annonce que l'API Adresse BAN est dépréciée et intégrée au service de géocodage de la Géoplateforme, et que l'URL api-adresse.data.gouv.fr devait être décommissionnée fin janvier 2026. Au moment de nos tests, elle répondait encore, mais il serait imprudent d'en dépendre. La migration est simple : les paramètres (q, limit, postcode, citycode, type…) et le format de réponse GeoJSON sont les mêmes ; seule l'URL de base change, et le service ajoute un paramètre index pour choisir entre adresses (address), points d'intérêt (poi) et parcelles cadastrales (parcel).

D'après la documentation de la Géoplateforme, l'usage est limité à 50 requêtes par seconde depuis une même adresse IP. Au-delà, le service répond par une erreur 429 et bloque les appels suivants tant que le rythme ne baisse pas.

Géocoder une adresse

Le point d'entrée /search prend l'adresse en texte libre dans q. On limite la réponse au meilleur résultat et on restreint la recherche aux adresses avec index=address :

import requests

BASE = "https://data.geopf.fr/geocodage"

def geocoder(adresse: str, code_postal: str | None = None) -> dict | None:
    params = {"q": adresse, "limit": 1, "index": "address"}
    if code_postal:
        params["postcode"] = code_postal
    r = requests.get(f"{BASE}/search", params=params, timeout=10)
    r.raise_for_status()
    features = r.json()["features"]
    if not features:
        return None
    f = features[0]
    lon, lat = f["geometry"]["coordinates"]
    p = f["properties"]
    return {"label": p["label"], "score": round(p["score"], 2), "type": p["type"],
            "citycode": p["citycode"], "lat": lat, "lon": lon}

print(geocoder("20 avenue de Ségur, Paris"))
print(geocoder("1 place de la mairie", code_postal="01000"))
print(geocoder("rue qui n'existe pas du tout zzz"))
{'label': '20 Avenue de Ségur 75007 Paris', 'score': 0.97, 'type': 'housenumber', 'citycode': '75107', 'lat': 48.850699, 'lon': 2.308628}
{'label': '1 Place de la Mairie 01000 Saint-Denis-lès-Bourg', 'score': 0.95, 'type': 'housenumber', 'citycode': '01344', 'lat': 46.202453, 'lon': 5.18974}
None

Quelques remarques sur ces résultats :

Le deuxième exemple montre un autre piège : le code postal 01000 couvre plusieurs communes, et la « place de la Mairie » trouvée est celle de Saint-Denis-lès-Bourg, pas celle de Bourg-en-Bresse. Un code postal n'identifie pas une commune ; pour lever l'ambiguïté, passez le code commune Insee dans le paramètre citycode, ou ajoutez le nom de la commune dans q. Enfin, une adresse introuvable renvoie une liste vide, que la fonction traduit par None.

Le géocodage inverse

Le point d'entrée /reverse fait le chemin inverse : à partir de coordonnées, il renvoie l'adresse la plus proche.

r = requests.get("https://data.geopf.fr/geocodage/reverse",
                 params={"lon": 2.308628, "lat": 48.850699, "limit": 1, "index": "address"}, timeout=10)
r.raise_for_status()
p = r.json()["features"][0]["properties"]
print(p["label"], "|", p["type"], "|", p["citycode"])
20 Avenue de Ségur 75007 Paris | housenumber | 75107

C'est utile pour afficher une adresse lisible à partir d'une position GPS (un relevé terrain, une photo géolocalisée) ou pour retrouver la commune d'un point. Si vous n'avez besoin que de la commune, lisez simplement les propriétés city et citycode de la réponse.

Géocoder un fichier CSV en un seul appel

Pour des centaines ou des milliers d'adresses, ne bouclez pas sur /search : le point d'entrée /search/csv reçoit un fichier CSV et renvoie le même fichier enrichi de colonnes result_…, en une seule requête. On indique la ou les colonnes qui composent l'adresse avec columns, et éventuellement la colonne du code postal avec postcode :

import io
import pandas as pd

adresses = pd.DataFrame({
    "id": [1, 2, 3],
    "adresse": ["20 avenue de Ségur", "1 place de la Mairie", "8 boulevard du Port"],
    "code_postal": ["75007", "01000", "95000"],
})
fichier = adresses.to_csv(index=False).encode("utf-8")

r = requests.post(
    "https://data.geopf.fr/geocodage/search/csv",
    files={"data": ("adresses.csv", fichier, "text/csv")},
    data={"columns": ["adresse"], "postcode": "code_postal", "indexes": "address"},
    timeout=60,
)
r.raise_for_status()
resultat = pd.read_csv(io.StringIO(r.text), dtype={"code_postal": "string", "result_citycode": "string"})

print(resultat[["id", "result_label", "result_score", "result_status"]].to_string(index=False))
 id                                     result_label  result_score result_status
  1                   20 Avenue de Ségur 75007 Paris      0.971628            ok
  2 1 Place de la Mairie 01000 Saint-Denis-lès-Bourg      0.954228            ok
  3                  8 Boulevard du Port 95000 Cergy      0.970895            ok

Le fichier renvoyé contient notamment latitude, longitude, result_score, result_type, result_citycode et result_status (ok, not-found ou skipped). Comme toujours avec les fichiers français, relisez les codes en texte : sinon le code postal 01000 redevient 1000. Ce point est détaillé dans notre article sur la lecture des CSV français avec pandas.

Pour un fichier volumineux, découpez-le en lots de quelques milliers de lignes, envoyez-les l'un après l'autre et gardez les résultats intermédiaires sur disque, de façon à pouvoir reprendre en cas d'interruption. Le site adresse.data.gouv.fr propose aussi un géocodeur CSV en ligne, pratique pour un fichier ponctuel sans écrire de code.

Boucler sans dépasser la limite

Si vous devez tout de même appeler /search en boucle (autocomplétion, adresses arrivant au fil de l'eau), espacez les requêtes et gérez l'erreur 429. Une session requests réutilise la connexion HTTPS, ce qui accélère nettement les appels successifs :

import time

session = requests.Session()

def geocoder_poli(adresses, pause=0.05):
    """Une requête toutes les 50 ms au plus : 20 par seconde, bien sous la limite de 50."""
    for adresse in adresses:
        for essai in range(3):
            r = session.get("https://data.geopf.fr/geocodage/search",
                            params={"q": adresse, "limit": 1}, timeout=10)
            if r.status_code == 429:          # trop de requêtes : on attend et on réessaie
                time.sleep(2 ** essai)
                continue
            r.raise_for_status()
            break
        feats = r.json()["features"]
        yield adresse, feats[0]["properties"]["label"] if feats else None
        time.sleep(pause)

for a, label in geocoder_poli(["10 rue de Rivoli Paris", "Place Bellecour Lyon"]):
    print(a, "->", label)
10 rue de Rivoli Paris -> 10 Rue de Rivoli 75004 Paris
Place Bellecour Lyon -> Place Bellecour 69002 Lyon

Avec une pause de 50 millisecondes, le script reste à environ 20 requêtes par seconde, bien en dessous de la limite. En cas de 429, il attend 1, 2 puis 4 secondes avant de réessayer. N'exécutez pas plusieurs copies de ce script en parallèle depuis la même machine : la limite s'applique à l'adresse IP, pas au processus.

Bonnes pratiques

Les données de la Base adresse nationale sont publiées sous licence ouverte. Si vous diffusez des coordonnées issues du géocodage, citez la source (Base adresse nationale, via le service de géocodage de la Géoplateforme).

Sources