763e06c127
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
80 lines
4.6 KiB
Markdown
80 lines
4.6 KiB
Markdown
# Capability: seo
|
|
|
|
SEO orientado a datos sobre Google Search Console (GSC): autenticar contra la Search Console
|
|
API con una cuenta de servicio, extraer Search Analytics (impresiones, clicks, CTR, posición
|
|
por query y página) y aterrizarlo en DuckDB (verdad acumulada) + Postgres (espejo para
|
|
Metabase). Es la cadena de ingesta del proyecto `seo_analytics`.
|
|
|
|
La tesis del grupo: el SEO deja de hacerse a ciegas y se convierte en un problema de datos
|
|
con loop medible — el dashboard señala la oportunidad (striking distance, CTR bajo, content
|
|
decay), se aplica el cambio y se mide el impacto en la siguiente ingesta.
|
|
|
|
## Funciones
|
|
|
|
| ID | Firma | Qué hace |
|
|
|---|---|---|
|
|
| `gsc_auth_py_infra` | `gsc_auth(credentials_path="", subject="") -> service` | Autentica contra la Search Console API v1 con una service account JSON (scope `webmasters.readonly`). Fallback a env `GSC_SA_JSON`. Devuelve el `service` de googleapiclient listo para consultar. |
|
|
| `pull_gsc_search_analytics_py_datascience` | `pull_gsc_search_analytics(service, site_url, start_date, end_date, dimensions=None, row_limit=25000, max_total_rows=0, search_type="web") -> list[dict]` | Extrae Search Analytics paginando (startRow) hasta agotar. Aplana cada fila (keys → nombres de dimensión + clicks/impressions/ctr/position). `dimensions` por defecto `["query","page"]`. |
|
|
| `ingest_gsc_search_analytics_py_pipelines` | `ingest_gsc_search_analytics(site_url="", duckdb_path="", pg_dsn="", start_date="", end_date="", lookback_days=5, credentials_path="") -> dict` | Pipeline: auth → pull (dims date,query,page) → upsert idempotente en DuckDB → espejo a Postgres (`mode=replace`). Resuelve defaults de env (`GSC_SITE_URL`, `SEO_DSN`, `GSC_SA_JSON`). Lo invoca el DAG `seo-gsc-daily`. |
|
|
|
|
## Ejemplo canónico (end-to-end)
|
|
|
|
```bash
|
|
# Greenfield: ver projects/seo_analytics/docs/SETUP.md para crear la service account,
|
|
# verificar la propiedad en Search Console y darle acceso a la SA.
|
|
|
|
# 1. Variables (el .env del proyecto las agrupa)
|
|
export GSC_SITE_URL="sc-domain:ejemplo.com"
|
|
export SEO_DSN="postgresql://captacion:PASS@localhost:5433/seo"
|
|
export GSC_SA_JSON="$HOME/.config/seo/gsc-sa.json"
|
|
|
|
# 2. Ingesta diaria (auth + pull + DuckDB + espejo Postgres) — la corre el DAG seo-gsc-daily
|
|
python/.venv/bin/python3 python/functions/pipelines/ingest_gsc_search_analytics.py
|
|
|
|
# 3. Dashboards en Metabase (una vez): añade la DB seo + 4 cards + dashboard
|
|
SEO_PG_PASS=... METABASE_USER=... METABASE_PASS=... \
|
|
python/.venv/bin/python3 projects/seo_analytics/setup_metabase.py
|
|
```
|
|
|
|
Uso desde Python, componiendo las tres:
|
|
|
|
```python
|
|
import sys; sys.path.insert(0, "python/functions")
|
|
from infra import gsc_auth
|
|
from datascience import pull_gsc_search_analytics
|
|
|
|
svc = gsc_auth() # lee GSC_SA_JSON
|
|
rows = pull_gsc_search_analytics(svc, "sc-domain:ejemplo.com",
|
|
"2026-05-01", "2026-05-28",
|
|
dimensions=["date", "query", "page"])
|
|
print(len(rows), rows[0])
|
|
```
|
|
|
|
## Fronteras
|
|
|
|
- **NO hace keyword research ni rank tracking externo**. GSC dice por qué keywords ya apareces
|
|
en Google; descubrir keywords nuevas o medir SERP de competidores es otro trabajo (scrapers).
|
|
- **NO escribe los dashboards**. Las cards/dashboard de Metabase los construye el script del
|
|
proyecto `setup_metabase.py` componiendo el grupo `metabase`. Este grupo solo ingiere datos.
|
|
- **NO gestiona el scheduling**. Eso es `dag_engine` (DAG `seo-gsc-daily`, grupo `scheduler`).
|
|
- **NO cubre Bing/otros buscadores**. Solo Google Search Console.
|
|
|
|
## Gotchas del grupo
|
|
|
|
- Los datos de GSC llegan con **~2-3 días de lag**. El pipeline pide hasta hoy menos 3 días.
|
|
- Google **anonimiza queries de baja frecuencia** (privacy threshold): la suma por query no
|
|
cuadra con el total del sitio. Es esperado, no un bug.
|
|
- El formato de `site_url` importa: `sc-domain:ejemplo.com` (propiedad de dominio) vs URL
|
|
completa con esquema (propiedad de prefijo).
|
|
- La service account accede porque su email está **añadido como usuario en Search Console**
|
|
(Settings > Users), no por domain-wide delegation. El JSON de la SA es un secreto.
|
|
- **DuckDB es la verdad** (upsert idempotente, acumula histórico); **Postgres es un espejo**
|
|
que se regenera por `replace` en cada sync. No acumular en Postgres directamente.
|
|
|
|
## Prerequisitos
|
|
|
|
- Sitio verificado en Search Console + service account con acceso (ver SETUP.md del proyecto).
|
|
- Stack Postgres + Metabase del proyecto `captacion_clientes` (contenedores `captacion-postgres`
|
|
:5433 y `captacion-metabase` :3030), con la DB `seo` creada.
|
|
- Deps Python `google-api-python-client` + `google-auth` (ya en el venv del registry).
|