1 Introduction : Qu’est-ce qu’une API ?
Nous avons vu dans les chapitres précédents comment consommer des données depuis un fichier (le mode d’accès le plus simple) ou comment récupérer des données par le biais du webscraping, une méthode qui permet à Python
de singer le comportement d’un navigateur web et de récupérer de l’information en moissonnant le HTML auquel accède un site web.
Le webscraping est un pis-aller pour accéder à de la donnée. Heureusement, il existe d’autres manières d’accéder à des données : les API de données. En informatique, une API est un ensemble de protocoles permettant à deux logiciels de communiquer entre eux. Par exemple, on parle parfois d’API Pandas ce qui désigne le fait que Pandas
est une interface entre votre code Python
et un langage compilé plus efficace (C
) qui fait les calculs que vous demandez au niveau de Python
. L’objectif d’une API est ainsi de fournir un point d’accès à une fonctionnalité qui soit facile à utiliser et qui masque les détails de la mise en oeuvre.
Dans ce chapitre, nous nous intéressons principalement aux API de données. Ces dernières sont simplement une façon de mettre à disposition des données : plutôt que de laisser l’utilisateur consulter directement des bases de données (souvent volumineuses et complexes), l’API lui propose de formuler une requête qui est traitée par le serveur hébergeant la base de données, puis de recevoir des données en réponse à sa requête.
L’utilisation accrue d’API dans le cadre de stratégies open-data est l’un des piliers des 15 feuilles de route ministérielles françaises en matière d’ouverture, de circulation et de valorisation des données publiques.
Note
Depuis quelques années, un service officiel de géocodage a été mis en place pour le territoire français. Celui-ci est gratuit et permet de manière efficace de coder des adresses à partir d’une API. Cette API, connue sous le nom de la Base d’Adresses Nationale (BAN) a bénéficié de la mise en commun de données de plusieurs acteurs (collectivités locales, Poste, IGN) et de compétences d’acteurs comme Etalab. La documentation de celle-ci est disponible à l’adresse https://api.gouv.fr/les-api/base-adresse-nationale.
On prend souvent comme exemple pour illustrer les API l’exemple du restaurant. La documentation est votre menu : elle liste les plats (les bases de données) que vous pouvez commander et les éventuels ingrédients de celle-ci que vous pouvez choisir (les paramètres de votre requête) : poulet, boeuf ou option végé ? Lorsque vous faites ceci, vous ne connaissez pas la recette utilisée en arrière cuisine pour faire votre plat: vous recevez seulement celui-ci. De manière logique, plus le plat que vous avez demandé est raffiné (calculs complexes côté serveur), plus votre plat mettra du temps à vous arriver.
Illustration avec l’API BAN
Pour illustrer ceci, imaginons ce qu’il se passe lorsque, dans la suite du chapitre, nous ferons des requêtes à l’API BAN.
Via Python
, on envoie notre commande à celle-ci: des adresses plus ou moins complètes avec des instructions annexes comme le code commune. Ces instructions annexes peuvent s’apparenter à des informations fournies au serveur du restaurant comme des interdits alimentaires qui vont personnaliser la recette.
A partir de ces instructions, le plat est lancé. En l’occurrence, il s’agit de faire tourner sur les serveurs d’Etalab une routine qui va chercher dans un référentiel d’adresse celle qui est la plus similaire à celle qu’on a demandé en adaptant éventuellement en fonction des instructions annexes qu’on a fourni. Une fois que côté cuisine on a fini cette préparation, on renvoie le plat au client. En l’occurrence, le plat sera des coordonnées géographiques qui correspondent à l’adresse la plus similaire.
Le client n’a donc qu’à se préoccuper de faire une bonne requête et d’apprécier le plat qui lui est fourni. L’intelligence dans la mise en oeuvre est laissée aux spécialistes qui ont conçu l’API. Peut-être que d’autres spécialistes, par exemple Google Maps, mettent en oeuvre une recette différente pour ce même plat (des coordonnées géographiques) mais ils vous proposeront probablement un menu très similaire. Ceci vous simplifie beaucoup la vie: il vous suffit de changer quelques lignes de code d’appel à une API plutôt que de modifier un ensemble long et complexe de méthodes d’identification d’adresses.
Approche pédagogique
Après une première présentation du principe général des API, ce chapitre illustre l’usage de celles-ci via Python
par le biais d’un use case assez standard: on dispose d’un jeu de données qu’on désire d’abord géolocaliser. Pour cela, on va demander à une API de nous renvoyer des coordonnées géographiques à partir d’adresses. Ensuite on ira chercher des informations un peu plus complexes par le biais d’autres API.
2 Première utilisation d’API
Une API a donc vocation à servir d’intermédiaire entre un client et un serveur. Ce client peut être de deux types: une interface web ou un logiciel de programmation. L’API ne fait pas d’a priori sur l’outil qui sert lui passe une commande, elle lui demande seulement de respecter un standard (en général une requête http), une structure de requête (les arguments) et d’attendre le résultat.
2.1 Comprendre le principe avec un exemple interactif
Le premier mode (accès par un navigateur) est principalement utilisé lorsqu’une interface web permet à un utilisateur de faire des choix afin de lui renvoyer des résultats correspondant à ceux-ci. Prenons à nouveau l’exemple de l’API de géolocalisation que nous utiliserons dans ce chapitre. Imaginons une interface web permettant à l’utilisateur deux choix: un code postal et une adresse. Cela sera injecté dans la requête et le serveur répondra avec la géolocalisation adaptée.
Voici donc nos deux widgets pour permettre au client (l’utilisateur de la page web) de choisir son adresse.
Une petite mise en forme des valeurs renseignées par ce widget permet d’obtenir la requête voulue:
Ce qui nous donne un output au format JSON, le format de sortie d’API le plus commun.
Si on veut un beau rendu, comme la carte ci-dessus, il faudra que le navigateur retravaille cet output, ce qui se fait normalement avec Javascript
, le langage de programmation embarqué par les navigateurs.
2.3 Comment connaître les inputs et outputs des API ?
Ici on a pris l’API BAN comme un outil magique dont on connaissait les principaux inputs (l’endpoint, les paramètres et leur formattage…). Mais comment faire, en pratique, pour en arriver là ? Tout simplement en lisant la documentation lorsqu’elle existe et en testant celle-ci via des exemples.
Les bonnes API proposent un outil interactif qui s’appelle le swagger
. C’est un site web interactif où sont décrites les principales fonctionnalités de l’API et où l’utilisateur peut tester des exemples interactivement. Ces documentations sont souvent créées automatiquement lors de la construction d’une API et mises à disposition par le biais d’un point d’entrée /docs
. Elles permettent souvent d’éditer certains paramètres dans le navigateur, voir le JSON obtenu (ou l’erreur générée) et récupérer la requête formattée qui permet d’obtenir celui-ci. Ces consoles interactives dans le navigateur permettent de répliquer le tâtonnement qu’on peut faire par ailleurs dans des outils spécialisés comme postman
.
Concernant l’API BAN, la documentation se trouve sur https://adresse.data.gouv.fr/api-doc/adresse. Elle n’est pas interactive, malheureusement. Mais elle présente de nombreux exemples qui peuvent être testés directement depuis le navigateur. Il suffit d’utiliser les URL proposés comme exemple. Ceux-ci sont présentées par le biais de curl
(un équivalent de request
en ligne de commande Linux):
"https://api-adresse.data.gouv.fr/search/?q=8+bd+du+port&limit=15" curl
Il suffit de copier l’URL en question (https://api-adresse.data.gouv.fr/search/?q=8+bd+du+port&limit=15
), d’ouvrir un nouvel onglet et vérifier que cela produit bien un résultat. Puis de changer un paramètre et vérifier à nouveau, jusqu’à trouver la structure qui convient. Et après, on peut passer à Python
comme le propose l’exercice suivant.
2.4 Application
Pour commencer cet exercice, vous aurez besoin de cette variable:
= "88 Avenue Verdier" adresse
Exercice 1: Structurer un appel à une API depuis Python
- Tester sans aucun autre paramètre, le retour de notre API. Transformer en
DataFrame
le résultat. - Se restreindre à Montrouge avec le paramètre ad hoc et la recherche du code insee ou code postal adéquat sur google.
- (Optionnel): Représenter l’adresse trouvée sur une carte
Les deux premières lignes du dataframe obtenu à la question 1 devraient être
label | score | housenumber | id | banId | name | postcode | citycode | x | y | city | context | type | importance | street | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 88 Avenue Verdier 92120 Montrouge | 0.973564 | 88 | 92049_9625_00088 | 92dd3c4a-6703-423d-bf09-fc0412fb4f89 | 88 Avenue Verdier | 92120 | 92049 | 649270.67 | 6857572.24 | Montrouge | 92, Hauts-de-Seine, Île-de-France | housenumber | 0.7092 | Avenue Verdier |
1 | Avenue Verdier 44500 La Baule-Escoublac | 0.719373 | NaN | 44055_3690 | NaN | Avenue Verdier | 44500 | 44055 | 291884.83 | 6701220.48 | La Baule-Escoublac | 44, Loire-Atlantique, Pays de la Loire | street | 0.6006 | Avenue Verdier |
A la question 2, on ressort cette fois qu’une seule observation, qu’on pourrait retravailler avec GeoPandas
pour vérifier qu’on a bien placé ce point sur une carte
label | score | housenumber | id | banId | name | postcode | citycode | x | y | city | context | type | importance | street | geometry | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 88 Avenue Verdier 92120 Montrouge | 0.973564 | 88 | 92049_9625_00088 | 92dd3c4a-6703-423d-bf09-fc0412fb4f89 | 88 Avenue Verdier | 92120 | 92049 | 649270.67 | 6857572.24 | Montrouge | 92, Hauts-de-Seine, Île-de-France | housenumber | 0.7092 | Avenue Verdier | POINT (2.30914 48.81622) |
Enfin, à la question 3, on obtient cette carte (plus ou moins la même que précédemment):
Make this Notebook Trusted to load map: File -> Trust Notebook
Quelques API à connaître
Les principaux fournisseurs de données officielles proposent des API. C’est le cas notamment de l’Insee, d’Eurostat, de la BCE, de la FED, de la Banque Mondiale…
Néanmoins, la production de données par les institutions étatiques est loin d’être restreinte aux producteurs de statistiques publiques. Le portail API gouv est le point de référencement principal pour les API produites par l’administration centrale française ou des administrations territoriales. De nombreuses villes publient également des données sur leurs infrastructures par le biais d’API, par exemple la ville de Paris.
Les producteurs de données privées proposent également des API. Par exemple, la SNCF ou la RATP proposent des API pour certains usages. Les grands acteurs du numérique, par exemple Spotify
proposent généralement des API pour intégrer certains de leurs services à des applications externes.
Cependant, il faut être conscient des limites de certaines API. En premier lieu, les données partagées ne sont pas forcément très riches pour ne pas compromettre la confidentialité des informations partagées par les utilisateurs du service ou la part de marché du producteur qui n’a pas intérêt à vous partager ses données à forte valeur. Il faut également être conscient du fait qu’une API peut disparaître ou changer de structure du jour au lendemain. Les codes de restructuration de données étant assez adhérants à une structure d’API, on peut se retrouver à devoir changer un volume conséquent de code si une API critique change substantiellement.
3 Plus d’exemples de requêtes GET
3.1 Source principale
Nous allons utiliser comme base principale pour ce tutoriel la base permanente des équipements, un répertoire d’équipements publics accueillant du public.
On va commencer par récupérer les données qui nous intéressent. On ne récupère pas toutes les variables du fichier mais seulement celles qu’ils nous intéressent: quelques variables sur l’équipement, son adresse et sa commune d’appartement.
Nous allons nous restreindre aux établissements d’enseignement primaire, secondaire et supérieur du département de la Haute-Garonne (le département 31). Ces établissements sont identifiés par un code particulier, entre C1
et C5
.
= """
query FROM read_parquet('https://minio.lab.sspcloud.fr/lgaliana/diffusion/BPE23.parquet')
SELECT NOMRS, NUMVOIE, INDREP, TYPVOIE, LIBVOIE,
CADR, CODPOS, DEPCOM, DEP, TYPEQU,
concat_ws(' ', NUMVOIE, INDREP, TYPVOIE, LIBVOIE) AS adresse, SIRET
WHERE DEP = '31'
AND starts_with(TYPEQU, 'C')
AND NOT (starts_with(TYPEQU, 'C6') OR starts_with(TYPEQU, 'C7'))
"""
import duckdb
= duckdb.sql(query)
bpe = bpe.to_df() bpe
3.2 Récupérer des données à façon grâce aux API
Nous avons vu précédemment le principe général d’une requête d’API. Pour illustrer, de manière plus massive, la récupération de données par le biais d’une API, essayons de récupérer des données complémentaires à notre source principale. Nous allons utiliser l’annuaire de l’éducation qui fournit de nombreuses informations sur les établissements scolaires. Nous utiliserons le SIRET pour croiser les deux sources de données.
L’exercice suivant viendra illustrer l’intérêt d’utiliser une API pour avoir des données à façon et la simplicité à récupéreer celles-ci via Python
. Néanmoins, cet exercice illustrera également une des limites de certaines API, à savoir la volumétrie des données à récupérer.
Exercice 2
- Visiter le swagger de l’API de l’Annuaire de l’Education nationale sur api.gouv.fr/documentation et tester une première récupération de données en utilisant le endpoint
records
sans aucun paramètre. - Puisqu’on n’a conservé que les données de la Haute Garonne dans notre base principale, on désire ne récupérer que les établissements de ce département par le biais de notre API. Faire une requête avec le paramètre ad hoc, sans en ajouter d’autres.
- Augmenter la limite du nombre de paramètres, voyez-vous le problème ?
- On va tenter de récupérer ces données par le biais de l’API tabular de
data.gouv
. Sa documentation est ici et l’identifiant de la ressource estb22f04bf-64a8-495d-b8bb-d84dbc4c7983
(source). Avec l’aide de la documentation, essayer de récupérer des données par le biais de cette API en utilisant le paramètreCode_departement__exact=031
pour ne garder que le département d’intérêt. - Voyez-vous le problème et comment nous pourrions automatiser la récupération de données ?
La première question nous permet de récupérer un premier jeu de données
identifiant_de_l_etablissement | nom_etablissement | type_etablissement | statut_public_prive | adresse_1 | adresse_2 | adresse_3 | code_postal | code_commune | nom_commune | ... | libelle_nature | code_type_contrat_prive | pial | etablissement_mere | type_rattachement_etablissement_mere | code_circonscription | code_zone_animation_pedagogique | libelle_zone_animation_pedagogique | code_bassin_formation | libelle_bassin_formation | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0470395Z | Ecole primaire | Ecole | Public | 8 impasse du chateau | AU BOURG | 47150 GAVAUDUN | 47150 | 47109 | Gavaudun | ... | ECOLE DE NIVEAU ELEMENTAIRE | 99 | 0470026Y | None | None | 0470786Z | 047010 | ZAP 047010 VILLENEUVE S/LOT FUMEL | None | None |
1 | 0470423E | Ecole élémentaire | Ecole | Public | 138 route de Massels | NOUVEAU BOURG | 47140 AURADOU | 47140 | 47017 | Auradou | ... | ECOLE DE NIVEAU ELEMENTAIRE | 99 | 0470031D | None | None | 0470904C | 047010 | ZAP 047010 VILLENEUVE S/LOT FUMEL | None | None |
2 rows × 72 columns
Néanmoins, on a deux problèmes: le nombre de lignes et le département d’intérêt. Essayons déjà avec la question 2 de changer ce dernier.
identifiant_de_l_etablissement | nom_etablissement | type_etablissement | statut_public_prive | adresse_1 | adresse_2 | adresse_3 | code_postal | code_commune | nom_commune | ... | libelle_nature | code_type_contrat_prive | pial | etablissement_mere | type_rattachement_etablissement_mere | code_circonscription | code_zone_animation_pedagogique | libelle_zone_animation_pedagogique | code_bassin_formation | libelle_bassin_formation | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0310166M | Ecole primaire publique Aérogare | Ecole | Public | 4 place de Verdun | None | 31700 BLAGNAC | 31700 | 31069 | Blagnac | ... | ECOLE DE NIVEAU ELEMENTAIRE | 99 | 0311581A | None | None | 0312602K | None | None | 16127 | TOULOUSE NORD-OUEST |
1 | 0310174W | Ecole maternelle publique | Ecole | Public | Rue des Ecoles | None | 31230 L ISLE EN DODON | 31230 | 31239 | L'Isle-en-Dodon | ... | ECOLE MATERNELLE | 99 | 0310003K | None | None | 0311108L | None | None | 16106 | COMMINGES |
2 | 0310175X | Ecole maternelle publique André Massat | Ecole | Public | Rue Saint-Victor | None | 31310 MONTESQUIEU VOLVESTRE | 31310 | 31375 | Montesquieu-Volvestre | ... | ECOLE MATERNELLE | 99 | 0310012V | None | None | 0311109M | None | None | 16107 | MURET |
3 | 0310182E | Ecole maternelle publique la résidence | Ecole | Public | Rue de la Résidence | None | 31800 ST GAUDENS | 31800 | 31483 | Saint-Gaudens | ... | ECOLE MATERNELLE | 99 | 0310083X | None | None | 0311108L | None | None | 16106 | COMMINGES |
4 | 0310184G | Ecole maternelle publique les caussades | Ecole | Public | 15 rue des Caussades | None | 31800 ST GAUDENS | 31800 | 31483 | Saint-Gaudens | ... | ECOLE MATERNELLE | 99 | 0310083X | None | None | 0311108L | None | None | 16106 | COMMINGES |
5 rows × 72 columns
C’est mieux mais nous avons toujours seulement 10 observations. Si on essayer d’ajuster le nombre de lignes (question 3), on obtient le retour suivant de l’API:
b'{\n "error_code": "InvalidRESTParameterError",\n "message": "Invalid value for limit API parameter: 200 was found but -1 <= limit <= 100 is expected."\n}'
Essayons avec des données plus exhaustives: le fichier brut sur data.gouv
. Comme on peut le voir dans les métadonnées, on sait qu’on a plus de 1000 écoles dont on peut récupérer des données mais qu’on en a ici extrait seulement 20. Le champ next
nous donne directement l’URL à utiliser pour récupérer les 20 pages suivantes: c’est grâce à lui qu’on a une chance de récupérer toutes nos données d’intérêt.
La partie intéressante pour automatiser la récupération de nos données est la clé links
du JSON:
{'profile': 'https://tabular-api.data.gouv.fr/api/resources/b22f04bf-64a8-495d-b8bb-d84dbc4c7983/profile/',
'swagger': 'https://tabular-api.data.gouv.fr/api/resources/b22f04bf-64a8-495d-b8bb-d84dbc4c7983/swagger/',
'next': 'https://tabular-api.data.gouv.fr/api/resources/b22f04bf-64a8-495d-b8bb-d84dbc4c7983/data/?Code_departement__exact=031&page=2&page_size=20',
'prev': None}
En bouclant sur celui-ci pour parcourir la liste des URL accessibles, on peut récupérer des données. Comme le code d’automatisation est assez fastidieux à écrire, le voici :
import requests
import pandas as pd
# Initialize the initial API URL
= "https://tabular-api.data.gouv.fr/api/resources/b22f04bf-64a8-495d-b8bb-d84dbc4c7983/data/?Code_departement__exact=031&page_size=50"
url_api_datagouv
# Initialize an empty list to store all data entries
= []
all_data
# Initialize the URL for pagination
= url_api_datagouv
current_url
# Loop until there is no next page
while current_url:
try:
# Make a GET request to the current URL
= requests.get(current_url)
response # Raise an exception for HTTP errors
response.raise_for_status()
# Parse the JSON response
= response.json()
json_response
# Extract data and append to the all_data list
= json_response.get("data", [])
page_data
all_data.extend(page_data)print(f"Fetched {len(page_data)} records from {current_url}")
# Get the next page URL
= json_response.get("links", {})
links = links.get("next") # This will be None if there's no next page
current_url
except requests.exceptions.RequestException as e:
print(f"An error occurred: {e}")
break
Le DataFrame obtenu est le suivant:
= pd.DataFrame(all_data)
schools_dep31 schools_dep31.head()
__id | Identifiant_de_l_etablissement | Nom_etablissement | Type_etablissement | Statut_public_prive | Adresse_1 | Adresse_2 | Adresse_3 | Code_postal | Code_commune | ... | libelle_nature | Code_type_contrat_prive | PIAL | etablissement_mere | type_rattachement_etablissement_mere | code_circonscription | code_zone_animation_pedagogique | libelle_zone_animation_pedagogique | code_bassin_formation | libelle_bassin_formation | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 3346 | 0310160F | Ecole élémentaire d'application Ricardie 3 | Ecole | Public | 54 avenue de l'URSS | None | 31400 TOULOUSE | 31400 | 31555 | ... | ECOLE ELEMENTAIRE D APPLICATION | 99 | 0311338L | None | None | 0312825C | None | None | 16109 | TOULOUSE CENTRE |
1 | 3347 | 0310161G | Ecole primaire publique Calas - Dupont | Ecole | Public | 101 grande rue Saint-Michel | None | 31400 TOULOUSE | 31400 | 31555 | ... | ECOLE DE NIVEAU ELEMENTAIRE | 99 | 0311338L | None | None | 0312825C | None | None | 16109 | TOULOUSE CENTRE |
2 | 3348 | 0310179B | Ecole maternelle publique Jean Jaurès | Ecole | Public | Allées des Tilleuls | None | 31120 PORTET SUR GARONNE | 31120 | 31433 | ... | ECOLE MATERNELLE | 99 | 0311093V | None | None | 0311105H | None | None | 16108 | TOULOUSE SUD-OUEST |
3 | 3349 | 0310181D | Ecole maternelle publique Roger Sudre | Ecole | Public | Rue Montpezat | None | 31250 REVEL | 31250 | 31451 | ... | ECOLE MATERNELLE | 99 | 0311690U | None | None | 0311102E | None | None | 16128 | TOULOUSE EST |
4 | 3350 | 0310184G | Ecole maternelle publique les caussades | Ecole | Public | 15 rue des Caussades | None | 31800 ST GAUDENS | 31800 | 31483 | ... | ECOLE MATERNELLE | 99 | 0310083X | None | None | 0311108L | None | None | 16106 | COMMINGES |
5 rows × 73 columns
On peut fusionner ces nouvelles données avec nos données précédentes pour enrichir celles-ci. Pour faire une production fiable, il faudrait faire attention aux écoles qui ne s’apparient pas mais ce n’est pas grave pour cette série d’exercices.
= bpe.merge(schools_dep31, left_on="SIRET", right_on="SIREN_SIRET") bpe_enriched
Cela nous donne des données enrichies de nouvelles caractéristiques sur les établissements. Il y a des coordonnées géographiques dans celles-ci mais nous allons faire comme s’il n’y en avait pas pour ré-utiliser notre API de géolocalisation.
4 Découverte des requêtes POST
4.1 Logique
Nous avons jusqu’à présent évoqué les requêtes GET
. Nous allons maintenant présenter les requêtes POST
qui permettent d’interagir de manière plus complexe avec des serveurs de l’API.
Pour découvrir celles-ci, nous allons reprendre l’API de géolocalisation précédente mais utiliser un autre point d’entrée qui nécessite une requête POST
.
Ces dernières sont généralement utilisées quand il est nécessaire d’envoyer des données particulières pour déclencher une action. Par exemple, dans le monde du web, si vous avez une authentification à mettre en oeuvre, une requête POST
permettra d’envoyer un token au serveur qui répondra en acceptant votre authentification.
Dans notre cas, nous allons envoyer des données au serveur, ce dernier va les recevoir, les utiliser pour la géolocalisation puis nous envoyer une réponse. Pour continuer sur la métaphore culinaire, c’est comme si vous donniez vous-mêmes à la cuisine un tupperware pour récupérer votre plat à emporter.
4.2 Principe
Prenons cette requête proposée sur le site de documentation de l’API de géolocalisation:
curl -X POST -F data=@path/to/file.csv -F columns=voie -F columns=ville -F citycode=ma_colonne_code_insee https://api-adresse.data.gouv.fr/search/csv/
Comme nous avons pu l’évoquer précédemment, curl
est un outil en ligne de commande qui permet de faire des requêtes API. L’option -X POST
indique, de manière assez transparente, qu’on désire faire une requête POST
.
Les autres arguments sont passés par le biais des options -F
. En l’occurrence, on envoie un fichier et on ajoute des paramètres pour aider le serveur à aller chercher la donnée dedans. L’@
indique que file.csv
doit être lu sur le disque et envoyé dans le corps de la requête comme une donnée de formulaire.
4.3 Application avec Python
Nous avions requests.get
, il est donc logique que nous ayons requests.post
. Cette fois, il faudra passer des paramètres à notre requête sous la forme d’un dictionnaire dont les clés sont le nom de l’argument et les valeurs sont des objets Python
.
Le principal défi, illustré dans le prochain exercice, est le passage de l’argument data
: il faudra renvoyer le fichier comme un objet Python
par le biais de la fonction open
.
Exercice 3: une requête POST pour géolocaliser en masse nos données
- Enregistrer au format CSV les colonnes
adresse
,DEPCOM
etNom_commune
de la base d’équipements fusionnée avec notre répertoire précédent (objetbpe_enriched
). Il peut être utile, avant l’écriture au format CSV, de remplacer les virgules dans la colonneadresse
par des espaces. - Créer l’objet
response
avecrequests.post
et les bons arguments pour géocoder votre CSV. - Transformer votre output en objet
geopandas
avec la commande suivante:
= pd.read_csv(io.StringIO(response.text)) bpe_loc
Les géolocalisations obtenues prennent cette forme
index | adresse | DEPCOM | Nom_commune | result_score | latitude | longitude | |
---|---|---|---|---|---|---|---|
0 | 0 | LD LA BOURDETTE | 31001 | Agassac | 0.367587 | 43.379868 | 0.874645 |
1 | 1 | 21 CHE DE L AUTAN | 31003 | Aigrefeuille | 0.730293 | 43.567530 | 1.585745 |
En enrichissant les données précédentes, cela donne:
NOMRS | NUMVOIE | INDREP | TYPVOIE | LIBVOIE | CADR | CODPOS | DEPCOM | DEP | TYPEQU | ... | etablissement_mere | type_rattachement_etablissement_mere | code_circonscription | code_zone_animation_pedagogique | libelle_zone_animation_pedagogique | code_bassin_formation | libelle_bassin_formation | result_score | latitude_ban | longitude_ban | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | ECOLE PRIMAIRE PUBLIQUE DENIS LATAPIE | LD | LA BOURDETTE | 31230 | 31001 | 31 | C108 | ... | None | None | 0311108L | None | None | 16106 | COMMINGES | 0.367587 | 43.379868 | 0.874645 | |||
1 | ECOLE MATERNELLE PUBLIQUE | 21 | CHE | DE L AUTAN | 31280 | 31003 | 31 | C107 | ... | None | None | 0311102E | None | None | 16128 | TOULOUSE EST | 0.730293 | 43.567530 | 1.585745 |
2 rows × 88 columns
On peut vérifier que la géolocalisation ne soit pas trop délirante en comparant avec les longitudes et latitudes de l’annuaire de l’éducation ajouté précédemment:
NOMRS | Nom_commune | longitude_annuaire | longitude_ban | latitude_annuaire | latitude_ban | |
---|---|---|---|---|---|---|
786 | ECOLE MATERNELLE PUBLIQUE SAUZELONG | Toulouse | 1.461930 | 1.462216 | 43.579014 | 43.579132 |
498 | ECOLE ELEMENTAIRE PUBLIQUE JEAN MERMOZ | Muret | 1.333780 | 1.334034 | 43.467869 | 43.468277 |
62 | ECOLE MATERNELLE PUBLIQUE LES MESANGES | Beauzelle | 1.377058 | 1.377226 | 43.662119 | 43.662234 |
624 | ECOLE PRIMAIRE PUBLIQUE ANNE FRANK | Sainte-Foy-d'Aigrefeuille | 1.610310 | 1.603325 | 43.536311 | 43.554022 |
232 | ECOLE MATERNELLE PUBLIQUE LEON BLUM | Cugnaux | 1.347270 | 1.346527 | 43.538188 | 43.537320 |
Sans rentrer dans le détail, les positions semblent très similaires à quelques imprécisions près.
Pour profiter de nos données enrichies, on peut faire une carte. Pour ajouter un peu de contexte à celle-ci, on peut mettre un fond de carte des communes en arrière plan. Celui-ci peut être récupéré avec cartiflette
:
from cartiflette import carti_download
= carti_download(
shp_communes =4326,
crs=["31"],
values="COMMUNE",
borders="topojson",
vectorfile_format="DEPARTEMENT",
filter_by="EXPRESS-COG-CARTO-TERRITOIRE",
source=2022,
year
)= 4326 shp_communes.crs
This is an experimental version of cartiflette published on PyPi.
To use the latest stable version, you can install it directly from GitHub with the following command:
pip install git+https://github.com/inseeFrLab/cartiflette.git
ERROR 1: PROJ: proj_create_from_database: Open of /opt/conda/share/proj failed
Représentées sur une carte, cela donne la carte suivante:
Make this Notebook Trusted to load map: File -> Trust Notebook
5 Gestion des secrets et des exceptions
Nous avons déjà utilisé plusieurs API. Néanmoins ces dernières étaient toutes sans authentification et présentent peu de restrictions, hormis le nombre d’échos. Ce n’est pas le cas de toutes les API. Il est fréquent que les API qui permettent d’aspirer plus de données ou d’accéder à des données confidentielles nécessitent une authentification pour tracer les utilisateurs de données.
Cela se fait généralement par le biais d’un token. Ce dernier est une sorte de mot de passe, souvent utilisé dans les systèmes modernes d’authentification pour certifier de l’identité d’un utilisateur.trice (cf. chapitre Git
).
Pour illustrer l’usage des tokens, nous allons utiliser une API de l’Insee. Les API développées par l’institut statistique français nécessitent en effet une authentification. Nous allons chercher des informations agrégées de l’Insee sur la population dans chaque commune. Cela nous donnera une estimation, très grossière, du bassin de population autour d’un établissement.
Avant d’en arriver là, nous allons faire un aparté sur la confidentialité des tokens et la manière d’éviter de révéler ceux-ci dans votre code.
5.1 Utiliser un token dans un code sans le révéler
Les tokens sont des informations personnelles qui ne doivent pas être partagées. Ils n’ont pas vocation à être présent dans le code. Comme ceci est évoqué à plusieurs reprises dans le cours de mise en production que Romain Avouac et moi donnons en 3e année, il est important de séparer le code des éléments de configuration
L’idée est de trouver une recette pour apporter les éléments de configuration avec le code mais sans mettre ceux-ci en clair dans le code. L’idée générale sera de stocker la valeur du token dans une variable mais ne jamais révéler celle-ci dans le code. Comment faire dès lors pour déclarer la valeur du jeton sans que celui-ci soit apparent dans le code ?
- Pour un code amené à fonctionner de manière interactive (par exemple par le biais d’un notebook), il est possible de créer une boite de dialogue qui injectera la valeur renseignée dans une variable. Cela se fait par le biais du package
getpass
. - Pour le code qui tourne en non interactif, par exemple par le biais de la ligne de commande, l’approche par variable d’environnement est la plus fiable, à condition de faire attention à ne pas mettre le fichier de mot de passe dans
Git
.
L’exercice suivant permettra de mettre en oeuvre ces deux méthodes. Ces méthodes nous serviront à ajouter de manière confidentielle un payload à des requêtes d’authentification, c’est-à-dire des informations confidentielles identifiantes en complément d’une requête.
5.2 Application
Pour cette application, à partir de la question 4, nous allons avoir besoin de créer une classe spéciale permettant à requests
de surcharger notre requête d’un jeton d’authentification. Comme elle n’est pas triviale à créer sans connaissance préalable, la voici:
class BearerAuth(requests.auth.AuthBase):
def __init__(self, token):
self.token = token
def __call__(self, r):
"authorization"] = "Bearer " + self.token
r.headers[return r
Nous allons aussi avoir besoin de cette variable qui correspond au Siren de Decathlon
= "500569405" siren
Exercice 4: ajouter un payload à une requête
- Se créer un compte pour l’API de l’INPI (Institut national de la protection intellectuelle) qui nous servira à récupérer des bilans des comptes sociaux d’entreprises au format PDF.
- Créer les variables
username
etpassword
avecgetpass
en faisant en sorte de ne pas rentrer les valeurs dans le code. - En utilisant la documentation de l’API, l’argument
json
derequests.post
, récupérer un jeton d’authentification et le stocker dans une variabletoken
. - Récupérer les données en utilisant la f-string
f'https://registre-national-entreprises.inpi.fr/api/companies/{siren}/attachments'
et en donnant àrequests
l’argumentauth=BearerAuth(token)
- Créer
identifier = documents.get('bilans')[0]['id']
et utiliserrequests
avec l’URLf'https://registre-national-entreprises.inpi.fr/api/bilans/{identifier}/download'
, sans argument, pour récupérer un PDF. Cela a-t-il fonctionné ? Vérifier le status code. A quoi correspond-il ? Comment éviter cela ? - En supposant que l’objet
requests.get
créé s’appeller
, écrire l’output de notre API dans un PDF de la manière suivante:
= "decathlon.pdf"
binary_file_path with open(binary_file_path, "wb") as f:
f.write(r.content)
- Remplacer l’utilisation de
getpass
par l’approche variable d’environnement grâce àdotenv
A la question 5, sans identifiant, on récupère le code erreur 401, qui correspond à “Unauthorized”, c’est-à-dire à une requête refusée. Néanmoins, si on ajoute le token comme précédemment, tout se passe bien, on récupère le bilan de Decathlon.
Le PDF récupéré
Important
L’approche par variable d’environnement est la plus générale et malléable. Il faut néanmoins bien faire attention à ne pas oublier d’ajouter le .env
stockant les identifiants dans Git
. Autrement, vous risquez de révéler des informations identifiantes ce qui annule tout effet positif des bonnes pratiques mises en oeuvre avec dotenv
.
Pour cela, la solution est simple : ajouter la ligne .env
au .gitignore
et par sécurité *.env
au cas où le fichier ne soit pas à la racine du dépôt. Pour en savoir plus sur ce fichier .gitignore
, se rendre sur les chapitres Git
.
6 Ouverture aux API de modèles
Nous avons vu jusqu’à présent des API de données. Celles-ci permettent
de récupérer du code. Ce n’est néanmoins pas la seule utilisation des API intéressantes pour les utilisateurs de Python
.
Il existe de nombreux autres types d’API. Parmi celles-ci, les API de modèles sont intéressantes. Elles permettent de récupérer des modèles pré-entraînés voire effectuer une phase d’inférence sur des serveurs spécialisés ayant plus de ressources que son ordinateur local (plus d’éléments dans les parties machine learning et NLP). La librairie la plus connue dans ce domaine est la librairie transformers
développée par HuggingFace
.
L’un des objectifs du cours de 3A de mise en production est de montrer comment ce type d’architecture logicielle fonctionne et comment celle-ci peut être créée sur des modèles que vous auriez vous-mêmes créés.
7 Exercices supplémentaires
Exercice bonus
Dans notre exemple sur les écoles, se restreindre aux lycées et ajouter les informations sur la valeur ajoutée des lycées disponibles ici.
Informations additionnelles
environment files have been tested on.
Latest built version: 2025-01-15
Python version used:
'3.12.6 | packaged by conda-forge | (main, Sep 30 2024, 18:08:52) [GCC 13.3.0]'
Package | Version |
---|---|
affine | 2.4.0 |
aiobotocore | 2.15.1 |
aiohappyeyeballs | 2.4.3 |
aiohttp | 3.10.8 |
aioitertools | 0.12.0 |
aiosignal | 1.3.1 |
alembic | 1.13.3 |
altair | 5.4.1 |
aniso8601 | 9.0.1 |
annotated-types | 0.7.0 |
anyio | 4.8.0 |
appdirs | 1.4.4 |
archspec | 0.2.3 |
asttokens | 2.4.1 |
attrs | 24.2.0 |
babel | 2.16.0 |
bcrypt | 4.2.0 |
beautifulsoup4 | 4.12.3 |
black | 24.8.0 |
blinker | 1.8.2 |
blis | 0.7.11 |
bokeh | 3.5.2 |
boltons | 24.0.0 |
boto3 | 1.35.23 |
botocore | 1.35.23 |
branca | 0.7.2 |
Brotli | 1.1.0 |
cachetools | 5.5.0 |
cartiflette | 0.0.2 |
Cartopy | 0.24.1 |
catalogue | 2.0.10 |
cattrs | 24.1.2 |
certifi | 2024.8.30 |
cffi | 1.17.1 |
charset-normalizer | 3.3.2 |
click | 8.1.7 |
click-plugins | 1.1.1 |
cligj | 0.7.2 |
cloudpathlib | 0.20.0 |
cloudpickle | 3.0.0 |
colorama | 0.4.6 |
comm | 0.2.2 |
commonmark | 0.9.1 |
conda | 24.9.1 |
conda-libmamba-solver | 24.7.0 |
conda-package-handling | 2.3.0 |
conda_package_streaming | 0.10.0 |
confection | 0.1.5 |
contextily | 1.6.2 |
contourpy | 1.3.0 |
cryptography | 43.0.1 |
cycler | 0.12.1 |
cymem | 2.0.10 |
cytoolz | 1.0.0 |
dask | 2024.9.1 |
dask-expr | 1.1.15 |
databricks-sdk | 0.33.0 |
dataclasses-json | 0.6.7 |
debugpy | 1.8.6 |
decorator | 5.1.1 |
Deprecated | 1.2.14 |
diskcache | 5.6.3 |
distributed | 2024.9.1 |
distro | 1.9.0 |
docker | 7.1.0 |
duckdb | 0.10.1 |
en-core-web-sm | 3.7.1 |
entrypoints | 0.4 |
et_xmlfile | 2.0.0 |
exceptiongroup | 1.2.2 |
executing | 2.1.0 |
fastexcel | 0.11.6 |
fastjsonschema | 2.21.1 |
fiona | 1.10.1 |
Flask | 3.0.3 |
folium | 0.17.0 |
fontawesomefree | 6.6.0 |
fonttools | 4.54.1 |
fr-core-news-sm | 3.7.0 |
frozendict | 2.4.4 |
frozenlist | 1.4.1 |
fsspec | 2023.12.2 |
geographiclib | 2.0 |
geopandas | 1.0.1 |
geoplot | 0.5.1 |
geopy | 2.4.1 |
gitdb | 4.0.11 |
GitPython | 3.1.43 |
google-auth | 2.35.0 |
graphene | 3.3 |
graphql-core | 3.2.4 |
graphql-relay | 3.2.0 |
graphviz | 0.20.3 |
great-tables | 0.12.0 |
greenlet | 3.1.1 |
gunicorn | 22.0.0 |
h11 | 0.14.0 |
h2 | 4.1.0 |
hpack | 4.0.0 |
htmltools | 0.6.0 |
httpcore | 1.0.7 |
httpx | 0.28.1 |
httpx-sse | 0.4.0 |
hyperframe | 6.0.1 |
idna | 3.10 |
imageio | 2.36.1 |
importlib_metadata | 8.5.0 |
importlib_resources | 6.4.5 |
inflate64 | 1.0.1 |
ipykernel | 6.29.5 |
ipython | 8.28.0 |
itsdangerous | 2.2.0 |
jedi | 0.19.1 |
Jinja2 | 3.1.4 |
jmespath | 1.0.1 |
joblib | 1.4.2 |
jsonpatch | 1.33 |
jsonpointer | 3.0.0 |
jsonschema | 4.23.0 |
jsonschema-specifications | 2024.10.1 |
jupyter-cache | 1.0.0 |
jupyter_client | 8.6.3 |
jupyter_core | 5.7.2 |
kaleido | 0.2.1 |
kiwisolver | 1.4.7 |
langchain | 0.3.14 |
langchain-community | 0.3.9 |
langchain-core | 0.3.29 |
langchain-text-splitters | 0.3.5 |
langcodes | 3.5.0 |
langsmith | 0.1.147 |
language_data | 1.3.0 |
lazy_loader | 0.4 |
libmambapy | 1.5.9 |
locket | 1.0.0 |
loguru | 0.7.3 |
lxml | 5.3.0 |
lz4 | 4.3.3 |
Mako | 1.3.5 |
mamba | 1.5.9 |
mapclassify | 2.8.1 |
marisa-trie | 1.2.1 |
Markdown | 3.6 |
markdown-it-py | 3.0.0 |
MarkupSafe | 2.1.5 |
marshmallow | 3.25.1 |
matplotlib | 3.9.2 |
matplotlib-inline | 0.1.7 |
mdurl | 0.1.2 |
menuinst | 2.1.2 |
mercantile | 1.2.1 |
mizani | 0.11.4 |
mlflow | 2.16.2 |
mlflow-skinny | 2.16.2 |
msgpack | 1.1.0 |
multidict | 6.1.0 |
multivolumefile | 0.2.3 |
munkres | 1.1.4 |
murmurhash | 1.0.11 |
mypy-extensions | 1.0.0 |
narwhals | 1.22.0 |
nbclient | 0.10.0 |
nbformat | 5.10.4 |
nest_asyncio | 1.6.0 |
networkx | 3.3 |
nltk | 3.9.1 |
numpy | 1.26.4 |
opencv-python-headless | 4.10.0.84 |
openpyxl | 3.1.5 |
opentelemetry-api | 1.16.0 |
opentelemetry-sdk | 1.16.0 |
opentelemetry-semantic-conventions | 0.37b0 |
orjson | 3.10.14 |
OWSLib | 0.28.1 |
packaging | 24.1 |
pandas | 2.2.3 |
paramiko | 3.5.0 |
parso | 0.8.4 |
partd | 1.4.2 |
pathspec | 0.12.1 |
patsy | 0.5.6 |
Pebble | 5.1.0 |
pexpect | 4.9.0 |
pickleshare | 0.7.5 |
pillow | 10.4.0 |
pip | 24.2 |
platformdirs | 4.3.6 |
plotly | 5.24.1 |
plotnine | 0.13.6 |
pluggy | 1.5.0 |
polars | 1.8.2 |
preshed | 3.0.9 |
prometheus_client | 0.21.0 |
prometheus_flask_exporter | 0.23.1 |
prompt_toolkit | 3.0.48 |
protobuf | 4.25.3 |
psutil | 6.0.0 |
ptyprocess | 0.7.0 |
pure_eval | 0.2.3 |
py7zr | 0.20.8 |
pyarrow | 17.0.0 |
pyarrow-hotfix | 0.6 |
pyasn1 | 0.6.1 |
pyasn1_modules | 0.4.1 |
pybcj | 1.0.3 |
pycosat | 0.6.6 |
pycparser | 2.22 |
pycryptodomex | 3.21.0 |
pydantic | 2.10.5 |
pydantic_core | 2.27.2 |
pydantic-settings | 2.7.1 |
Pygments | 2.18.0 |
PyNaCl | 1.5.0 |
pynsee | 0.1.8 |
pyogrio | 0.10.0 |
pyOpenSSL | 24.2.1 |
pyparsing | 3.1.4 |
pyppmd | 1.1.1 |
pyproj | 3.7.0 |
pyshp | 2.3.1 |
PySocks | 1.7.1 |
python-dateutil | 2.9.0 |
python-dotenv | 1.0.1 |
python-magic | 0.4.27 |
pytz | 2024.1 |
pyu2f | 0.1.5 |
pywaffle | 1.1.1 |
PyYAML | 6.0.2 |
pyzmq | 26.2.0 |
pyzstd | 0.16.2 |
querystring_parser | 1.2.4 |
rasterio | 1.4.3 |
referencing | 0.35.1 |
regex | 2024.9.11 |
requests | 2.32.3 |
requests-cache | 1.2.1 |
requests-toolbelt | 1.0.0 |
retrying | 1.3.4 |
rich | 13.9.4 |
rpds-py | 0.22.3 |
rsa | 4.9 |
Rtree | 1.3.0 |
ruamel.yaml | 0.18.6 |
ruamel.yaml.clib | 0.2.8 |
s3fs | 2023.12.2 |
s3transfer | 0.10.2 |
scikit-image | 0.24.0 |
scikit-learn | 1.5.2 |
scipy | 1.13.0 |
seaborn | 0.13.2 |
setuptools | 74.1.2 |
shapely | 2.0.6 |
shellingham | 1.5.4 |
six | 1.16.0 |
smart-open | 7.1.0 |
smmap | 5.0.0 |
sniffio | 1.3.1 |
sortedcontainers | 2.4.0 |
soupsieve | 2.5 |
spacy | 3.7.5 |
spacy-legacy | 3.0.12 |
spacy-loggers | 1.0.5 |
SQLAlchemy | 2.0.35 |
sqlparse | 0.5.1 |
srsly | 2.5.0 |
stack-data | 0.6.2 |
statsmodels | 0.14.4 |
tabulate | 0.9.0 |
tblib | 3.0.0 |
tenacity | 9.0.0 |
texttable | 1.7.0 |
thinc | 8.2.5 |
threadpoolctl | 3.5.0 |
tifffile | 2025.1.10 |
toolz | 1.0.0 |
topojson | 1.9 |
tornado | 6.4.1 |
tqdm | 4.66.5 |
traitlets | 5.14.3 |
truststore | 0.9.2 |
typer | 0.15.1 |
typing_extensions | 4.12.2 |
typing-inspect | 0.9.0 |
tzdata | 2024.2 |
Unidecode | 1.3.8 |
url-normalize | 1.4.3 |
urllib3 | 1.26.20 |
wasabi | 1.1.3 |
wcwidth | 0.2.13 |
weasel | 0.4.1 |
webdriver-manager | 4.0.2 |
websocket-client | 1.8.0 |
Werkzeug | 3.0.4 |
wheel | 0.44.0 |
wordcloud | 1.9.3 |
wrapt | 1.16.0 |
xgboost | 2.1.1 |
xlrd | 2.0.1 |
xyzservices | 2024.9.0 |
yarl | 1.13.1 |
yellowbrick | 1.5 |
zict | 3.0.0 |
zipp | 3.20.2 |
zstandard | 0.23.0 |
View file history
SHA | Date | Author | Description |
---|---|---|---|
3c22d3a | 2025-01-15 11:40:33 | lgaliana | SIREN Decathlon |
e182c9a | 2025-01-13 23:03:24 | Lino Galiana | Finalisation nouvelle version chapitre API (#586) |
f992df0 | 2025-01-06 16:50:39 | lgaliana | Code pour import BPE |
dc4a475 | 2025-01-03 17:17:34 | Lino Galiana | Révision de la partie API (#584) |
6c6dfe5 | 2024-12-20 13:40:33 | lgaliana | eval false for API chapter |
e56a219 | 2024-10-30 17:13:03 | Lino Galiana | Intro partie modélisation & typo geopandas (#571) |
9d8e69c | 2024-10-21 17:10:03 | lgaliana | update badges shortcode for all manipulation part |
47a0770 | 2024-08-23 07:51:58 | linogaliana | fix API notebook |
1953609 | 2024-08-12 16:18:19 | linogaliana | One button is enough |
783a278 | 2024-08-12 11:07:18 | Lino Galiana | Traduction API (#538) |
580cba7 | 2024-08-07 18:59:35 | Lino Galiana | Multilingual version as quarto profile (#533) |
101465f | 2024-08-07 13:56:35 | Lino Galiana | regex, webscraping and API chapters in 🇬🇧 (#532) |
065b0ab | 2024-07-08 11:19:43 | Lino Galiana | Nouveaux callout dans la partie manipulation (#513) |
06d003a | 2024-04-23 10:09:22 | Lino Galiana | Continue la restructuration des sous-parties (#492) |
8c316d0 | 2024-04-05 19:00:59 | Lino Galiana | Fix cartiflette deprecated snippets (#487) |
005d89b | 2023-12-20 17:23:04 | Lino Galiana | Finalise l’affichage des statistiques Git (#478) |
3fba612 | 2023-12-17 18:16:42 | Lino Galiana | Remove some badges from python (#476) |
a06a268 | 2023-11-23 18:23:28 | Antoine Palazzolo | 2ème relectures chapitres ML (#457) |
b68369d | 2023-11-18 18:21:13 | Lino Galiana | Reprise du chapitre sur la classification (#455) |
889a71b | 2023-11-10 11:40:51 | Antoine Palazzolo | Modification TP 3 (#443) |
04ce567 | 2023-10-23 19:04:01 | Lino Galiana | Mise en forme chapitre API (#442) |
3eb0aeb | 2023-10-23 11:59:24 | Thomas Faria | Relecture jusqu’aux API (#439) |
a771183 | 2023-10-09 11:27:45 | Antoine Palazzolo | Relecture TD2 par Antoine (#418) |
a63319a | 2023-10-04 15:29:04 | Lino Galiana | Correction du TP numpy (#419) |
154f09e | 2023-09-26 14:59:11 | Antoine Palazzolo | Des typos corrigées par Antoine (#411) |
3bdf3b0 | 2023-08-25 11:23:02 | Lino Galiana | Simplification de la structure 🤓 (#393) |
130ed71 | 2023-07-18 19:37:11 | Lino Galiana | Restructure les titres (#374) |
f0c583c | 2023-07-07 14:12:22 | Lino Galiana | Images viz (#371) |
ef28fef | 2023-07-07 08:14:42 | Lino Galiana | Listing pour la première partie (#369) |
f21a24d | 2023-07-02 10:58:15 | Lino Galiana | Pipeline Quarto & Pages 🚀 (#365) |
62aeec1 | 2023-06-10 17:40:39 | Lino Galiana | Avertissement sur la partie API (#358) |
38693f6 | 2023-04-19 17:22:36 | Lino Galiana | Rebuild visualisation part (#357) |
3248633 | 2023-02-18 13:11:52 | Lino Galiana | Shortcode rawhtml (#354) |
3c880d5 | 2022-12-27 17:34:59 | Lino Galiana | Chapitre regex + Change les boites dans plusieurs chapitres (#339) |
f5f0f9c | 2022-11-02 19:19:07 | Lino Galiana | Relecture début partie modélisation KA (#318) |
2dc82e7 | 2022-10-18 22:46:47 | Lino Galiana | Relec Kim (visualisation + API) (#302) |
f10815b | 2022-08-25 16:00:03 | Lino Galiana | Notebooks should now look more beautiful (#260) |
494a85a | 2022-08-05 14:49:56 | Lino Galiana | Images featured ✨ (#252) |
d201e3c | 2022-08-03 15:50:34 | Lino Galiana | Pimp la homepage ✨ (#249) |
1239e3e | 2022-06-21 14:05:15 | Lino Galiana | Enonces (#239) |
bb38643 | 2022-06-08 16:59:40 | Lino Galiana | Répare bug leaflet (#234) |
5698e30 | 2022-06-03 18:28:37 | Lino Galiana | Finalise widget (#232) |
7b9f27b | 2022-06-03 17:05:15 | Lino Galiana | Essaie régler les problèmes widgets JS (#231) |
1ca1a8a | 2022-05-31 11:44:23 | Lino Galiana | Retour du chapitre API (#228) |
Citation
BibTeX
@book{galiana2023,
author = {Galiana, Lino},
title = {Python pour la data science},
date = {2023},
url = {https://pythonds.linogaliana.fr/},
doi = {10.5281/zenodo.8229676},
langid = {fr}
}
Veuillez citer ce travail comme suit :
Galiana, Lino. 2023. Python pour la data science. https://doi.org/10.5281/zenodo.8229676.
2.2 Comment faire avec
Python
?Le principe est le même sauf que nous perdons l’aspect interactif. Il s’agira donc, avec
Python
, de construire l’URL voulu et d’aller chercher via une requête HTTP le résultat.Nous avons déjà vu dans le chapitre de webscraping la manière dont
Python
communique avec internet: via le packagerequests
. Ce package suit le protocole HTTP où on retrouve principalement deux types de requêtes:GET
etPOST
:GET
est utilisée pour récupérer des données depuis un serveur web. C’est la méthode la plus simple et courante pour accéder aux ressources d’une page web. Nous allons commencer par décrire celle-ci.POST
est utilisée pour envoyer des données au serveur, souvent dans le but de créer ou de mettre à jour une ressource. Sur les pages web, elle sert souvent à la soumission de formulaires qui nécessitent de mettre à jour des informations sur une base (mot de passe, informations clients, etc.). Nous verrons son utilité plus tard, lorsque nous commencerons à rentrer dans les requêtes authentifiées où il faudra soumettre des informations supplémentaires à notre requête.Faisons un premier test avec
Python
en faisant comme si nous connaissions bien cette API.Qu’est-ce qu’on obtient ? Un code HTTP. Le code 200 correspond aux requêtes réussies, c’est-à-dire pour lesquelles le serveur est en mesure de répondre. Si ce n’est pas le cas, pour une raison x ou y, vous aurez un code différent.
Les codes de statut HTTP sont des réponses standard envoyées par les serveurs web pour indiquer le résultat d’une requête effectuée par un client (comme un navigateur ou un script Python). Ils sont classés en différentes catégories selon le premier chiffre du code :
Ceux à retenir sont : 200 (succès), 400 (requête mal structurée), 401 (authentification non réussie), 403 (accès interdit), 404 (ressource demandée n’existe pas), 503 (le serveur n’est pas en capacité de répondre)
Pour récupérer le contenu renvoyé par
requests
, il existe plusieurs méthodes. Quand on un JSON bien formatté, le plus simple est d’utiliser la méthodejson
qui transforme cela en dictionnaire :En l’occurrence, on voit que les données sont dans un JSON imbriqué. Il faut donc développer un peu de code pour récupérer les informations voulues dans celui-ci:
C’est là l’inconvénient principal de l’usage des API: le travail ex post sur les données renvoyées. Le code nécessaire est propre à chaque API puisque l’architecture du JSON dépend de chaque API.