neurotrack_pubmed_search.py
Python 3.11
"""
NeuroTrack AI — PubMed Search via NCBI E-utilities
Búsqueda reproducible de literatura biomédica sobre IA + Alzheimer.
Requiere: requests, python-dotenv
Variables de entorno: NCBI_EMAIL, NCBI_API_KEY
"""
import os
import time
import json
import csv
from datetime import date
import requests
BASE = "https://eutils.ncbi.nlm.nih.gov/entrez/eutils"
TODAY = date.today().isoformat()
# ─── Configuración ─────────────────────────────────────────────────────────
NCBI_EMAIL = os.environ.get("NCBI_EMAIL", "investigacion@neurotrack.ai")
NCBI_API_KEY = os.environ.get("NCBI_API_KEY") # obtener en: ncbi.nlm.nih.gov/account/
RETMAX = 200
# ─── Queries de búsqueda (3 passes) ────────────────────────────────────────
SEARCH_PASSES = [
{
"id": "pass1",
"label": "IA + Alzheimer (revisiones sistemáticas)",
"query": (
"(artificial intelligence[mh] OR machine learning[tiab] OR deep learning[tiab])"
" AND Alzheimer disease[mh]"
" AND diagnosis[sh]"
" AND 2022:2026[dp]"
" AND english[la]"
" AND (systematic review[pt] OR meta-analysis[pt])"
),
},
{
"id": "pass2",
"label": "Biomarcadores plasmáticos + ML",
"query": (
"(amyloid beta-peptides[mh] OR tau proteins[mh])"
" AND (machine learning[tiab] OR neural network[tiab] OR random forest[tiab])"
" AND blood[tiab]"
" AND 2022:2026[dp]"
" AND english[la]"
" AND hasabstract[text]"
),
},
{
"id": "pass3",
"label": "MRI + CNN/Transformer + Sensibilidad/Especificidad",
"query": (
"magnetic resonance imaging[mh]"
" AND (convolutional neural network[tiab] OR CNN[tiab] OR transformer[tiab])"
" AND Alzheimer disease[mh]"
" AND sensitivity AND specificity[mh]"
" AND 2022:2026[dp]"
" AND free full text[sb]"
),
},
]
# ─── Funciones E-utilities ──────────────────────────────────────────────────
def _params(**extra) -> dict:
p = {"tool": "neurotrack-pubmed", "email": NCBI_EMAIL}
if NCBI_API_KEY:
p["api_key"] = NCBI_API_KEY
p.update(extra)
return p
def esearch(query: str, retmax: int = RETMAX) -> tuple[list[str], int]:
r = requests.get(
f"{BASE}/esearch.fcgi",
params=_params(db="pubmed", term=query,
retmode="json", retmax=retmax),
timeout=30,
)
r.raise_for_status()
time.sleep(0.35)
data = r.json()["esearchresult"]
return data["idlist"], int(data["count"])
def efetch_abstracts(pmids: list[str]) -> str:
r = requests.get(
f"{BASE}/efetch.fcgi",
params=_params(db="pubmed", id=",".join(pmids),
rettype="abstract", retmode="text"),
timeout=60,
)
r.raise_for_status()
time.sleep(0.35)
return r.text
# ─── Ejecución principal ────────────────────────────────────────────────────
log_rows = []
for pass_ in SEARCH_PASSES:
print(f"[{pass_['id']}] Ejecutando: {pass_['label']}")
pmids, total = esearch(pass_["query"])
print(f" → {total} resultados totales | {len(pmids)} recuperados")
log_rows.append({
"pass_id": pass_["id"],
"label": pass_["label"],
"database": "PubMed/MEDLINE",
"date_searched": TODAY,
"query": pass_["query"],
"total_results": total,
"retrieved": len(pmids),
"pmids": "|".join(pmids),
})
# Guardar log CSV
with open("pubmed_search_log.csv", "w", newline="", encoding="utf-8") as f:
writer = csv.DictWriter(f, fieldnames=log_rows[0].keys())
writer.writeheader()
writer.writerows(log_rows)
print("\n✓ Log guardado en pubmed_search_log.csv")