L'extraction de données scientifiques à partir des interfaces web de la NASA nécessite la simulation de requêtes HTTP POST. Les modèles IRI2012 (ionosphère) et NRLMSISE00 (thermosphère) exposent des formulaires permettnat de générer des profils atmosphériques en fonction de paramètres spatio-temporels spécifiques tels que la date, l'heure, la latitude, la longitude et l'altitude.
Pour automtaiser la récupération de ces données sur de multiples plages de valeurs, il est nécessaire d'itérer sur les paramètres cibles et de soumettre les formulaires programmatiquement. L'approche technique repose sur la bibliothèque requests de Python. Afin d'optimiser les performances réseau et d'assurer la robustesse du script, l'implémentation utilise requests.Session pour le maintien des connexions TCP, le module pathlib pour une gestion sécurisée et multiplateforme des chemins de fichiers, ainsi qu'un mécanisme de reprise sur erreur (retry) borné.
Récupération des données du modèle IRI2012
Le premier script interagit avec l'interface du modèle IRI2012. Il est configuré pour extraire des paramètres tels que la densité électronique et les températures des particules (Ne, Tn, Ti, Te). Le code parcourt une plage définie pour un paramètre choisi (par exemple, la longitude) et sauvegarde la réponse brute du serveur dans un fichier texte.
import requests
import time
from pathlib import Path
def fetch_iri2012_data():
target_dimension = 'longitude'
api_endpoint = 'https://omniweb.gsfc.nasa.gov/cgi/vitmo/vitmo_model.cgi'
# Configuration du chemin de sortie avec pathlib
output_directory = Path(__file__).parent
output_filepath = output_directory / f"iri2012_raw_{target_dimension}.txt"
# Utilisation d'une session pour le pooling de connexions
http_session = requests.Session()
http_session.headers.update({
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
'Referer': 'https://omniweb.gsfc.nasa.gov/vitmo/iri2012_vitmo.html',
'Content-Type': 'application/x-www-form-urlencoded'
})
# Paramètres de base du formulaire POST
form_payload = {
'model': 'iri_2012',
'year': '2023',
'month': '12',
'day': '01',
'time_flag': '1',
'hour': '8',
'geo_flag': '0.',
'latitude': '50.',
'longitude': '40.',
'height': '100.',
'profile': '1',
'start': '100.',
'stop': '1000.',
'step': '50.',
'sun_n': '',
'ion_n': '',
'radio_f': '',
'format': '0',
'vars': ['17', '19', '20', '21'], # Ne, Tn, Ti, Te
'linestyle': 'solid'
}
# Dictionnaire des plages de valeurs itérables
dimension_ranges = {
'hour': range(0, 24),
'month': range(1, 13),
'latitude': range(-90, 91, 10),
'longitude': range(0, 360, 10)
}
with open(output_filepath, 'w', encoding='utf-8') as data_file:
for current_value in dimension_ranges[target_dimension]:
form_payload[target_dimension] = str(current_value)
data_file.write(f"\n#======== {target_dimension}: {current_value} ========\n")
max_retries = 3
attempt = 0
while attempt < max_retries:
try:
print(f"Requête en cours pour {target_dimension}={current_value} (Tentative {attempt + 1})")
response = http_session.post(api_endpoint, data=form_payload)
response.raise_for_status()
data_file.write(response.text)
break # Succès, sortie de la boucle de retry
except requests.exceptions.RequestException as network_error:
print(f"Erreur réseau détectée : {network_error}")
attempt += 1
time.sleep(2) # Pause avant la prochaine tentative
data_file.write(f"\n#-------- Fin {target_dimension}: {current_value} --------\n")
if __name__ == "__main__":
fetch_iri2012_data()
Récupération des données du modèle NRLMSISE00
Le second script s'adresse au modèle NRLMSISE00. La structure logique demeure identique, mais l'URL cible et les variables du formulaire (payload) sont modifiées pour extraire les concentrations de gaz neutres, notamment l'oxygène atomique (O), les molécules d'azote (N2) et d'oxygène (O2).
import requests
import time
from pathlib import Path
def fetch_nrlmsise_data():
target_dimension = 'latitude'
api_endpoint = 'https://ccmc.gsfc.nasa.gov/cgi-bin/modelweb/models/vitmo_model.cgi'
output_directory = Path(__file__).parent
output_filepath = output_directory / f"nrlmsise_raw_{target_dimension}.txt"
http_session = requests.Session()
http_session.headers.update({
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)',
'Referer': 'https://ccmc.gsfc.nasa.gov/modelweb/models/nrlmsise00.php',
'Content-Type': 'application/x-www-form-urlencoded'
})
form_payload = {
'model': 'nrlmsise',
'year': '2023',
'month': '12',
'day': '01',
'time_flag': '1',
'hour': '12',
'geo_flag': '0.',
'latitude': '60',
'longitude': '120',
'height': '100.',
'profile': '1',
'start': '60.',
'stop': '1000.',
'step': '10.',
'f10_7': '',
'f10_7_3': '',
'ap': '',
'format': '0',
'vars': ['08', '09', '10'], # O, N2, O2
'linestyle': 'solid'
}
dimension_ranges = {
'hour': range(0, 24),
'month': range(1, 13),
'latitude': range(-90, 91, 10),
'longitude': range(0, 360, 10)
}
with open(output_filepath, 'w', encoding='utf-8') as data_file:
for current_value in dimension_ranges[target_dimension]:
form_payload[target_dimension] = str(current_value)
data_file.write(f"\n#======== {target_dimension}: {current_value} ========\n")
max_retries = 3
attempt = 0
while attempt < max_retries:
try:
print(f"Requête en cours pour {target_dimension}={current_value} (Tentative {attempt + 1})")
response = http_session.post(api_endpoint, data=form_payload)
response.raise_for_status()
data_file.write(response.text)
break
except requests.exceptions.RequestException as network_error:
print(f"Erreur réseau détectée : {network_error}")
attempt += 1
time.sleep(2)
data_file.write(f"\n#-------- Fin {target_dimension}: {current_value} --------\n")
if __name__ == "__main__":
fetch_nrlmsise_data()