import requests
import pandas as pd
import time
from datetime import datetimeSegunda parte (Python): API APOD de la NASA
Instrucciones
- Usarán la API de la NASA llamada APOD (Astronomy Picture of the Day). Busca su documentación en https://api.nasa.gov/
- Genera una API key en el sitio https://api.nasa.gov/
- Cada miembro del equipo debe seleccionar la palabra correspondiente al número de la primera letra de tu apellido paterno. Por ejemplo, 1 = A, 2 = B, 3 = C, etc. Si tu apellido empieza con Ñ, selecciona la última palabra de la lista. Si la palabra coincide con la de algunos miembro de tu equipo, toma la inmediata posterior.
- gravitational
- retrograde
- supernova
- spiral
- James Webb
- emission
- nebula
- planetary
- Juno
- X-ray
- black hole
- infrared
- dust clouds
- aurora borealis
- Northern Lights
- geomagnetic storm
- Perseids
- Geminids
- Einstein
- elliptical
- Newton
- Spitzer
- Kepler
- Apollo
- Voyager
- Redshift
- Hand of God
- Hydrogen
- alpha
- Sulfur
- Cuidado: La API se puede sentir “atacada” y bloquearte si haces muchas solicitudes rápidamente.
- Cuidado: La API sólo permite un número finito de solicitudes.
Basándose en solicitudes de la API en el campo “explanation” haz búsquedas basadas en tu palabra y responde la siguientes preguntas:
Preguntas del equipo:
- ¿Qué tipo de parámetros admite la solicitud?
- ¿Qué tipo respuestas se pueden obtener con cada solicitud?
- ¿Qué tipo de restricciones tiene la API?
Preguntas de cada miembro del equipo:
- Para las búsquedas de tu palabra, ¿cuántos resultados obtuviste?
- Para las búsquedas de tu palabra, ¿en qué rangos de fechas se introdujo el recurso?
- Para las búsquedas de tu palabra, ¿cuáles son los “media_type” más comunes?
- Para las búsquedas de tu palabra, ¿quiénes son los autores o instituciones propietaria de los derechos (i.e. el copyright)?
Preguntas del equipo
1. ¿Qué tipo de parámetros admite la solicitud?
La API APOD de la NASA admite los siguientes parámetros en las solicitudes:
api_key(string) - La clave generada para uso ampliado. Por defecto esDEMO_KEY.date(string) - Una cadena en formato YYYY-MM-DD que indica la fecha de la imagen APOD a recuperar. Debe ser posterior al 16 de junio de 1995 (1995-06-16), fecha en que se publicó por primera vez una imagen de APOD. No hay imágenes disponibles para mañana a través de esta API. Por defecto es la fecha de hoy.start_date(string) - Una cadena en formato YYYY-MM-DD que indica el inicio de un rango de fechas. Todas las imágenes comprendidas entrestart_dateyend_datese devolverán en un JSON array. No se puede usar condate. El valor por defecto esNone.end_date(string) - Una cadena en formato YYYY-MM-DD que indica el final de un rango de fechas. Si se especificastart_datesinend_date,end_datetoma por defecto la fecha actual.count(int) - Un número entero positivo, no mayor que 100. Si se especifica, se devolverá la cantidad de imágenes elegidas aleatoriamente en un JSON array. No se puede usar junto condateni constart_dateyend_date. El valor por defecto esNone.thumbs(bool) - Un booleanoTrue|Falseque indica si la API debe devolver la URL de la imagen en miniatura para los archivos de video. Si se establece enTrue, la API devuelve la URL de la miniatura del video. Si un APOD no es un video, este parámetro se ignora. El valor por defecto esFalse.hd(bool) - Un booleanoTrue|Falseque indica si se deben devolver imágenes de alta resolución. Este parámetro se incluye por motivos de compatibilidad con versiones anteriores; el servicio siempre lo ignora y, en cualquier caso, se devuelven las URL de alta resolución.concept_tags(bool) - Un booleanoTrue|Falseque indica si las etiquetas de concepto deben incluirse en la respuesta. Estas etiquetas no necesariamente se incluyen en la explicación, sino que se derivan de etiquetas de búsqueda comunes asociadas al texto de la descripción. (Mejor que una simple búsqueda de texto). El valor por defecto esFalse. Por ahora, este parámetro está deshabilitado en este servicio.
2. ¿Qué tipo respuestas se pueden obtener con cada solicitud?
La estructura de la respuesta depende de los parámetros utilizados en cada solicitud:
- Si solicitas la imagen de hoy o una fecha específica con
date, la API devolverá un único objeto JSON (un diccionario en Python). - Si solicitas todas las imágenes comprendidas en un rango de fechas con
start_dateyend_date, la API devolverá una lista de objetos JSON, uno por cada día del periodo solicitado. - Si solicitas un número de imágenes seleccionadas al azar con
count, la API devolverá una lista de objetos JSON, uno por cada día seleccionado al azar.
Cada objeto JSON contiene metadatos sobre la Astronomy Picture of the Day (APOD) del día especificado.
Los campos principales del objeto JSON son los siguientes:
title- El título de la imagen.date- Fecha de la imagen.url- La URL de la imagen o el video APOD del día.explanation- El texto que explica la imagen.hdurl- La URL de la imagen del día en alta resolución.media_type- El tipo de medio (datos) devuelto. Puede serimageovideosegún el contenido.service_version- Versión del servicio utilizada.
Opcionales:
copyright- Nombre del titular de los derechos de autor. Sólo se devuelve si la imagen no es de dominio público.thumbnail_url- La URL de la miniatura del vídeo. Sólo se devuelve si el tipo de medio es un video y sithumbs = True
No disponibles en este servicio:
resourceconcept_tagsconcepts
Además, la API devuelve un código de estado que indica si la solicitud fue exitosa o no, los más comunes son:
- 200 OK: La solicitud fue exitosa y el servidor devolvió lo que se solicitó.
- 400 Bad Request (Solicitud incorrecta): La solicitud estaba mal formada y el servidor no pudo entenderla. Ocurre cuando hay un error en los parámetros.
- 403 Forbidden (Prohibido): La solicitud está prohibida y el cliente no está autorizado para acceder al recurso. Ocurre si se proporcionó una API Key no válida.
- 404 Not Found (No encontrado): El recurso solicitado no existe (por ejemplo, no hay datos disponibles para la fecha de mañana).
- 429 Too Many Requests (Demasiadas solicitudes): Superaste el límite de solicitudes (Over Rate Limit). En este caso, ocurre al superar las 1,000 solicitudes por hora con la API key.
- 500 Internal Server Error (Error interno del servidor): Ocurrió un error inesperado en el servidor de la NASA.
- 503 Service Unavailable (Servicio No disponible): Indica que el servidor web está temporalmente inhabilitado para procesar solicitudes, generalmente por sobrecarga o mantenimiento.
3. ¿Qué tipo de restricciones tiene la API?
La API tiene límites establecidos en la cantidad de solicitudes que puedes realizar:
- Utilizando una API key propia, el límite es de 1000 solicitudes por hora. Si excedes este límite, tu API key será bloqueada temporalmente y no podrás realizar más solicitudes. El bloqueo se levantará automáticamente tras una hora.
- Utilizando la DEMO_KEY, el límite de uso es de 30 solicitudes por dirección IP por hora con un máximo de 50 solicitudes por dirección IP al día.
Tiene restricciones con las fechas que puedes solicitar:
- No puedes solicitar información anterior al 16 de junio de 1995, fecha en la que inició el servicio APOD.
- Tampoco puedes solicitar información de fechas futuras como “mañana”, la API solo responde con datos hasta la fecha de hoy.
Tiene restricciones con las combinaciones de parámetros que puedes realizar en una solicitud:
- Si usas el parámetro
date(para obtener una imagen específica), no puedes usarcount,start_dateniend_date. - Si usas el parámetro
count(para obtener imágenes al azar), no puedes usardate,start_dateniend_date. - Si usas los parámetros
start_dateyend_date(para obtener todas las imágenes en un rango de fechas), no puedes usardatenicount. - No puedes usar el parámetro
end_datesin usarstart_date.
Tiene restricciones con el tamaño de las solicitudes y la frecuencia de las mismas:
- Si el rango de fechas en la solicitud es demasiado grande, la respuesta podría fallar por tiempo de espera.
- Si realizas muchas solicitudes simultáneas se podría saturar el servicio y provocar un error en la respuesta.
Datos
Usaremos la API de la NASA llamada APOD (Astronomy Picture of the Day).
Documentación en https://api.nasa.gov/
Cargar librerías
Guarda tu API key generada en el sitio https://api.nasa.gov/
Vamos a cargar la API key desde el archivo .env:
from dotenv import load_dotenv
import os
load_dotenv()True
mi_api_key = os.getenv("NASA_API_KEY")Para empezar, veamos como realizar una solicitud simple a la API APOD de la NASA.
# Establecer API key y URL para la solicitud
api_key = mi_api_key
url = 'https://api.nasa.gov/planetary/apod'
# Establecer fechas para realizar la solicitud
start_date = '2026-03-16'
end_date = '2026-04-16'
# Establecer los parámetros de la solicitud
obs_params = {
'api_key': api_key,
'start_date': start_date,
'end_date': end_date
}
response = requests.get(url, params = obs_params)Revisemos la respuesta recibida.
response<Response [200]>
Tipo de respuesta 200 significa éxito.
Guardar los registros en un DataFrame mi_df
mi_data = response.json()
mi_df = pd.DataFrame(mi_data)Explorar el Dataframe mi_df
mi_df.info()<class 'pandas.core.frame.DataFrame'>
RangeIndex: 32 entries, 0 to 31
Data columns (total 8 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 date 32 non-null object
1 explanation 32 non-null object
2 hdurl 28 non-null object
3 media_type 32 non-null object
4 service_version 32 non-null object
5 title 32 non-null object
6 url 32 non-null object
7 copyright 19 non-null object
dtypes: object(8)
memory usage: 2.1+ KB
Imprimimos el dataframe desde R para poder explorarlo más fácilmente:
py$mi_dfListo, hemos realizado una solicitud exitosa.
Cargar la base api_pod_data.csv
Para fines de practicidad y evitar tener que descargar todos los registros de la API APOD en cada ejecución del script, hemos tomado la decisión de descargar todos los registros comprendidos desde el 16 de junio de 1995 (primer registro de la API) hasta el 16 de mayo de 2026. La base se ha guardado en un archivo csv llamado api_apod_data.csv.
# Para leer y guardar el csv en un nuevo DataFrame
df_apod = pd.read_csv('../datos/api_apod_data.csv', sep=';')# Rango de fechas del CSV
print(df_apod['date'].min())1995-06-16
print(df_apod['date'].max())2026-05-16
df_apod.info()<class 'pandas.core.frame.DataFrame'>
RangeIndex: 11288 entries, 0 to 11287
Data columns (total 8 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 date 11288 non-null object
1 explanation 11272 non-null object
2 hdurl 10862 non-null object
3 media_type 11288 non-null object
4 service_version 11288 non-null object
5 title 11288 non-null object
6 url 11263 non-null object
7 copyright 5564 non-null object
dtypes: object(8)
memory usage: 705.6+ KB
# Imprimimos con R
py$df_apod