Extraction des mairies (annuaire.py) : lecture du fichier brut input/2026-06-22_053126-data.gouv_local.json (annuaire service-public.gouv.fr, 86 212 services). Filtrage sur les entrées dont le champ pivot[].type_service_local == "mairie" et dont le siren est renseigné. Cas particulier de Paris, Lyon et Marseille : chaque arrondissement y est une entrée distincte partageant le SIREN de la ville ; une seule ligne est conservée par ville, avec le code INSEE de la commune entière (75056, 69123, 13055) plutôt qu'un code d'arrondissement. Résultat : 23 920 mairies.
Jointure avec data.gouv.fr (join.py) : croisement avec l'export des organisations data.gouv.fr (input/export-organization-20260622-061308.csv) sur la clé siren (annuaire) = 9 premiers caractères du business_number_id (SIRET, export). 839 correspondances trouvées. 18 SIREN correspondent à plusieurs organisations (doublons de lignes dans l'export).
data/annuaire_mairies.csvToutes les mairies avec SIREN extraites de l'annuaire service-public.
| Colonne | Description |
|---|---|
nom | Nom de la mairie |
siren | Numéro SIREN (9 chiffres) |
code_insee_commune | Code INSEE de la commune |
data/annuaire_mairies_join.csvMairies présentes à la fois dans l'annuaire service-public et sur data.gouv.fr.
| Colonne | Description |
|---|---|
id | Identifiant de l'organisation data.gouv.fr |
name | Nom de l'organisation data.gouv.fr |
annuaire_nom | Nom dans l'annuaire service-public |
siren | Numéro SIREN |
code_insee_commune | Code INSEE de la commune |
metric.datasets | Nombre de jeux de données publiés |
data/annuaire_mairies_join_duplicates.csvMême schéma que annuaire_mairies_join.csv. Contient uniquement les lignes pour lesquelles un même SIREN correspond à plusieurs organisations dans l'export data.gouv.fr.
A partir de la base locale de l'annuaire des services publics en JSON, produit un CSV nom,siren,code_insee_commune :
import csv
import json
INPUT_FILE = "input/2026-06-22_053126-data.gouv_local.json"
OUTPUT_FILE = "data/annuaire_mairies.csv"
FIELDNAMES = ["nom", "siren", "code_insee_commune"]
# Paris, Lyon, Marseille each expose one service per arrondissement, all
# sharing the city's siren. Collapse those down to the whole-city code.
PLM_CODES = {"75056", "69123", "13055"}
def is_mairie(service: dict) -> bool:
return any(
p.get("type_service_local") == "mairie"
for p in service.get("pivot", [])
)
def get_code_insee(service: dict) -> str:
for p in service.get("pivot", []):
if p.get("type_service_local") == "mairie":
codes = p.get("code_insee_commune", [])
return codes[0] if codes else ""
return ""
def main():
print(f"Loading {INPUT_FILE}...")
with open(INPUT_FILE, encoding="utf-8") as f:
data = json.load(f)
services = data.get("service", [])
print(f"{len(services)} services total")
entries_by_siren = {}
for svc in services:
if not is_mairie(svc):
continue
siren = svc.get("siren", "").strip()
if not siren:
continue
entries_by_siren.setdefault(siren, []).append(
(svc.get("nom", ""), get_code_insee(svc))
)
count = 0
with open(OUTPUT_FILE, "w", newline="", encoding="utf-8") as f:
writer = csv.DictWriter(f, fieldnames=FIELDNAMES)
writer.writeheader()
for siren, entries in entries_by_siren.items():
plm_code = next((c for _, c in entries if c in PLM_CODES), None)
if plm_code:
nom = next(n for n, c in entries if c == plm_code)
writer.writerow({
"nom": nom,
"siren": siren,
"code_insee_commune": plm_code,
})
count += 1
else:
for nom, code in entries:
writer.writerow({
"nom": nom,
"siren": siren,
"code_insee_commune": code,
})
count += 1
print(f"Done. {count} mairies with siren written to {OUTPUT_FILE}")
if __name__ == "__main__":
main()
A partir du CSV extrait de l'annuaire plus haut et du catalogue des ressources de data.gouv.fr, créé les fichiers de jointure et des doublons :
import csv
import os
ANNUAIRE_FILE = "data/annuaire_mairies.csv"
EXPORT_FILE = "input/export-organization-20260622-061308.csv"
OUTPUT_FILE = "data/annuaire_mairies_join.csv"
DUPLICATES_FILE = "data/annuaire_mairies_join_duplicates.csv"
def main():
# Index annuaire by siren
annuaire: dict[str, dict] = {}
with open(ANNUAIRE_FILE, newline="", encoding="utf-8") as f:
for row in csv.DictReader(f):
annuaire[row["siren"]] = row
print(f"Annuaire: {len(annuaire)} mairies")
os.makedirs("data", exist_ok=True)
matched = 0
siren_hits: dict[str, list[str]] = {}
rows_by_siren: dict[str, list[dict]] = {}
with open(EXPORT_FILE, newline="", encoding="utf-8") as fin, \
open(OUTPUT_FILE, "w", newline="", encoding="utf-8") as fout:
reader = csv.DictReader(fin, delimiter=";")
fieldnames = ["id", "name", "annuaire_nom", "siren", "code_insee_commune", "metric.datasets"]
writer = csv.DictWriter(fout, fieldnames=fieldnames)
writer.writeheader()
for row in reader:
siren = (row.get("business_number_id") or "").strip()[:9]
if siren in annuaire:
siren_hits.setdefault(siren, []).append(row.get("business_number_id", "").strip())
out_row = {
"id": row["id"],
"name": row["name"],
"annuaire_nom": annuaire[siren]["nom"],
"siren": siren,
"code_insee_commune": annuaire[siren]["code_insee_commune"],
"metric.datasets": row.get("metric.datasets", ""),
}
rows_by_siren.setdefault(siren, []).append(out_row)
writer.writerow(out_row)
matched += 1
duplicates = {siren: rows for siren, rows in rows_by_siren.items() if len(rows) > 1}
if duplicates:
print(f"WARNING: {len(duplicates)} siren(s) matched multiple orgs")
with open(DUPLICATES_FILE, "w", newline="", encoding="utf-8") as fdup:
writer_dup = csv.DictWriter(fdup, fieldnames=["id", "name", "annuaire_nom", "siren", "code_insee_commune", "metric.datasets"])
writer_dup.writeheader()
for rows in duplicates.values():
writer_dup.writerows(rows)
print(f"Duplicates written to {DUPLICATES_FILE}")
print(f"Done. {matched} rows written to {OUTPUT_FILE}")
if __name__ == "__main__":
main()
Vues
0
Téléchargements
0
Documentation des fichiers manquante
Couverture temporelle non renseignée