Files
chemavx-seo-tools/MANUAL-GSC.md
T
ChemaVXandClaude Opus 5 896d723f15 seo_gsc: el marcador — datos reales de Search Console
Toda la caja de herramientas miraba hacia dentro (enlaces, sitemap, reglas de
metas): decía si el sitio está bien construido, no si alguien lo encuentra. Los
únicos datos de resultado en la máquina eran una exportación manual del
2026-06-17, anterior al remate de metas del 23 de junio — o sea, cuarenta días
optimizando sin saber el resultado.

Cuenta de servicio en vez de OAuth, porque aquí no hay navegador (misma piedra
que con Gemini). Sin librerías de Google: el JWT se firma con PyJWT y se canjea
a mano, treinta líneas en lugar de media docena de dependencias.

Lo que de verdad aporta es `informe`: la lista de páginas que POSICIONAN Y NO
SE PINCHAN, con los clics que faltan si el CTR fuese el normal de su posición.
Y `antes-despues`, escrito para responder de una vez si el remate del 23-jun
sirvió: la API guarda 16 meses, así que el histórico está disponible desde el
primer minuto y no hay que esperar semanas para comparar.

Probado lo que se puede probar sin credencial: firma RS256 emitida y verificada
con su pública, los dos caminos de fallo de la credencial (ausente y con
permisos flojos), y la lógica de análisis contra datos sintéticos calcados del
caso Nimitz real (pos 6,44 / 2.452 impresiones / 0,16% CTR), que sale marcada
con +111 clics de hueco mientras la página sana no se marca.

El timer queda instalado y PARADO: sin credencial fallaría cada lunes, y un
timer que falla siempre enseña a ignorar los avisos.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-27 20:36:45 +00:00

123 lines
4.9 KiB
Markdown

# El marcador — Search Console (`seo_gsc.py`)
Lo que faltaba en toda la caja de herramientas: **datos de resultado**. El
resto mira hacia dentro (enlaces, sitemap, reglas de metas); esto mira lo único
que decide si el trabajo sirvió — cuánta gente nos encuentra y cuánta pincha.
Es de **solo lectura**. No escribe en los blogs ni en Search Console.
## Puesta en marcha (cuatro pasos de navegador, una sola vez)
La API es gratis. Hace falta una **cuenta de servicio**, no OAuth: en esta
máquina no hay navegador y el flujo interactivo no funciona headless — la misma
piedra con la que ya tropezamos en Gemini.
1. **Proyecto y API.** En <https://console.cloud.google.com> crea un proyecto
(o reutiliza uno) y activa **Google Search Console API** en
*APIs y servicios → Biblioteca*.
2. **Cuenta de servicio.** *IAM y administración → Cuentas de servicio → Crear*.
No necesita ningún rol de IAM: el permiso que importa se da en el paso 4.
Luego *Claves → Añadir clave → Crear nueva → JSON* y descarga el fichero.
3. **La clave, en su sitio.** En esta máquina:
```bash
mkdir -p ~/.config/gsc
mv ~/Descargas/EL-FICHERO.json ~/.config/gsc/service-account.json
chmod 600 ~/.config/gsc/service-account.json
```
La herramienta **se niega a arrancar** si el fichero es legible por otros.
Está fuera de cualquier repo; no la metas en git.
4. **Permiso en Search Console.** Este es el paso que se olvida. Para **cada
una de las dos propiedades** (`theexclusionzone.com` y
`zonadeexclusion.com`): *Configuración → Usuarios y permisos → Añadir
usuario* → pega el `client_email` de la credencial (algo como
`nombre@proyecto.iam.gserviceaccount.com`) → permiso **Restringido**, que
basta para leer.
⚠️ Si `zonadeexclusion.com` no está dada de alta en Search Console, hay que
verificarla antes. Del blog ES no había ni una sola exportación, así que es
probable que ni exista la propiedad.
5. **Arrancar el vigilante.** El timer se instala **parado a propósito**: sin
credencial fallaría cada lunes, y un timer que falla siempre enseña a
ignorar los avisos. Se enciende cuando el canario pasa:
```bash
seo-gsc comprueba && sudo systemctl enable --now seo-gsc-watch.timer
```
Comprobación:
```bash
seo-gsc sitios # tienen que salir las dos propiedades
seo-gsc comprueba # canario: recorre el camino real eslabón por eslabón
```
Si el nombre que devuelve `sitios` no coincide con el configurado (puede ser
`sc-domain:x.com` o `https://www.x.com/`, con barra final), corrige el
diccionario `SITIOS` en `seo_gsc.py` con el nombre exacto.
## Uso diario
```bash
seo-gsc pull # descarga y acumula en SQLite (idempotente)
seo-gsc # sin argumentos = informe de 28 días
seo-gsc informe --dias 7
```
La primera descarga se trae **16 meses**, que es todo lo que Google guarda. Eso
significa que el histórico está disponible desde el minuto uno: no hay que
esperar semanas para tener con qué comparar.
### La pregunta pendiente
El remate de metas fue el **23 de junio** y los únicos datos que había eran del
17. En cuanto haya credencial:
```bash
seo-gsc antes-despues --corte 2026-06-23 --dias 28
```
## Qué mira el informe
- **Movimiento** de clics, impresiones y CTR contra el periodo anterior.
- **Páginas que posicionan y no se pinchan.** Es la lista que importa: si algo
está en posición 6 con 2.400 impresiones y 0,16% de CTR, no tiene un problema
de posicionamiento, tiene un problema de titular. Cada línea estima los clics
que faltan si el CTR fuese el normal de esa posición.
- **Consultas con impresiones y cero clics**, que son temas donde ya salimos y
no convencemos.
El CTR "normal" sale de una curva de referencia del sector, no de una medición
nuestra: **sirve para ordenar candidatas, no para prometer tráfico**. Solo se
avisa por encima de 150 impresiones, porque por debajo el CTR es ruido.
## Automático
`seo-gsc-watch.timer` — lunes 06:15 UTC: descarga y manda el informe por
Telegram, pero **solo si hay páginas desperdiciadas y el informe ha cambiado**
desde el último aviso. Misma disciplina que `seo-watch`: si no hay nada que
decir, se calla.
```bash
systemctl status seo-gsc-watch.timer
journalctl -u seo-gsc-watch -n 40
```
## Notas de implementación
- **Sin librerías de Google.** El JWT se firma con PyJWT y se canjea a mano.
Son treinta líneas y evita arrastrar media docena de dependencias para tres
peticiones.
- **Los datos tardan 2-3 días en consolidarse.** Todo termina 3 días atrás y se
pide `dataState=final`; pedir "ayer" devuelve cifras que luego cambian solas.
- **La posición se pondera por impresiones.** Promediar posiciones a pelo da el
mismo peso a un día de 2 impresiones que a uno de 500.
- **La API pagina de 25.000 en 25.000** y no avisa de que quedan más filas.
- El almacén es SQLite en `~/.local/state/seo-gsc/gsc.db`; `pull` es idempotente
y resolapa un día por si el último se consolidó después.