Files
fn_registry/python/functions/pipelines/ingest_gsc_search_analytics.md
T
egutierrez 763e06c127 feat(browser): auto-commit con 178 cambios
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-20 18:22:23 +02:00

6.7 KiB

name, kind, lang, domain, version, purity, signature, description, tags, uses_functions, uses_types, returns, returns_optional, error_type, imports, params, output, tested, tests, test_file_path, file_path
name kind lang domain version purity signature description tags uses_functions uses_types returns returns_optional error_type imports params output tested tests test_file_path file_path
ingest_gsc_search_analytics pipeline py pipelines 1.0.0 impure def ingest_gsc_search_analytics(site_url: str = '', duckdb_path: str = '', pg_dsn: str = '', start_date: str = '', end_date: str = '', lookback_days: int = 5, credentials_path: str = '') -> dict Pipeline de ingesta diaria de Google Search Console (Search Analytics): GSC -> DuckDB -> PostgreSQL. Autentica con una service account (gsc_auth), extrae las filas de Search Analytics por las dimensiones date/query/page (pull_gsc_search_analytics), crea la tabla DuckDB si no existe con una restriccion UNIQUE (duckdb_execute), transforma cada fila renombrando 'date'->'data_date' y rellenando defaults estables (country='', device='', search_type='web') para las dimensiones no pedidas, hace upsert idempotente en DuckDB (duckdb_upsert) y espeja la tabla completa a PostgreSQL en modo replace para que Metabase la lea (duckdb_to_postgres). DuckDB es la verdad acumulada (historico append idempotente); PostgreSQL es un espejo regenerado por completo cada corrida. Resuelve defaults de site_url/pg_dsn/duckdb_path desde env (GSC_SITE_URL, SEO_DSN, SEO_DUCKDB con fallback ~/.fn_seo/seo.duckdb). Resuelve fechas teniendo en cuenta el lag de ~3 dias de la API: end=hoy-3, start=hoy-(3+lookback_days), re-pulleando los ultimos dias para que el upsert corrija lo que GSC ajusta a posteriori. Devuelve un dict sin lanzar: {status:'ok', site_url, start_date, end_date, rows_pulled, duckdb, postgres} en exito, {status:'error', error} en fallo.
seo
gsc
search-console
pipelines
duckdb
gsc_auth_py_infra
pull_gsc_search_analytics_py_datascience
duckdb_execute_py_infra
duckdb_upsert_py_infra
duckdb_to_postgres_py_pipelines
false error_go_core
os
datetime
name desc
site_url propiedad de Search Console: 'sc-domain:ejemplo.com' (propiedad de dominio) o la URL de prefijo 'https://ejemplo.com/'. Si esta vacio se lee de la env var GSC_SITE_URL. Obligatorio: ValueError si falta.
name desc
duckdb_path ruta al archivo DuckDB de la fuente de verdad acumulada. Si esta vacio se lee de la env var SEO_DUCKDB y, en su defecto, ~/.fn_seo/seo.duckdb. El directorio padre se crea (os.makedirs exist_ok=True).
name desc
pg_dsn cadena de conexion PostgreSQL del espejo BI, p.ej. 'postgresql://user:pass@host:5432/db'. Si esta vacio se lee de la env var SEO_DSN. Obligatorio: ValueError si falta.
name desc
start_date fecha inicial inclusiva 'YYYY-MM-DD'. Si esta vacia se calcula como hoy-(3+lookback_days).
name desc
end_date fecha final inclusiva 'YYYY-MM-DD'. Si esta vacia se calcula como hoy-3 (lag de la API de GSC).
name desc
lookback_days numero de dias extra hacia atras que se re-pullean para que el upsert idempotente corrija los datos que GSC ajusta a posteriori (hasta ~3 dias). Default 5.
name desc
credentials_path ruta al JSON de la service account. Se pasa tal cual a gsc_auth, que ya hace su propio fallback a la env var GSC_SA_JSON.
dict. En exito: {status:'ok', site_url:str, start_date:str, end_date:str, rows_pulled:int, duckdb:dict (resultado de duckdb_upsert), postgres:dict (resultado de duckdb_to_postgres)}. En error (sin lanzar): {status:'error', error:str}. true
test_renombra_date_a_data_date_y_persiste_en_duckdb
test_resolucion_fechas_por_defecto
test_upsert_idempotente_no_duplica
test_falta_site_url_da_value_error
test_falta_pg_dsn_da_value_error
python/functions/pipelines/ingest_gsc_search_analytics_test.py python/functions/pipelines/ingest_gsc_search_analytics.py

