Cómo trackear la posición de keywords con Python

Last Updated on enero 23, 2025 by Álvaro

La mayoría de herramientas SEO son bastante caras, por eso muchas veces nos toca tirar de inventiva. Eso he hecho yo en esta ocasión, creando un algoritmo para trackear la posición de las keywords de un dominio con Python y Beautiful Soup.

(Si solo vienes por el código, tienes el completo al final del artículo).

Si te da pereza leer, en este vídeo explico más en detalle el algoritmo.

Librerías necesarias

Para este proyecto, utilizaremos las siguientes librerías de Python:

  • Requests: Para realizar solicitudes HTTP.
  • Beautiful Soup: Para analizar y extraer datos del HTML.
  • Time: Para añadir un delay entre ejecuciones y que Google no sepa que no somos humanos.
  • Pandas: Para exportar los resultados a Excel.

Puedes instalar estas librerías utilizando pip:

pip install requests beautifulsoup4 pandas

Time no es necesario instalarlo porque es parte de la biblioteca estándar de Python. Simplemente puedes importarla en tu script sin necesidad de instalación adicional.

import requests
from bs4 import BeautifulSoup
import time
import pandas as pd

Código del SERP Scraper

Para trackear las posiciones de una keyword, necesitamos antes extraer sus SERPs. Para ello utilizamos la siguiente función:

def get_search_results(keyword, numResults):
    keyword = keyword.replace(' ', '+')
    search_url = f"https://www.google.com/search?q={keyword}&num={numResults}&gl=es&hl=es"
    
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"
    }
    
    results = []
    response = requests.get(search_url, headers = headers)
    soup = BeautifulSoup(response.text, 'html.parser')
    
    for i in soup.find_all('div', class_='g'):
        link = i.find('a', href=True)
        results.append(link['href'])
        if len(results) >= numResults:
            break;
    time.sleep(2)
    
    return results

Repasemos un poco su código.

En primer lugar creamos una URL de búsqueda. Los atributos que recibe son:

  • ?q= Que no es más que la consulta. En vez de espacios se utilizan +, de ahí el replace. Por ejemplo, la keyword alcachofas con jamon se traducirá como ?q=alcachofas+con+jamon.
  • &num = Es el número de resultados que se mostrarán en cada página. Gracias a este atributo no tendremos que navegar por la paginación de Google.
  • &gl= Indica la localización de la consulta. Para las SERPs de España utilizamos &gl=es, pero si por ejemplo quisiéramos scrapear las SERPs de Costa Rica utilizaríamos &gl=cr
  • &hl= Es el idioma, en este caso el español.

Luego, es necesario crear un header que mandaremos junto con la URL. Su función es básicamente emular el navegador de un usuario para no ser detectados como robots.

Y ya a partir de ahí como cualquier otro algoritmo de scraping (si no tienes ni idea te recomiendo que revises mi tutorial de web scraping).

Código para trackear las keywords

Ahora, necesitamos una lista con las keywords a trackear y el dominio que posiciona para ellas.

El funcionamiento del script es muy sencillo: se recorre la lista de keywords y para cada una se ejecuta la función anteriormente mostrada. Luego, se comprueba en que posición (índice + 1 porque las listas empiezan desde la posición 0) está el dominio introducido la lista que se genera como output.

dominio = "alvarohontanar.es"
keywords = ["entrega de premios vocación digital raiola", "cómo aparecer en google discover", "graficos manipulados"]
resultados = {}

for keyword in keywords:
    found = False
    results = get_search_results(keyword, 50)

    for index, result in enumerate(results):
        if dominio in result:
            print(f"La posición de {dominio} para la keyword '{keyword}' es {index + 1}")
            resultados[keyword] = index + 1
            found = True
            break

    if not found:
        print(f"{dominio} no se encontró en los resultados para la keyword '{keyword}'")

Y por si quieres exportar a Excel las keywords…

Para ello utilizamos la librería pandas. Convertimos el diccionario en el que hemos almacenado la keyword y la posición en un dataframe y exportamos a XSLX.

df_resultados = pd.DataFrame(list(resultados.items()), columns=['Keyword', 'Posición'])
df_resultados.to_excel('posicion-keywords.xlsx', index=False)
Ejemplo de salida en Excel tras ejecutar el algoritmo
Ejemplo de salida en Excel

Código completo

Para que copies y pegues directamente el código 🙂

import requests
from bs4 import BeautifulSoup
import time
import pandas as pd

def get_search_results(keyword, numResults):
    keyword = keyword.replace(' ', '+')
    search_url = f"https://www.google.com/search?q={keyword}&num={numResults}&gl=es&hl=es"
    
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"
    }
    
    results = []
    response = requests.get(search_url, headers = headers)
    soup = BeautifulSoup(response.text, 'html.parser')
    
    for i in soup.find_all('div', class_='g'):
        link = i.find('a', href=True)
        results.append(link['href'])
        if len(results) >= numResults:
            break;
    time.sleep(2)
    
    return results

dominio = "alvarohontanar.es"
keywords = ["entrega de premios vocación digital raiola", "cómo aparecer en google discover", "graficos manipulados"]
resultados = {}

for keyword in keywords:
    found = False
    results = get_search_results(keyword, 50)

    for index, result in enumerate(results):
        if dominio in result:
            print(f"La posición de {dominio} para la keyword '{keyword}' es {index + 1}")
            resultados[keyword] = index + 1
            found = True
            break

    if not found:
        print(f"{dominio} no se encontró en los resultados para la keyword '{keyword}'")

df_resultados = pd.DataFrame(list(resultados.items()), columns=['Keyword', 'Posición'])
df_resultados.to_excel('posicion-keywords.xlsx', index=False)

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *