#01 Cómo uso Python para detectar oportunidades de keywords que GSC no te muestra directamente

PythonSEOGoogle Search ConsoleData ScienceKeywords

Cómo uso Python para detectar oportunidades de keywords que GSC no te muestra directamente

Si trabajas en SEO y usas Google Search Console a diario, ya sabes lo que te voy a decir: la interfaz te da lo justo. Puedes ver las queries que generan impresiones, los clics, el CTR y la posición media. Bien. Pero ahí se acaba la fiesta.

El problema no es que GSC sea mala herramienta, sino que te muestra los datos de forma agregada y sin contexto. Y cuando tienes un sitio con cientos o miles de URLs, navegar por esa interfaz para encontrar oportunidades reales es como buscar una aguja en un pajar con los ojos cerrados.

Hace tiempo que resolví esto con Python. Te cuento exactamente cómo lo hago.

Por qué la interfaz de GSC se queda corta

Antes de entrar en código, quiero que entiendas bien el problema. GSC te muestra hasta 1.000 queries en su interfaz estándar. Si tienes más volumen, ya vas perdiendo datos. Además, no puedes cruzar fácilmente queries con URLs, ni filtrar por rangos de posición y CTR al mismo tiempo, ni detectar patrones entre keywords que comparten intención.

Lo que necesitas para encontrar oportunidades reales es poder hacerte preguntas como estas:

  • ¿Qué keywords tienen muchas impresiones pero CTR muy bajo? (posible problema de título o metadescripción)
  • ¿Qué queries están en posición 8-15 y podrían subir con un pequeño empujón?
  • ¿Hay URLs que reciben tráfico por keywords que no están optimizadas en la página?

Para responder a esto de forma sistemática, necesitas los datos en crudo y una herramienta que te deje manipularlos. Ahí entra Python.

El proceso paso a paso

1. Exportar los datos de GSC

Lo primero es sacar los datos fuera de la interfaz. Tienes dos opciones: exportar el CSV manualmente desde la pestaña de Rendimiento, o usar la Google Search Console API para automatizarlo. Yo uso la API cuando trabajo con proyectos recurrentes, pero para empezar el CSV es más que suficiente.

Exporta con el filtro de fecha más amplio posible (los últimos 16 meses si puedes) y asegúrate de activar la vista de Query + Página para tener el cruce entre ambas dimensiones.

2. Cargar y limpiar los datos con pandas

Una vez tienes el CSV, esto es lo primero que ejecuto:

import pandas as pd

df = pd.read_csv("gsc_export.csv")

# Renombrar columnas si vienen en inglés
df.columns = ["query", "url", "clicks", "impressions", "ctr", "position"]

# Limpiar el CTR (viene como string tipo "3.45%")
df["ctr"] = df["ctr"].str.replace("%", "").astype(float) / 100

# Eliminar filas sin datos
df = df.dropna()

print(df.shape)
print(df.head())

Nada del otro mundo, pero es importante hacer esta limpieza antes de cualquier análisis. El CTR en formato porcentaje como string es uno de esos errores que te puede dar dolores de cabeza si no lo corriges desde el principio.

3. Detectar oportunidades por posición y CTR

Aquí empieza lo interesante. El segmento que más me gusta analizar es el de keywords en posición 6-15 con volumen de impresiones razonable. Son las que están cerca del top pero no terminan de entrar, y suelen responder bien a mejoras de contenido o de SEO on-page.

oportunidades = df[
    (df["position"] >= 6) &
    (df["position"] <= 15) &
    (df["impressions"] >= 100)
].copy()

oportunidades = oportunidades.sort_values("impressions", ascending=False)

print(oportunidades[["query", "url", "impressions", "ctr", "position"]].head(20))

Con este filtro obtienes un listado de queries que ya tienen visibilidad, pero que todavía no están convirtiendo bien. Son candidatos perfectos para una optimización rápida.

4. Cruzar CTR real con CTR esperado por posición

Este es el análisis que más me gusta y el que más valor aporta. La idea es comparar el CTR que está obteniendo cada keyword con el CTR esperado para esa posición, según benchmarks conocidos del sector.

# CTR medio esperado por posición (valores aproximados según estudios del sector)
ctr_esperado = {
    1: 0.28, 2: 0.15, 3: 0.11, 4: 0.08, 5: 0.06,
    6: 0.04, 7: 0.03, 8: 0.025, 9: 0.022, 10: 0.02
}

df["position_round"] = df["position"].round().astype(int)
df["ctr_esperado"] = df["position_round"].map(ctr_esperado)

df["ctr_gap"] = df["ctr_esperado"] - df["ctr"]

# Keywords con CTR muy por debajo del esperado
bajo_ctr = df[
    (df["position_round"] <= 10) &
    (df["ctr_gap"] > 0.02)
].sort_values("ctr_gap", ascending=False)

print(bajo_ctr[["query", "url", "position", "ctr", "ctr_esperado", "ctr_gap"]].head(20))

Ojo: los valores de CTR esperado varían mucho según el sector, el tipo de query y si hay features de SERP (featured snippets, PAA, etc.). Úsalos como referencia, no como verdad absoluta. Lo importante es el patrón, no el número exacto.

Cuando encuentras una keyword con posición 3 y CTR del 2% cuando lo esperable sería un 11%, tienes una señal clara de que algo falla: el título no es atractivo, la metadescripción no engancha, o hay un snippet que está robando los clics.

5. Exportar el resultado para trabajar con él

Al final del proceso, exporto todo a un CSV limpio para revisarlo con calma o compartirlo con el equipo:

bajo_ctr.to_csv("oportunidades_ctr.csv", index=False)
oportunidades.to_csv("oportunidades_posicion.csv", index=False)

Lo que hago con estos datos después

Los resultados de este análisis me sirven para dos cosas principalmente:

  • Priorizar páginas para optimización on-page: si una URL aparece varias veces con diferentes queries con CTR bajo, es candidata clara a revisar título, H1 y metadescripción.
  • Identificar contenido que necesita expansión: si una página posiciona en top 10 por una query que no está bien desarrollada en el texto, añadir contenido relevante suele mover la aguja.

No es un proceso mágico, pero sí es sistemático. Y eso, en SEO, ya es mucho.


Si tienes cualquier duda sobre cómo adaptar esto a tu caso concreto, escríbeme. Y si quieres ver cómo automatizo este proceso completo con la API de GSC para no tener que exportar CSVs manualmente, eso lo cuento en otro post.