Utiliser l'API ouverte U.R.B.S via python

U.R.B.S. met à disposition de sa communauté une API ouverte permettant d’accéder à l’essentiel des données présentes dans la base de données IMOPE et dans l’ONB.

La documentation complète de l’API est disponible directement sur le site d’U.R.B.S.. Le swagger détail comment l’interroger et vous permet de tester des requêtes.

Ce tutoriel ce focalise sur l’accès à l’API via python pour par exemple exécuter un nombre plus important de requêtes dans la limite des restrictions de l’API (15000 interrogations par mois, 150 appels par minute par IP, 10 identifiants adresse par appel).

Récupérer sa clé

Pour interroger notre API, il est nécessaire d’avoir une clé. Celle-ci peut être générée directement depuis votre compte ONB.

Accéder à la génération de sa clé API

Modules python

Pour ce tutoriel, nous utiliserons les modules requests et json pour réaliser les différentes requêtes sur l’API.

La documentation de ces modules peut-être retrouvée aux liens suivants :

Ne pas oublier d’importer ces modules en début de script python.

import requests
import json

Récupérer le catalogue

L’endpoint /catalog permet de récupérer le catalogue des attributs de la base IMOPE accessibles dans l’API. Le catalogue peut être interrogé de la manière suivante :

def getCatalog(apiKey):
   apiUrl = 'https://api.urbs.fr/catalog' 
   headers = {"Authorization" : "Bearer "+apiKey}
   r = requests.get(apiUrl, headers=headers)
   return r.json()

NB : le swagger permet également de récupérer le catalogue sans passer par python.

Interroger la base d’adresses d’IMOPE

L’endpoint /addressList permet d’interroger la base d’adresse d’IMOPE. Il retourne le détail d’une ou plusieurs adresses en fonction de la requête formulée.

Récupérer l’identifiant IMOPE d’une adresse à partir d’un texte

La fonction suivante permet de rechercher des adresses à partir d’une adresse au format textuel (n°, rue, code postal, commune).

def getAddressByText(apiKey,address):
	apiUrl = 'https://api.urbs.fr/addressList/byText'
	headers = {"Authorization" : "Bearer "+apiKey}
	body = {"text" : address}
	r = requests.post(apiUrl, data=body, headers=headers)
	return r.json()

Pour le 14 rue paul et pierre guichard 42000 Saint-Étienne on obtient le résultat suivant :

print(getAddressByText(apiKey,"14 rue paul et pierre guichard 42000 Saint-Étienne"))
>>> [{'address': '14 RUE PAUL ET PIERRE GUICHARD', 'postcode': '42000', 'id': '000CP0246_39a657823692e7ca', 'ban_id': '42218_6780_00014', 'parcelle_id': '42218000CP0246', 'city': 'Saint-Etienne', 'rank': 0.96442914}]

On peut ainsi récupérer l’identifiant IMOPE correspondant à cette adresse (‹ id ›). Dans le cas où l’adresse n’existe pas dans la base, l’api retourne un résultat vide.

Par exemple, on recherche le 1001 rue pierre et jacques guichard 42000 Saint-Étienne :

print(getAddressByText(apiKey,"1001 rue pierre et jacques guichard 42000 Saint-Étienne"))
>>> []

On peut de la même manière interroger l’API avec une liste d’adresses. Par exemple, on considère la liste d’adresses suivante de 25 mairies du département de la Loire.

Liste des adresses de 25 mairies du département de la Loire
mairies = ["Place de l'Eglise 42380 Aboen",
"Le Prieure 42820 Ambierle",
"Avenue du Parc 42161 Andrezieux-Boutheon Cedex",
"Le Bourg 42460 Arcinges",
"Place du 19-Mars-1962 42130 Arthun",
"20, rue du 11-Novembre 42510 Balbigny",
"29, rue des Ecoles 42210 Bellegarde-en-Forez",
"Route des Echarmeaux 42670 Belmont-de-la-Loire",
"50, rue du Feria 42660 Le Bessat",
"Place de l'Hotel-de-Ville 42130 Boen-sur-Lignon",
"Le Bourg 42560 Boisset-Saint-Priest",
"Place de l'Hotel-de-Ville 42220 Bourg-Argental",
"16, rue de la Liberation 42720 Briennon",
"Le Bourg 42220 BURDIGNES",
"Le Bourg 42260 Bussy-Albieux",
"1, place de Verdun 42320 Cellieu",
"Le Bourg 42440 Cervieres",
"72, place de la Fontaine-Disparue 42800 Chagnon",
"Place de la Mairie 42600 Chalain-le-Comtal",
"Le Bourg 42440 La Chamba",
"Place de la Mairie 42170 Chambles",
"12, rue Jean-Morel 42190 Charlieu",
"82, rue de la Mairie 42600 Champdieu",
"1088, route de la Croix-Leigne 42190 Chandon",
"Le Bourg 42380 La Chapelle-en-Lafaye"]

