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

Terminale – Compétence | API (Application Programming Interface) 3/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 « Mars Rover Photos »

Contexte

Découvrir le site :

Obtention d’un jeton ou d’une clé (‘token’, ‘api_key’)

Pour cela il faut créer un compte à partir de cette adresse : https://api.nasa.gov/ et suivre les consignes données.
Le jeton utilisé ci-après n’a qu’une valeur indicative. Il n’est plus actif.

URL de l’API

Envoi d’une première requête

>>> from requests import request as requete

>>> methode = 'GET'

>>> url = "https://api.nasa.gov/mars-photos/api/v1/rovers/"

>>> rover = "curiosity"

>>> camera = "NAVCAM"

>>> sol = "10"

>>> page = "1"

>>> token = "plVirWytxjNQ8XTD92IEflveR85cXOUou2NtXx"

>>> r1 = requete(methode,url+rover+"/photos?"+"sol="+sol+"&page="+page+"&camera="+camera+"&api_key="+token)

>>> r1
<Response [200]>

Examen et traitement de la réponse

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

>>> dir(r1)
['__attrs__', '__bool__', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__enter__', '__eq__', '__exit__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__nonzero__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setstate__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_content', '_content_consumed', '_next', 'apparent_encoding', 'close', 'connection', 'content', 'cookies', 'elapsed', 'encoding', 'headers', 'history', 'is_permanent_redirect', 'is_redirect', 'iter_content', 'iter_lines', 'json', 'links', 'next', 'ok', 'raise_for_status', 'raw', 'reason', 'request', 'status_code', 'text', 'url']

>>> r1.status_code
200

>>> r1.url
'https://api.nasa.gov/mars-photos/api/v1/rovers/curiosity/photos?sol=10&page=1&camera=NAVCAM&api_key=plVirWytxjNQ8XTD92IEflveR85cXOUou2NtXx'

>>> r1.text
'{"photos":[{"id":2095,"sol":10,"camera":{"id":26,"name":"NAVCAM","rover_id":5,"
full_name":"Navigation Camera"},"img_src":"http://mars.jpl.nasa.gov/msl-raw-imag
es/proj/msl/redops/ods/surface/sol/00010/opgs/edr/ncam/NLA_398380694EDR_F0030000
NCAM15000M_.JPG","earth_date":"2012-08-16","rover":{"id":5,"name":"Curiosity","l
anding_date":"2012-08-06","launch_date":"2011-11-26","status":"active"}},{"id":2
672,"sol":10,"camera":{"id":26,"name":"NAVCAM","rover_id":5,"full_name":"Navigat
ion Camera"},"img_src":"http://mars.jpl.nasa.gov/msl-raw-images/proj/msl/redops/
ods/surface/sol/00010/opgs/edr/ncam/NRA_398380694EDR_F0030000NCAM15000M_.JPG","e
arth_date":"2012-08-16","rover":{"id":5,"name":"Curiosity","landing_date":"2012-
08-06","launch_date":"2011-11-26","status":"active"}},{"id":32406,"sol":10,"came
ra":{"id":26,"name":"NAVCAM","rover_id":5,"full_name":"Navigation Camera"},"img_
src":"http://mars.jpl.nasa.gov/msl-raw-images/proj/msl/redops/ods/surface/sol/00
010/opgs/edr/ncam/NLA_398381736EDR_F0030000NCAM15000M_.JPG","earth_date":"2012-0
8-16","rover":{"id":5,"name":"Curiosity","landing_date":"2012-08-06","launch_dat
e":"2011-11-26","status":"active"}},{"id":49166,"sol":10,"camera":{"id":26,"name
":"NAVCAM","rover_id":5,"full_name":"Navigation Camera"},"img_src":"http://mars.
jpl.nasa.gov/msl-raw-images/proj/msl/redops/ods/surface/sol/00010/opgs/edr/ncam/
NRA_398381736EDR_F0030000NCAM15000M_.JPG","earth_date":"2012-08-16","rover":{"id
":5,"name":"Curiosity","landing_date":"2012-08-06","launch_date":"2011-11-26","s
tatus":"active"}}]}'

>>> type(r1.text)
<class 'str'>

La réponse au format « chaîne de caractères » est difficilement exploitable.

D’où :

>>> r1json = r1.json()

>>> r1json
{'photos': [{'id': 2095, 'sol': 10, 'camera': {'id': 26, 'name': 'NAVCAM', 'rove
r_id': 5, 'full_name': 'Navigation Camera'}, 'img_src': 'http://mars.jpl.nasa.go
v/msl-raw-images/proj/msl/redops/ods/surface/sol/00010/opgs/edr/ncam/NLA_3983806
94EDR_F0030000NCAM15000M_.JPG', 'earth_date': '2012-08-16', 'rover': {'id': 5, '
name': 'Curiosity', 'landing_date': '2012-08-06', 'launch_date': '2011-11-26', '
status': 'active'}}, {'id': 2672, 'sol': 10, 'camera': {'id': 26, 'name': 'NAVCA
M', 'rover_id': 5, 'full_name': 'Navigation Camera'}, 'img_src': 'http://mars.jp
l.nasa.gov/msl-raw-images/proj/msl/redops/ods/surface/sol/00010/opgs/edr/ncam/NR
A_398380694EDR_F0030000NCAM15000M_.JPG', 'earth_date': '2012-08-16', 'rover': {'
id': 5, 'name': 'Curiosity', 'landing_date': '2012-08-06', 'launch_date': '2011-
11-26', 'status': 'active'}}, {'id': 32406, 'sol': 10, 'camera': {'id': 26, 'nam
e': 'NAVCAM', 'rover_id': 5, 'full_name': 'Navigation Camera'}, 'img_src': 'http
://mars.jpl.nasa.gov/msl-raw-images/proj/msl/redops/ods/surface/sol/00010/opgs/e
dr/ncam/NLA_398381736EDR_F0030000NCAM15000M_.JPG', 'earth_date': '2012-08-16', '
rover': {'id': 5, 'name': 'Curiosity', 'landing_date': '2012-08-06', 'launch_dat
e': '2011-11-26', 'status': 'active'}}, {'id': 49166, 'sol': 10, 'camera': {'id'
: 26, 'name': 'NAVCAM', 'rover_id': 5, 'full_name': 'Navigation Camera'}, 'img_s
rc': 'http://mars.jpl.nasa.gov/msl-raw-images/proj/msl/redops/ods/surface/sol/00
010/opgs/edr/ncam/NRA_398381736EDR_F0030000NCAM15000M_.JPG', 'earth_date': '2012
-08-16', 'rover': {'id': 5, 'name': 'Curiosity', 'landing_date': '2012-08-06', '
launch_date': '2011-11-26', 'status': 'active'}}]}

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

>>> len(r1json)
1

>>> r1json.keys()
dict_keys(['photos'])

>>> type(r1json['photos'])
<class 'list'>

>>> len(r1json['photos'])
4

>>> type(r1json['photos'][0])
<class 'dict'>

>>> r1json['photos'][0].keys()
dict_keys(['id', 'sol', 'camera', 'img_src', 'earth_date', 'rover'])

>>> r1json['photos'][0]['img_src']
'http://mars.jpl.nasa.gov/msl-raw-images/proj/msl/redops/ods/surface/sol/00010/opgs/edr/ncam/NLA_398380694EDR_F0030000NCAM15000M_.JPG'

Il s’agit de l’image suivante :

http://mars.jpl.nasa.gov/msl-raw-images/proj/msl/redops/ods/surface/sol/00010/opgs/edr/ncam/NLA_398380694EDR_F0030000NCAM15000M_.JPG

Accès au ‘manifest’ de chaque mission

Pour chacune des missions – Curiosity, Opportunity et Spirit – il est possible d’accéder – via une requête – à une documentation (‘manifest’) qui permet d’affiner les valeurs des paramètres à utiliser dans les requêtes de recherche de photographies.

>>> from requests import request as requete

>>> methode = 'GET'

>>> token = "plVirWytxjNQ8XTD92IEflveR85cXOUou2NtXxHR"

>>> rover = 'curiosity'

>>> url = "https://api.nasa.gov/mars-photos/api/v1/manifests/"

>>> r2 = requete(methode,url+rover+"?api_key="+token)

>>> r2
<Response [200]>

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

>>> dir(r2)
['__attrs__', '__bool__', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__enter__', '__eq__', '__exit__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__nonzero__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setstate__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_content', '_content_consumed', '_next', 'apparent_encoding', 'close', 'connection', 'content', 'cookies', 'elapsed', 'encoding', 'headers', 'history', 'is_permanent_redirect', 'is_redirect', 'iter_content', 'iter_lines', 'json', 'links', 'next', 'ok', 'raise_for_status', 'raw', 'reason', 'request', 'status_code', 'text', 'url']

>>> r2json=r2.json()

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

>>> len(r2json)
1

>>> r2json.keys()
dict_keys(['photo_manifest'])

>>> type(r2json['photo_manifest'])
<class 'dict'>

>>> len(r2json['photo_manifest'])
8

>>> r2json['photo_manifest'].keys()
dict_keys(['name', 'landing_date', 'launch_date', 'status', 'max_sol', 'max_date', 'total_photos', 'photos'])

>>> r2json['photo_manifest']['max_sol']
3385

>>> r2json['photo_manifest']['total_photos']
547114

>>> type(r2json['photo_manifest']['photos'])
<class 'list'>

>>> len(r2json['photo_manifest']['photos'])
3079

>>> type(r2json['photo_manifest']['photos'][0])
<class 'dict'>

>>> r2json['photo_manifest']['photos'][0].keys()
dict_keys(['sol', 'earth_date', 'total_photos', 'cameras'])

>>> r2json['photo_manifest']['photos'][0]['sol']
0

>>> r2json['photo_manifest']['photos'][0]['earth_date']
'2012-08-06'

>>> r2json['photo_manifest']['photos'][0]['total_photos']
3702

>>> r2json['photo_manifest']['photos'][0]['cameras']
['CHEMCAM', 'FHAZ', 'MARDI', 'RHAZ']

Nous apprenons ainsi que la mission ‘Curiosity’ :

  • a décollé de Terre le 26-11-2011 (‘launch_date’)
  • s’est posé sur Mars le 06-08-2012 (‘landing_date’)
  • est toujours en activité (‘status’)
  • que les dernières photographies ont été prises le :
    • 3 385e jour martien après que le rover se soit posé (‘max_sol’)
    • soit le 13-02-2022 (‘max_date’)
  • et que le rover a pris au total 547 114 photographies (‘total_photos’)
Pour en savoir plus sur la mesure du temps sur Mars…

Idées de projets…

P1 - Ecrire un programme en Python qui permet :
- de choisir l'une des trois missions Opportunity, Curiosity et Spirit
- de choisir un langue d'affichage 'fr', 'en', 'es' ou 'de'
- d'afficher dans la langue choisie
--- en titre, le nom de la mission choisie
--- la nature des informations fournies ('manifest')
--- les données 'landing_date', 'launch_date', 'status', 'max_sol', 'max_date' et 'total_photos' sous la forme d'un tableau
- d'afficher dans la langue choisie
--- les données 'sol', 'earth_date', 'total_photos' et 'cameras' du dernier élément de l'entrée 'photos' du 'manifest', sous la forme d'un tableau.
P2 - Ecrire un programme en Python qui permet :
- de récupérer le 'manifest' des trois missions Opportunity, Curiosity et Spirit
- de convertir et de sauvegarder toutes les données 'sol', 'earth_date', 'total_photos' et 'cameras' de tous les éléments de l'entrée 'photos' du 'manifest', sous la forme d'un fichier 'csv'.
P3 - Ecrire un programme en Python qui permet :
- de choisir l'une des trois missions Opportunity, Curiosity et Spirit
- de choisir l'une des caméras du rover (en fonction de la mission choisie)
- de choisir une date dans le calendrier de la Terre comprise entre celle du début de la mission et celle des dernières photographies prises par la mission choisie
- d'exécuter une requête permettant de récupérer les données d'une seule page de résultats
- d'afficher la liste des photographies disponibles
- de choisir l'une de ces photos
- de télécharger et d'afficher dans une fenêtre la photo choisie.