SPAB — retrieval pulido y fuente Wikipedia conectada

Fecha: 2026-09-14 · Proyecto: ~/nef/estado_turismo/spab-retrieval Método: aplicar el recetario de retrieval de surtido (~/nef/decisions/2026-09-13-surtido-recetario-retrieval.md) al pipeline de SPAB.

Idea fuerza del recetario aplicada

“Toda fuente declarada en el schema debe tener su fetcher registrado y que compile; una fuente sin conector es señal que se pierde en silencio.” El pipeline tiene 6 etapas: registrar → fetch → normalizar/guardar → enriquecer → consolidar/exportar → servir.

Estado de fuentes (tras esta sesión)

Fuentemodocorre hoyrequiere
dataturfilesí (llegadas extranjeras, vía script)data/raw/datatur.csv (generado por scripts/datatur_desde_upm.py)
aerofilesolo si depositas CSVdata/raw/aero.csv
sesnspfilesolo si depositas CSVdata/raw/sesnsp*.csv
insideairbnbhttpsí (descarga pública)—
googleplaceshttpno sin keyGOOGLE_PLACES_API_KEY
trendshttpno (Google responde 429 al scraping)GOOGLE_TRENDS_COOKIE
sargazofilesolo si depositas CSVdata/raw/sargazo-*.csv
wikipediahttpsí, cero-config—
openskyhttpsí (OAuth2; cobertura parcial en MX)OPENSKY_CLIENT_ID/OPENSKY_CLIENT_SECRET

Correcciones hechas

  1. trends: su endpoint /api/interestOverTime devuelve 404 y el flujo vigente es de dos pasos (/api/explore → token → /widgetdata/multiline). Además Google devuelve 429 sin cookie de sesión. Quedó implementado el flujo real y gateado por GOOGLE_TRENDS_COOKIE: sin ella listo()=false y el panel pide configurarla (no falla en silencio).
  2. sargazo: import roto + métrica severidad_sargazo emitida antes de declararla; y el array fallos era código muerto. Corregido; ahora reporta filas omitidas.
  3. wikipedia (nueva): la fuente anticipatoria que sí corre sin key. API de Wikimedia Pageviews — estable, JSON, sin cookie. Emite vistas_wikipedia (conteo mensual humano) = serie destino × mes.
  4. Script lint: next lint fue eliminado en Next 16 y no había ESLint instalado. Se quitó el script muerto; la vara es npm run typecheck + build.

Gotcha crítico: títulos de Wikipedia (redirects / desambiguación)

La API de Pageviews cuenta solo el título canónico: un redirect o una página de desambiguación devuelve números falsos y silenciosos. Verificado:

DestinoTítulo correctoAntes (mal)Después
acapulcoAcapulco de Juárez3504794
puerto-escondidoPuerto Escondido (Oaxaca)372359

Por eso se agregó claves.wikipedia en destinos.json (config, no código) con el título canónico de cada destino. Sin override cae a nombre.

Resolver de títulos canónicos (implementado)

Además de los claves explícitos, el conector wikipedia ahora resuelve solo, en una sola llamada a la Action API para los 10 destinos (action=query&redirects=1&converttitles=1&prop=pageprops):

  • sigue redirects → Acapulco ⇒ Acapulco de Juárez;
  • detecta desambiguaciones (pageprops.disambiguation) y las omite con nota ("Puerto Escondido" es desambiguación) en vez de traer conteos falsos;
  • si la Action API falla, fallback a claves.wikipedia (o nombre).

Probado end-to-end con títulos “malos” en un SPAB_DATA_DIR temporal: acapulco se autocorrigió a 4794 y puerto-escondido se omitió (99 obs, nota clara).

Credencial Wikimedia (bot password)

En .env: BOT_USER=Engraxia@datatur + BOT_PASS (32 chars). Login verificado (Success, id 934740, solo lectura, sin grants de escritura). Es opcional: las lecturas no la exigen; da holgura de límite de tasa al resolver. El login corre en sesion() y si falla el conector sigue anónimo. .env está en .gitignore.

Bug de Places (corregido)

textQuery: "{nombre}, {estado}" hacía que Text Search devolviera el lugar (no sus negocios); con includedType daba 0 resultados (hoteles). Fix: textQuery: "{categoría} en {nombre}, {estado}". Verificado: 10–20 resultados por giro en Tulum/Bacalar. Sin esto, rating/reviews/menciones_caro habrían quedado vacíos en silencio. Corrida 2026-09-14: 30 obs (10 destinos × 3 métricas) en data/obs/googleplaces.ndjson.

Cómo empezar (comandos)

cd ~/nef/estado_turismo/spab-retrieval
npm run dev            # o: npm run build && npm run start
npm run recolectar     # POST /api/retrieve {meses:12}  (asume :3000)
# para una sola fuente:
curl -s -X POST localhost:3000/api/retrieve \
  -H 'content-type: application/json' -d '{"fuentes":["wikipedia"],"meses":12}'

Datos: data/obs/<fuente>.ndjson (append-only) y data/meta/corridas.ndjson. Verificado esta sesión: wikipedia → 110 obs (11 meses × 10 destinos).

Pendiente / siguiente

  • Datos: el índice (burbuja.ts) requiere precio_hospedaje, rating, ocupacion_hotelera; hoy solo hay vistas_wikipedia → todo sin_datos. Para poblarlo: depositar datatur.csv (ocupación) y key de Places (rating), o aceptar la señal de wikipedia como capa aparte.
  • Clustering (primer paso pedido): con data/obs/wikipedia.ndjson ya hay matriz destino × mes para un primer KMeans de perfiles de interés. Falta la corrida de análisis.
  • BigQuery: sumidero opcional; se activa con BQ_DATASET + GOOGLE_APPLICATION_CREDENTIALS. Sin eso corre todo en disco.