Le code suivant permet d’interroger l’API avec cette liste d’adresses et de récupérer le ou les identifiants IMOPE associés (une requête peut parfois retourner plusieurs réponses).

def getAddressIdFromList(apiKey,addressList):
	addressId = []
	for a in addressList :
		adId=getAddressByText(apiKey,a)
		if adId!=[]:
			for add in adId :
				addressId.append(add["id"])
	return addressId

Pour les 25 adresses précédentes on a le résultat suivant :

print(getAddressIdFromList(apiKey,mairies))

>>> ['0000A1615_e423190d4cdb2196', '0000A1635_c6fe98333f41c81a', '0000A0201_35354a4f2f873904', '000AC0196_972509aea0a5e920', '000AD0096_ab95bba577d26d07', '000AD0054_145b95f443eb7163', '000AD0055_f586693f17395c0f', '000AD0058_2d8aa3ca4bcf6ae4', '000AD0061_ade01635f76a6f11', '000AD0064_f288b1e145c52c7a', '000AD0086_ab45b76db53bc488', '000AD0087_50d38759b275b447', '000AD0088_a1812001370a3ea5', '000AD0090_ee995d30a027238d', '000AD0091_302ab979c912a414', '000AD0092_e147dcca05e2fff4', '000AD0095_52a574925c4d5d75', '000AD0122_d785e20697d7eed1', '000AD0124_7d6f47f0e8fc27b9', '000AD0171_a9854e78a8806672', '000AD0194_d68588d2a722e67f', '000AD0228_bf6c880bd2c7f07c', '000AD0234_f4835676c7dc46b2', '000AD0268_f317db8bcde3d178', '000AD0311_7fc30df971f4191f', '000AD0326_eea073c405cdf1cc', '000AD0328_62115bb7467233e7', '000AD0346_c65edf693f92a8cc', '000AD0348_4e0444aa8d56cce9', '0000F0639_6348a619142c1b82', '0000H0290_238be1a4ac19f639', '0000H0538_0be2b5cdb771b32e', '000AC0188_d2314eb6859af53e', '000AC0192_d13a393df1587d09', '000AC0219_9372612a2c1bd3fb', '000AC0227_50c23398b20a9e6f', '000AC0279_e62a4f263e9d40b3', '000AC0342_85dec9def1ef2d8f', '000AC0456_50c23398b20a9e6f', '000AC0467_fd0370da0780c892', '000AC0189_ab88beb14aca28f2', '000AC0195_8b0f97e9d446e4f5', '000AL0472_d9ddf7f92e557761', '000AL0401_db2f91ad687e2d86', '000AL0452_32238a900c5b5a03', '000AL0665_5e341a05331d36f7', '000AL0422_052dcc879e61bf2e', '000AL0423_0d6d79155f8a150c', '000AL0665_3fee23d70230070d', '000AL0939_be1dbfd7fa7c8fb1', '000AL1035_1fe62dee4e5b1151', '000AL1038_f9a4f5de3734b983', '0000C0119_63e0710ca720769c', '0000C0128_5ad1257c83b52cc7', '0000C0698_3c6ce7a7582dd208', '0000C0718_c4d511f7b8399151', '0000C0127_632203a98276b7a6', '0000A1536_1c3044836439d546', '0000A0400_697b581230fad19a', '000AR0613_7ac424a72ae694ee']

Rechercher des adresses autour d’une coordonnées