Ejemplo

# Con las 3 env seteadas, una sola corrida hace el snapshot diario completo:
export GSC_SITE_URL="sc-domain:ejemplo.com"
export SEO_DSN="postgresql://seo:****@127.0.0.1:5432/seo"
export GSC_SA_JSON="$HOME/.fn_seo/service_account.json"
# (SEO_DUCKDB opcional; por defecto ~/.fn_seo/seo.duckdb)
./fn run ingest_gsc_search_analytics
# -> {"status": "ok", "site_url": "sc-domain:ejemplo.com",
#     "start_date": "2026-06-09", "end_date": "2026-06-17",
#     "rows_pulled": 1280, "duckdb": {...}, "postgres": {...}}
import sys
sys.path.insert(0, "python/functions")
from pipelines.ingest_gsc_search_analytics import ingest_gsc_search_analytics

# Variante explicita: rango de fechas fijo y rutas pasadas como args.
res = ingest_gsc_search_analytics(
    site_url="sc-domain:ejemplo.com",
    duckdb_path="/home/me/.fn_seo/seo.duckdb",
    pg_dsn="postgresql://seo:****@127.0.0.1:5432/seo",
    start_date="2026-06-01",
    end_date="2026-06-17",
    credentials_path="/home/me/.fn_seo/service_account.json",
)
print(res["rows_pulled"], res["status"])  # 4210 ok

Cuando usarla

Cuando quieras un snapshot diario de Google Search Console acumulado y consultable desde Metabase: cada corrida añade/actualiza los datos del rango en DuckDB y regenera el espejo PostgreSQL. La invoca el DAG seo-gsc-daily de dag_engine una vez al dia (no uses cron ni systemd timers: usa dag_engine). Para un re-pull manual puntual de un rango concreto, pásale start_date/end_date a mano.

Gotchas

  • Lag de ~3 dias: la API de GSC no consolida datos hasta ~3 dias despues. Por eso end_date por defecto es hoy-3 y start_date retrocede lookback_days extra. Pedir hasta hoy devolveria filas vacias o incompletas.
  • Re-pull idempotente: se re-piden a proposito los ultimos lookback_days dias. La restriccion UNIQUE (site_url, data_date, query, page, country, device, search_type) + duckdb_upsert actualizan esas filas sin duplicarlas, recogiendo las correcciones que GSC aplica a posteriori. El snapshot_date se sobrescribe al valor de la ultima corrida.
  • DuckDB es la verdad; PostgreSQL es un espejo: la ingesta acumula histórico solo en DuckDB. El espejo a Postgres usa mode='replace' -> hace DROP + CREATE + INSERT de la tabla completa cada vez. NO escribas en la tabla Postgres ni esperes acumular alli: se borra y reescribe en cada corrida. Si quieres histórico, leelo de DuckDB.
  • Dimensiones: este pull pide solo date/query/page. country y device quedan vacios y search_type='web' como defaults estables para que la tupla UNIQUE sea consistente. Si necesitas desglose por pais/dispositivo, es otro pull/tabla.
  • Requisitos de entorno: necesita las 3 env (GSC_SITE_URL, SEO_DSN, GSC_SA_JSON) o sus args equivalentes, y la service account debe estar añadida como usuario con permiso sobre la propiedad en Search Console. Faltar site_url o pg_dsn devuelve {status:'error'} (ValueError capturado, no crash).