Consultar bases de datos biológicas mediante la API
Al finalizar este tema
Podrás llamar a las API de NCBI y UniProt con la biblioteca Python requests, extraer los datos necesarios de la respuesta JSON y consultar varios genes mediante un bucle.
¿Qué es una API?
Probablemente hayas buscado genes en el sitio web de NCBI. Si introduces "EGFR" en la barra de búsqueda, aparecerá una página con información sobre el gen. En este caso, el navegador envía una solicitud al servidor de NCBI y el servidor envía una respuesta.
Una API (Interfaz de programación de aplicaciones) es simplemente la forma de hacer esto mediante código. En lugar de un navegador, Python envía la solicitud y, en lugar de HTML, recibe una respuesta en forma de datos estructurados (JSON).
Si lo comparamos con un equipo de laboratorio, es como introducir una muestra y pulsar un botón para obtener un resultado. Con una API, introduces el nombre de un gen y obtienes información. La diferencia es que, en lugar de que una persona pulse el botón, el código lo hace automáticamente.
La biblioteca requests
pip install requestsimport requests
response = requests.get("https://api.github.com")print(f"Código de estado: {response.status_code}")print(f"Datos de respuesta: {response.json()}")requests.get(URL) — Se envía una solicitud GET a la URL especificada. Es lo mismo que escribir la URL en un navegador web.
Códigos de estado:
- 200 — Éxito
- 404 — URL no encontrada
- 429 — Demasiadas solicitudes (límite de frecuencia)
- 500 — Error interno del servidor
JSON: Formato de respuesta de la API
La API responde principalmente en formato JSON. Tiene una estructura muy similar a un diccionario de Python:
{
"gene": "EGFR",
"organism": "Homo sapiens",
"chromosome": "7",
"aliases": ["ERBB1", "HER1"]
}Cómo manejar las respuestas JSON en Python:
import requests
response = requests.get("https://rest.uniprot.org/uniprotkb/P04637.json")data = response.json()
print(f"Protein: {data['proteinDescription']['recommendedName']['fullName']['value']}")print(f"Organism: {data['organism']['scientificName']}")print(f"Sequence length: {data['sequence']['length']}")response.json() — Convierte la respuesta JSON en un diccionario de Python. A continuación, extrae los valores deseados con data["key"].
En la práctica: Obtención de información de proteínas mediante la API de UniProt.
import requests
def get_protein_info(uniprot_id: str) -> dict: url = f"https://rest.uniprot.org/uniprotkb/{uniprot_id}.json" response = requests.get(url)
if response.status_code != 200: print(f"Error: {uniprot_id} — código de estado {response.status_code}") return {}
data = response.json() return { "id": uniprot_id, "name": data["proteinDescription"]["recommendedName"]["fullName"]["value"], "organism": data["organism"]["scientificName"], "length": data["sequence"]["length"], }
info = get_protein_info("P04637")print(info)Si se crea como una función, se pueden consultar varias proteínas mediante un bucle:
ids = ["P04637", "P00533", "P38398"]results = []
for uid in ids: info = get_protein_info(uid) if info: results.append(info) print(f" ✓ {info['name']} ({info['length']} aa)")
print(f"\nConsulta completada: {len(results)} resultados en total")Práctica: NCBI E-utilities
NCBI ofrece una API llamada E-utilities. Con ella, se pueden realizar búsquedas de genes, descargar secuencias, buscar artículos, etc., mediante código.
import requests
gene_name = "BRCA1"url = "https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi"params = { "db": "gene", "term": f"{gene_name}[Gene Name] AND Homo sapiens[Organism]", "retmode": "json",}
response = requests.get(url, params=params)data = response.json()
gene_ids = data["esearchresult"]["idlist"]print(f"Resultados de búsqueda de {gene_name}: {gene_ids}")params — Se pasan los parámetros de la URL como un diccionario. requests añade automáticamente ?db=gene&term=... a la URL.
Buenas prácticas al llamar a la API: Limitación de frecuencia
La API no se puede llamar de forma ilimitada. Para evitar sobrecargar el servidor, se debe mantener un intervalo entre solicitudes:
import timeimport requests
ids = ["P04637", "P00533", "P38398", "Q13315", "P42336"]
for uid in ids: info = get_protein_info(uid) if info: print(f" {info['name']}") time.sleep(0.5)time.sleep(0.5) — Espere 0,5 segundos. NCBI recomienda aproximadamente 3 solicitudes por segundo y UniProt, 10 solicitudes por segundo. Esto es similar a la etiqueta de uso de equipos compartidos en un laboratorio: si lo acapara, otras personas no podrán usarlo.
Clave de API
Algunas API requieren una clave de API. Las utilidades E de NCBI se pueden usar sin una clave de API, pero registrar una clave aumenta el límite de solicitudes por segundo de 3 a 10.
params = { "db": "gene", "term": "TP53[Gene Name]", "retmode": "json", "api_key": "YOUR_API_KEY_HERE",}La clave de la API nunca debe incluirse directamente en el código. Guárdela en una variable de entorno o en un archivo de configuración independiente y no la suba a Git.
Manejo de errores
Las llamadas a la API pueden fallar debido a problemas de red o a un ID incorrecto:
import requests
def safe_api_call(url: str, params: dict = None) -> dict: try: response = requests.get(url, params=params, timeout=10) response.raise_for_status() return response.json() except requests.exceptions.Timeout: print("La solicitud agotó el tiempo de espera — inténtalo de nuevo más tarde") return {} except requests.exceptions.HTTPError as e: print(f"Error HTTP: {e}") return {}timeout=10 — Si no hay respuesta en 10 segundos, se abandona la operación. Esto evita que el programa se quede bloqueado indefinidamente cuando el servidor está lento.
¡Pruébalo tú mismo! (Ejemplo simplificado)
Completa los espacios en blanco a continuación para completar el código que obtiene la longitud de la secuencia de proteínas de la API de UniProt.
importurl = "https://rest.uniprot.org/uniprotkb/P04637.json"response = requests.(url)if response.status_code == :data = response.()length = data["sequence"]["length"]print(f"Longitud de la secuencia: {length} aa")
Problemas comunes y soluciones
P: Ocurre el error ConnectionError o Timeout
Compruebe su conexión a Internet. Es posible que el servidor esté temporalmente inactivo. time.sleep(5) y vuelva a intentarlo o ejecútelo más tarde.
P: Ocurre KeyError y no puedo obtener los valores de JSON
Es posible que la estructura de la respuesta de la API sea diferente de lo esperado. Imprima la respuesta completa con print(json.dumps(data, indent=2)) para comprobar la estructura real de las claves. O utilice data.get("key", "no disponible") para devolver un valor predeterminado cuando falte una clave.
P: La respuesta de la API llega en HTML
Es posible que la URL sea una dirección de página web (para navegadores) y no una dirección de API. Compruebe el punto final exacto en la documentación de la API. Normalmente, una URL que contiene /api/ o .json es para API.
P: Ocurre el error 429 Too Many Requests
Ha enviado demasiadas solicitudes demasiado rápido. Aumente el intervalo entre las solicitudes con time.sleep(1). NCBI recomienda registrar una clave de API.