N.S.I. WorkSpace Compétence,T-Th-D3,Terminale Terminale – Compétence | API (Application Programming Interface) 4/4

Terminale – Compétence | API (Application Programming Interface) 4/4

Interroger un serveur via une API

La démarche est la suivante :

  • envoyer une requête HTTP à un serveur Web depuis la console Python (Client) ;
  • à partir des données fournies dans la requête HTTP, une API du serveur Web va générer une requête SQL pour interroger une base de données ;
  • la réponse SQL parvient à l’API qui formate les données de cette réponse ;
  • ces données formatées sont transmises dans une réponse HTTP à la console Python (Client)

Utilisation du module « Requests » de Python

La fonction ‘request’ du module Requests permet d’envoyer des requêtes HTTP.

>>> from requests import request as requete

Les paramètres d’une requête

>>> help(requete)
Help on function request in module requests.api:

request(method, url, **kwargs)
    Constructs and sends a :class:`Request <Request>`.

…/…

    Usage::
    
      >>> import requests
      >>> req = requests.request('GET', 'https://httpbin.org/get')
      <Response [200]>

Les deux paramètres requis pour l’envoi d’une requête sont :

  • une méthode du protocole HTTP. Nous utiliserons la méthode ‘GET’ ;
  • l’url de l’API

Pour en savoir plus sur **kwargs …

Envoi d’une requête à l’API de « Datas Angers » pour le ‘dataset’ intitulé ‘Prénoms des enfants nés à Angers’

Contexte

Découvrir le site : https://data.angers.fr/

URL de l’API permettant de faire de l’extraction d’enregistrements

https://data.angers.fr/api/v2/catalog/datasets/prenoms-des-enfants-nes-a-angers/records?

Envoi d’une première requête

>>> from requests import request as requete

>>> methode = 'GET'

>>> api_url = "https://data.angers.fr/api/v2/catalog/datasets/prenoms-des-enfants-nes-a-angers/records"

>>> reponse = requete(methode, api_url)

>>> type(reponse)
<class 'requests.models.Response'>

>>> repjson = reponse.json()

>>> type(repjson)
<class 'dict'>

>>> len(repjson)
3

>>> repjson.keys()
dict_keys(['total_count', 'links', 'records'])

>>> repjson['total_count']
2850

Nous apprenons ainsi qu’il y a 2850 enregistrements disponibles dans le ‘dataset’.

Examinons le contenu de la réponse plus en détails.

>>> type(repjson['records'])
<class 'list'>

>>> len(repjson['records'])
10

>>> type(repjson['records'][0])
<class 'dict'>

>>> repjson['records'][0].keys()
dict_keys(['links', 'record'])

>>> type(repjson['records'][0]['record'])
<class 'dict'>

>>> repjson['records'][0]['record'].keys()
dict_keys(['id', 'timestamp', 'size', 'fields'])

>>> type(repjson['records'][0]['record']['fields'])
<class 'dict'>

>>> repjson['records'][0]['record']['fields'].keys()
dict_keys(['commune_nom', 'coll_insee', 'enfant_sexe', 'enfant_prenom', 'nombre_occurrences', 'annee'])

>>> repjson['records'][0]['record']['fields']
{'commune_nom': 'ANGERS', 'coll_insee': '49007', 'enfant_sexe': 'F', 'enfant_prenom': 'Alice', 'nombre_occurrences': 22, 'annee': 2013}

Cet examen nous apprend que :

  • seulement 10 enregistrements ont été récupérés.
  • les données ‘exploitables’ ne constituent qu’une partie des informations recueillies

Poursuivons nos investigations :

>>> type(repjson['links'])
<class 'list'>

>>> len(repjson['links'])
4

>>> type(repjson['links'][0])
<class 'dict'>

>>> repjson['links'][0].keys()
dict_keys(['rel', 'href'])

>>> repjson['links'][0]
{'rel': 'self', 'href': 'https://data.angers.fr/api/v2/catalog/datasets/prenoms-des-enfants-nes-a-angers/records?limit=10&offset=0'}

>>> repjson['links'][1]
{'rel': 'first', 'href': 'https://data.angers.fr/api/v2/catalog/datasets/prenoms-des-enfants-nes-a-angers/records?limit=10&offset=0'}

>>> repjson['links'][2]
{'rel': 'last', 'href': 'https://data.angers.fr/api/v2/catalog/datasets/prenoms-des-enfants-nes-a-angers/records?limit=10&offset=2840'}

>>> repjson['links'][3]
{'rel': 'next', 'href': 'https://data.angers.fr/api/v2/catalog/datasets/prenoms-des-enfants-nes-a-angers/records?limit=10&offset=10'}

On s’aperçoit que :

  • seuls les dix premiers enregistrements ont été transmis
    • repjson[‘links’][0] >>> ‘rel’: ‘self‘, …/… limit=10&offset=0
    • repjson[‘links’][1] >>> ‘rel’: ‘first‘, …/… limit=10&offset=0
  • des couples ‘parametre=valeur’ ont été ajoutés – par defaut – à l’URL de l’API, constituant ainsi une requête ‘HTTP’ basée sur la méthode ‘GET’.

Une API qui utilise ‘Opendatasoft Query Language (ODSQL)’