La fonction suivante permet de recherche les adresses autour de coordonnées (au format latitude, longitude) selon un rayon spécifié par l’utilisateur.
NB : le rayon doit être inférieur ou égal à 100 mètres et sa valeur par défaut est de 25 mètres.

def getAddressByCoord(apiKey,lat,lon,radius=25):
	apiUrl = 'https://api.urbs.fr/addressList/byCoords'
	headers = {"Authorization" : "Bearer " + apiKey}
	body = {"lat" : lat, "lon" : lon, "radius" : radius}
	r = requests.post(apiUrl, data=body, headers=headers)

	return r.json()

Par exemple voici le résultat pour une recherche dans un rayon de 50 mètres autour de la préfecture de la Loire à Saint-Etienne.

print(getAddressByCoord(apiKey,45.44220,4.38676,radius=50))
>>> [{'address': '2 RUE BALAY', 'postcode': '42000', 'id': '000BZ0016_965763658e73371b', 'ban_id': '42218_0580_00002', 'parcelle_id': '42218000BZ0016', 'city': 'Saint-Etienne', 'distance': 55}, {'address': '4 RUE BALAY', 'postcode': '42000', 'id': '000BZ0017_70edbe84fade8315', 'ban_id': '42218_0580_00004', 'parcelle_id': '42218000BZ0017', 'city': 'Saint-Etienne', 'distance': 56}, {'address': '2 RUE CHARLES DE GAULLE', 'postcode': '42000', 'id': '000BZ0015_af620bc8337adfee', 'ban_id': '42218_1770_00002', 'parcelle_id': '42218000BZ0015', 'city': 'Saint-Etienne', 'distance': 62}, {'address': '3 RUE ROBERT', 'postcode': '42000', 'id': '000BZ0016_200ce0b7bc4b6c8d', 'ban_id': '42218_7740', 'parcelle_id': '42218000BZ0016', 'city': 'Saint-Etienne', 'distance': 72}, {'address': '17 RUE ROUGET DE LISLE', 'postcode': '42000', 'id': '000BZ0017_989de47bd46230dc', 'ban_id': '42218_7920_00017', 'parcelle_id': '42218000BZ0017', 'city': 'Saint-Etienne', 'distance': 95}]

Récupérer les informations liées à une adresse à partir de son identifiant IMOPE

L’endpoint /address, permet d’interroger la base IMOPE et de récupérer les valeurs des attributs spécifié, pour l’identifiant adresse spécifié.

La fonction suivante permet cette requête :

def getAddressDatas(apiKey,imopeIds,attributes):
	apiUrl = 'https://api.urbs.fr/address'
	headers = {"Authorization" : "Bearer "+apiKey}
	body = {"id" : imopeIds, "attributes":attributes}
	r = requests.post(apiUrl, data=body, headers=headers)

	return r.json()

NB : imopeIds est une liste d’identifiant IMOPE lesquels peuvent être récupérés grâce aux fonctions précédentes. Grâce au catalogue on peut avoir les liste des attributs disponibles.

Si l’on reprend l’exemple du 14 rue paul et pierre guichard 42000 Saint-Étienne, l’identifiant IMOPE est 000CP0246_39a657823692e7ca. On souhaite uniquement récupérer les attributs dpe (classe dpe), ges (classe GES) et jannatmin (année de construction).

addressId = ["000CP0246_39a657823692e7ca"]
attributes = ["dpe", "ges",  "jannatmin"]
print(getAddressDatas(apiKey,addressId,attributes))
>>> [{'id': '000CP0246_39a657823692e7ca', 'address': {'label': '14 RUE PAUL ET PIERRE GUICHARD', 'postcode': '42000', 'city': 'Saint-Etienne'}, 'attributes': {'dpe': {'value': None, 'source': None}, 'ges': {'value': None, 'source': None}, 'jannatmin': {'value': 1950, 'source': {'name': 'Fichiers Fonciers enrichis', 'provider': 'CEREMA', 'model_year': '2023', 'reliability': '+', 'method': 'information cadastrales'}}}}]

Il est tout à fait possible d’interroger l’API en soumettant plusieurs adresses en même temps. Attention toutefois aux limitations de l’API : vous ne pourrez soumettre que identifiant adresse à la fois et réaliser 150 appels au plus par minute.