Autres exemples d'APIs
Ce chapitre est une parenthèse dans ce tutoriel, pour présenter quelques exemples d'exploitation d'APIs.
Un XML (http://mob.u-strasbg.fr/)
L'université de Strasbourg entretient une API fournissant des POIs, exemple :
La forme du XML généré est plus classique que ceux d'OSM :
<rss version="2.0"> <poi> <id>1</id> <name>Central</name> <latitude>48.5803337</latitude> <longitude>7.7655637</longitude> <floor/> <type>campus</type> <description/> <url>http://fr.wikipedia.org/wiki/Campus_central_de_Strasbourg</url> <url_image/> <tags/> <capacity>0</capacity> </poi> <poi> <id>2</id> ...
Pour extraire les données de ce type d'XML :
import requests import xml.etree.ElementTree r = requests.get('http://mob.u-strasbg.fr/cgi-bin/odudsApi.py?method=search&id=allpois') root = xml.etree.ElementTree.fromstring(r.content) for my_poi in root.findall('poi'): my_name = my_poi.find('name').text print(my_name)
Afficher les points à partir de leurs coordonnées
Le code suivant, dans un projet QGIS vide, affiche un fond de carte OSM, crée puis affiche une couche virtuelle de points, avec 2 champs, peuplée des points issus d'un XML. Toujours à partir de l'API de l'université de Strasbourg :
import requests import xml.etree.ElementTree # VIDER PROJET QgsProject.instance().removeAllMapLayers() iface.mapCanvas().refresh() # PARAMETRES OSM urlWithParams = "type=xyz&url=http://tile.openstreetmap.org/{z}/{x}/{y}.png" osm = QgsRasterLayer(urlWithParams, "OpenStreetMap", "wms") # CREER UNE COUCHE VIRTUELLE DE POINTS point_vector = QgsVectorLayer("Point", "my_points", "memory") # AFFICHER LES COUCHES QgsProject.instance().addMapLayer(osm) QgsProject.instance().addMapLayer(point_vector) # AJOUTER CHAMPS DANS point_vector from qgis.PyQt.QtCore import QVariant pr = point_vector.dataProvider() pr.addAttributes([QgsField("id", QVariant.Int), QgsField("name", QVariant.String)]) point_vector.updateFields() # PARSER LE FICHIER r = requests.get('http://mob.u-strasbg.fr/cgi-bin/odudsApi.py?method=search&id=allpois') root = xml.etree.ElementTree.fromstring(r.content) for my_poi in root.findall('poi'): my_id = int(my_poi.find('id').text) my_name = str(my_poi.find('name').text) my_longitude = float(my_poi.find('longitude').text) my_latitude = float(my_poi.find('latitude').text) #print(my_id, my_name, my_longitude, my_latitude) # EDITER COUCHE VIRTUELLE f = QgsFeature() f.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(my_longitude, my_latitude))) f.setAttributes([my_id, my_name]) pr.addFeature(f) point_vector.updateExtents() QgsProject.instance().addMapLayer(point_vector) # RAFRAICHIR iface.mapCanvas().refresh() # CRS my_crs=QgsCoordinateReferenceSystem(3857) QgsProject.instance().setCrs(my_crs)
Aller chercher l'image sous condition
... for my_poi in root.findall('poi'): my_id = int(my_poi.find('id').text) my_name = str(my_poi.find('name').text) my_divers = str(my_poi.find('url_image').text) if my_divers == "None": my_divers = "" elif my_divers != "None": my_divers = "https://mob.u-strasbg.fr/geoloc/url_image/" + my_divers my_longitude = float(my_poi.find('longitude').text) ...
Un JSON (data.culture.gouv.fr, monuments historiques)
Le site data.culture.gouv.fr propose plusieurs APIs, dont les données sont fournis en JSON.
Exemple avec la liste des immeubles parisiens protégés au titre des monuments historiques :
Quand vous êtes confronté à ce type de fichiers, dont la visualisation en ligne n'est pas toujours aisée, il existe ce type d'outil en ligne qui vous permettra d'en comprendre la structure ou de tester votre fichier :
Sur jsonviewer utilisez le bouton Load JSON data et copiez-y l'URL (supprimez le « s » du https de votre URL si besoin). Sur geojson.io copiez vos données GEOJSON dans l'encart prévu, ou ajoutez l'adresse de votre fichier GEOJSON comme dans l'exemple ci-dessus (à la place de [URL]).
Pour parser ce type de JSON, et en extraire les données :
import json import requests response = requests.get("https://data.culture.gouv.fr/api/records/1.0/search/?dataset=liste-des-immeubles-proteges-au-titre-des-monuments-historiques&q=&facet=reg&facet=dpt_lettre&refine.dpt_lettre=Paris") my_file = json.loads(response.text) my_json = my_file["records"] for my_block in my_json: my_fields = my_block["fields"] print(my_fields["wadrs"])
Les lignes 4 et 5 en font un JSON lisible pour Python.
Les données qui nous intéressent sont dans le bloc records
, nous l'isolons donc avec la ligne 7.
La ligne 9 boucle sur le bloc records
, et pour chaque sous-blocs fields
affiche les données du tag wadrs
.
Un JSON (data.culture.gouv.fr, événements publics cibul)
Récupérer les informations :
import json import requests response = requests.get( "https://public.opendatasoft.com/api/records/1.0/search/?dataset=evenements-publics-cibul&q=&rows=1354&facet=tags&facet=placename&facet=department&facet=region&facet=city&facet=date_start&facet=date_end&facet=pricing_info&facet=updated_at&facet=city_district&refine.tags=musique&refine.tags=gratuit&refine.department=Paris") my_file = json.loads(response.text) my_json = my_file["records"] for my_block in my_json: my_fields = my_block["fields"] my_uid = my_fields["uid"] my_title = my_fields["title"] my_geometry = my_block["geometry"] my_coordinates = my_geometry["coordinates"] print("my_uid :",my_uid, "my_coordinates :", my_coordinates, "my_title :", my_title)
Récupérer proprement les coordonnées
Pour utiliser les points, il faudra d'abord les splitter :
my_geometry = my_block["geometry"] my_coordinates = my_geometry["coordinates"] my_lat = str(my_coordinates).split(", ")[0].replace("[", "") my_lon = str(my_coordinates).split(", ")[1].replace("]", "")
Afficher les points à partir de leurs coordonnées
import requests import json # VIDER PROJET QgsProject.instance().removeAllMapLayers() iface.mapCanvas().refresh() # CREER UNE COUCHE VIRTUELLE DE POINTS point_vector = QgsVectorLayer("Point", "my_points", "memory") # AFFICHER LES COUCHES QgsProject.instance().addMapLayer(point_vector) # AJOUTER CHAMPS DANS point_vector from qgis.PyQt.QtCore import QVariant pr = point_vector.dataProvider() pr.addAttributes([QgsField("uid", QVariant.Int), QgsField("title", QVariant.String)]) point_vector.updateFields() # PARSER LE FICHIER response = requests.get('https://public.opendatasoft.com/api/records/1.0/search/?dataset=evenements-publics-cibul&q=&rows=1354&facet=tags&facet=placename&facet=department&facet=region&facet=city&facet=date_start&facet=date_end&facet=pricing_info&facet=updated_at&facet=city_district&refine.tags=musique&refine.tags=gratuit&refine.department=Paris') my_file = json.loads(response.text) my_json = my_file["records"] for my_block in my_json: my_fields = my_block["fields"] my_uid = my_fields["uid"] my_title = my_fields["title"] my_geometry = my_block["geometry"] my_coordinates = my_geometry["coordinates"] my_lat = str(my_coordinates).split(", ")[0].replace("[", "") my_lon = str(my_coordinates).split(", ")[1].replace("]", "") print("my_uid :", my_uid,"my_coordinates :", my_coordinates,"my_lat :", my_lat,"my_lon :", my_lon,"my_title :", my_title) # EDITER COUCHE VIRTUELLE f = QgsFeature() f.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(float(my_lon), float(my_lat)))) f.setAttributes([my_uid, my_title]) pr.addFeature(f) point_vector.updateExtents() QgsProject.instance().addMapLayer(point_vector) # RAFRAICHIR iface.mapCanvas().refresh()
Un GEOJSON
Pour ouvrir un fichier GEOJSON, ce ne sera pas compliqué (source : webgeodatavore) :
iface.addVectorLayer('https://d2ad6b4ur7yvpq.cloudfront.net/naturalearth-3.3.0/ne_50m_populated_places.geojson', 'Populated places', 'ogr')
Mais pour ouvrir des données GEOJSON brutes (construites à la volée par une API par exemple, ou simplement non-accessibles par URL), alors vous devrez d'abord les enregistrer dans un fichier, puis ouvir ce fichier.
Un GEOJSON (API zones isochrones https://openrouteservice.org)
Pensez à vérifier que la structure d'usage des APIs d'openrouteservice n'a pas changé ! Des exemples de codes peuvent être générés sur leur site.
Exemple avec l'excellente API de zones isochrones d'openrouteservice (votre obtiendrez une clé gratuite après une rapide inscription) :
import requests body = {"locations":[[8.681495,49.41461],[8.686507,49.41943]],"range":[300,200]} headers = { 'Accept': 'application/json, application/geo+json, application/gpx+xml, img/png; charset=utf-8', 'Authorization': 'VOTRE CLE API', 'Content-Type': 'application/geo+json; charset=utf-8' } call = requests.post('https://api.openrouteservice.org/v2/isochrones/driving-car', json=body, headers=headers) #print(call.status_code, call.reason) #print(call.text) with open('C:/Users/Georges/Downloads/myfile.geoson', 'w', encoding='utf-8') as outfile: outfile.write(call.text) iface.addVectorLayer('C:/Users/Georges/Downloads/myfile.geoson', 'Isochrones', 'ogr')
Un autre GEOJSON (API directions https://openrouteservice.org)
import requests headers = { 'Accept': 'application/json, application/geo+json, application/gpx+xml, img/png; charset=utf-8', } call = requests.get('https://api.openrouteservice.org/v2/directions/driving-car?api_key=VOTRE CLE API&start=8.681495,49.41461&end=8.686507,49.41943', headers=headers) #print(call.status_code, call.reason) #print(call.text) with open('C:/Users/Georges/Downloads/trajet.geoson', 'w', encoding='utf-8') as outfile: outfile.write(call.text) iface.addVectorLayer('C:/Users/Georges/Downloads/trajet.geoson', 'trajet', 'ogr')
Et pour boucler sur plusieurs mode de déplacement, et créer autant de fichier geojson, et les afficher :
import requests MesModes = ['foot-hiking', 'driving-car', 'wheelchair'] for i in MesModes: Chemin = 'C:/Users/Georges/Downloads/trajet_' + i + '.geoson' headers = { 'Accept': 'application/json, application/geo+json, application/gpx+xml, img/png; charset=utf-8', } call = requests.get('https://api.openrouteservice.org/v2/directions/' + i + '?api_key=VOTRE CLE API&start=2.011776,49.048384&end=2.077019,49.038914', headers=headers) with open(Chemin, 'w', encoding='utf-8') as outfile: outfile.write(call.text) iface.addVectorLayer(Chemin, 'trajet', 'ogr')
Obsolète