Une documentation est accessible ici : https://help.opendatasoft.com/

Il est possible d’écrire une requête avec les clauses ‘select’, ‘where’, ‘group_by’, ‘order_by’ et ‘limit’ similaires à celles du langage SQL.

Testons :

from requests import request as requete

def clause_formatage(clause):
    clause.replace("=", "%3D")
    clause.replace(" ", "%20")
    clause.replace("'", "%27")
    clause.replace('"', "%27")
    clause.replace(',', "%2C")
    clause.replace('/', "%2F")
    return clause

methode = 'GET'

api_url = 'https://data.angers.fr/api/v2/catalog/datasets/prenoms-des-enfants-nes-a-angers/records'

clause_select = "enfant_prenom, nombre_occurrences"
clause_select = clause_formatage(clause_select)
clause_select = "select=" + clause_select

clause_where = "annee=2013 AND enfant_sexe='F'"
clause_where = clause_formatage(clause_where)
clause_where = "&where=" + clause_where

clause_orderby = "nombre_occurrences desc"
clause_orderby = clause_formatage(clause_orderby)
clause_orderby = "&order_by=" + clause_orderby

clause_limit = "&limit=5"
clause_offset ="&offset=0"

requeteGet = api_url+"?"+clause_select+clause_where+clause_orderby+clause_limit+clause_offset
requeteGet += clause_formatage("&lang=fr&timezone=Europe/Paris")

reponse = requete(methode, requeteGet )

repjson = reponse.json()
top = len(repjson['records'])

print("*" * 45)

titre = "TOP " + str(top) + " des prénoms"
espace = (45 - len(titre)) // 2
titre = " " * espace + titre
print(titre)

titre = "donnés aux filles nées à Angers en 2013"
espace = (45 - len(titre)) // 2
titre = " " * espace + titre
print(titre)

print("*" * 45)
print()
for compt in range(top):
    prenom = repjson['records'][compt]['record']['fields']['enfant_prenom']
    prenom = prenom + " " + "." * (20 - len(prenom))
    score = " " + str(repjson['records'][compt]['record']['fields']['nombre_occurrences'])
    print(prenom + score)

Résultat obtenu dans la console :

*********************************************
              TOP 5 des prénoms
   donnés aux filles nées à Angers en 2013
*********************************************

Jade ................ 43
Manon ............... 41
Louise .............. 41
Chloé ............... 40
Inès ................ 36

Extraction de données et sauvegarde de ces données dans un fichier au format ‘csv’

L’API permet d’extraire des données et de les récupérer sous la forme d’une chaîne de caractères directement sauvegardable au format ‘json’ ou ‘csv’. Testons avec le format ‘csv’.

Dans un éditeur Python saisir le programme qui suit et l’exécuter.

# *****************************************************************************
#            TELECHARGEMENT ET SAUVEGARDE DE DONNEES AU FORMAT 'CSV'
# *****************************************************************************

from requests import request as requete

# requête
api_url = "https://data.angers.fr/api/v2/catalog/datasets/prenoms-des-enfants-nes-a-angers/"
api_action = "exports/"
api_format = "csv"

clause_select = "?select=enfant_prenom%2C%20nombre_occurrences"
clause_where = "&where=annee%3D2013%20and%20enfant_sexe%3D%27F%27"
clause_limit = "&limit=5&offset=0"
clause_supplem = "&lang=fr&timezone=Europe%2FParis"

req = clause_select + clause_where + clause_limit + clause_supplem

req = api_url + api_action + api_format + req

export = requete('GET', req)
export_txt = export.text
print(export_txt)

""" option :
export_txt = export_txt.replace(";", ",")
print(export_txt)
"""

export_file_name = "top-5_prenoms-F_annee-2013.csv"

fichier_csv = open(export_file_name, 'w', encoding='UTF-8', newline='')
fichier_csv.write(export_txt)
fichier_csv.close()

Idées de projets…

P1 - Écrire un programme en Python qui permet :
- de saisir et d'affecter son propre prénom à une variable ;
- d'effectuer une recherche du nombre d'occurrences de son prénom pour toutes les années disponibles dans le 'dataset' ;
- d'afficher le résultat de cette recherche sous une forme structurée.
P2 - Écrire un programme en Python qui permet :
- de saisir et d'affecter à une variable une chaine de un à trois caractères maximum correspondant aux lettres du début d'un prénom ;
- d'effectuer une recherche de tous les prénoms commençant par la chaîne de caractères choisie pour toutes les années disponibles dans le 'dataset' ;
- d'afficher le résultat de cette recherche sous une forme structurée.
P3 - Écrire un programme en Python qui permet :
- d'effectuer une recherche du 'top 10' des prénoms des garçons et des filles pour toutes les années disponibles dans le 'dataset' ;
- de calculer en pourcentage ce que représente le nombre d'occurrences de chacun de ces prénoms par rapport au nombre total de prénoms par année et par sexe ;
- d'afficher le résultat de cette recherche sous une forme structurée.
P4 - Écrire un programme en Python qui permet :
- d'effectuer une recherche du 'top 3' des prénoms les plus courts et les plus longs, par année et par sexe ;
- d'afficher le résultat de cette recherche sous une forme structurée.