Optimizar el SEO On Page en bulk con Python

Esta vez quería trasladar a la comunidad SEO hispana un script que he encontrado que me ha parecido brutal. Esto de la programación no siempre consiste en inventar la rueda, si no que también te da la posibilidad de utilizar y adaptar a tus necesidades lo que la comunidad va desarrollando incluso si no dispones de conocimientos avanzados.

La idea original del script la he sacado de Practical Data Science. El script está «tuneado» según lo que me ha parecido más conveniente, y como digo, me ha parecido tan brutal que he decidido crear un post sobre ello, siempre dándoles los créditos que se merecen 😊

Script para detectar oportunidades SEO

El SEO On Page como todos sabemos es algo que debemos tener muy presente puesto que siempre es recomendable facilitarles la tarea a los bots para entender el contenido de la URL y enfocarlo así unas main keywords concretas (satisfaciendo lógicamente a los usuarios con un buen contenido).

Cuando una URL tiene cierto rendimiento y vemos que empieza a posicionar por determinadas keywords, la experiencia demuestra que es siempre positivo intentar incluir esas keywords en los principales elementos On Page de la página en el caso de que este trabajo no se hubiera realizado en el momento de la publicación. Aunque el SEO sea cada vez sea más semántico, e incluir las keywords exactas no tenga que ser una regla estricta ni necesaria, no nos engañemos, es una premisa que siempre está presente. Lo lógico en estos casos es no luchar contra Google e intentar darle peso a las keywords que ya tienen cierta visibilidad y rendimiento (dando por hecho que son keywords relevantes para la URL), puesto que esto puede darle un plus de visibilidad. Si me empeño en que una URL posicione por un nicho de keywords pero realmente está posicionando por otro muy diferente, o lo has hecho muy mal con el contenido o la intencionalidad de búsqueda que intentas cubrir no es la correcta, etc. En estos casos, una optimización on page va servir de bien poco.

El objetivo del script es precisamente identificar la keyword que mejor rendimiento tiene, asociada a cada URL de nuestra web, y evaluar si dicha keyword se encuentra en los principales elementos On Page de la URL (en este caso: title, description, h1, primer párrafo de texto y todos los h2 del contenido). Lógicamente la gracia de esto es hacerlo en bulk en base a un crawl previo para todas las URLs de la web o una sección concreta.

Resultado final que vamos a obtener

La tabla resultante que vamos a obtener es la siguiente:

Una tabla con todas las URLs de nuestra web con tráfico en donde se especifica la query o consulta más relevante (por clicks) y se evalúa si dicha query se encuentra en los principales elementos On Page (en el ejemplo: title, description, H1, primer párrafo del contenido y todos los H2). Además, solo nos vamos a quedar con aquellas URLs cuya consulta principal tiene una posición media entre 2-20 , que son aquellas que tienen margen de mejora.

Herramientas necesarias

  • Screaming Frog para hacer un crawl a tu web.
  • Un IDLE de Python para ejecutar el script (yo uso Pycharm)
  • Acceso a la API de Google Search Console (credenciales, etc.)

Proceso

Paso 1: Crawl con Screaming Frog

Haz un crawl a tu web completa o una sección concreta sobre la que quieras hacer el análisis. Para el caso, tenemos que dejar un excel preparado con las columnas «URL», «Title», «Description», «H1» , «H2» y «P1».

En este caso, en el crawl vamos a extraer con xpath el primer párrafo de texto (Columna «P1») de cada URL con la siguiente expresión o similares:

«//p[position()=1]» (es recomendable que adaptes el xpath para tu proyecto en concreto puesto que pueden diferir las necesidades).

Este elemento también me parece interesante a la hora de evaluar una posible optimización on page pero incluso podrías escrapear todo el texto de cada URL y evaluar si la query se encuentra en él.

También vamos a extraer todos los H2 del contenido, por lo que si hay varios, tendrías que llamarlos «H2.0», «H2.1», «H2.3», etc. Esto lo vamos a hacer con una extracción personalizada para extraer todos los H2 que tenga la URL:

La tabla del crawl tiene que quedar así:

Paso 2: Extracción de datos de Google Search Console con la API

La segunda parte del proceso será entrar al turrón con el script.

Pero antes, vamos a instalar las librerías e importar las clases que vamos a utilizar en el script:

$ pip install ecommercetools
$ pip install pandas 
$ pip install numpy

from ecommercetools import seo
import pandas as pd
import numpy as np

Vamos a usar principalmente la librería ecommercetools, también desarrollada por Practical Data Science, con la que podemos hacer una request a la API de GSC de forma muy sencilla. Vamos a poner una fecha de inicio y de fin y poner de límite unas 25.000 filas que es el máximo que permite la API. Con esto, vamos a obtener todos los datos de GSC para esas fechas concretas.

Te recomiendo echarle un ojo a algún tutorial para usar la API de GSC con Python para conocer los requisitos de uso: crear un proyecto en la API Console de Google, crear cuenta de servicio, descargar credenciales JSON, dar de alta cuenta de servicio en GSC, etc.
key = "client_secrets.json" #tus credenciales de la API
site_url = "sc-domain:seoalex.es" #tu propiedad de GSC, puede ser de dominio completo o no
start_date = '2022-01-08'
end_date = '2022-03-07'
payload = {
    'startDate': start_date,
    'endDate': end_date,
    'dimensions': ['page', 'query'],
    'rowLimit': 25000, #maximo de rows
    'startRow': 0
}

df = seo.query_google_search_console(key, site_url, payload)  #almacenamos los datos en un dataframe
df = df.sort_values(by=['page', 'clicks'], ascending=False) #ordenamos las URLs por volumen de clicks
df = df.drop_duplicates(subset='page', keep='first') #eliminamos los duplicados de URL y nos quedamos con la query que más clicks consigue por URL

Paso 3: Fusionar datos de GSC y crawl de Screaming Frog

Una vez tenemos un dataframe con los datos de GSC, los vamos a fusionar con nuestro crawl, obteniendo un nuevo dataframe en donde ya tengamos los datos de clicks, posición media, etc. y también los datos de title, description, h1, etc. de nuestro crawl.

Para ello simplemente leemos con Pandas el Excel que habíamos preparado y usamos el método merge() para hacer la fusión de ambos dataframes según URL.

df_crawl = pd.read_excel('crawl.xlsx' , engine="openpyxl")
df_all = df_crawl.merge(df, how='left', left_on='URL', right_on='page')

Una vez tengamos el nuevo dataframe con los datos fusionados, vamos a eliminar aquellas URLs que no tienen consultas con clicks y además vamos a quedarnos solo con aquellas que tienen una posición media que se encuentra entre 2-20, que son las que nos interesa optimizar a corto plazo:

df_traffic = df_all[df_all['query'].notnull()]
df_traffic = df_all[df_all['position'].between(1.9, 20, inclusive=False)]
del df_traffic['page']

Ahora vamos a concatenar todos los headings H2 en una sola cadena y la almacenaremos en una nueva columna «all_h2» para evaluar si la query se encuentra en ella. Si el resultado es verdadero quiere decir que efectivamente la query se encuentra en algún encabezado H2 de la URL.

Para ello primero tenemos que reemplazar los valores vacíos por una cadena vacía para que la concatenación no de error:

df_traffic = df_traffic.replace(np.nan, '', regex=True)
df_traffic.insert(16, 'all_h2', '')
for i in range(9): #este bucle tendrás que adaptarlo al nº máximo de h2 que quieres concatenar
    df_traffic['all_h2'] = df_traffic['all_h2']+" "+df_traffic['H2.'+str(i)]

Paso 4: Crear Dataframe final

Finalmente crearemos nuestras funciones de evaluación con las que checkearemos si la query se encuentra en cada elemento onpage. Estos resultados se almacenarán en nuevas columnas en nuestro Dataframe:

def in_title(row):
    if type(row['Title']) == str:
        if str(row['query']) in row['Title'].lower():
                return "Si"
        else:
            return "No"
    else:
        return "No existe"


def in_description(row):
    if type(row['Description']) == str:
            if str(row['query']) in row['Description'].lower():
                return "Si"
            else:
                return "No"
    else:
        return "No existe"


def in_h1(row):
    if type(row['H1']) == str:
        if str(row['query']) in str(row['H1']).lower():
            return "Si"
        else:
            return "No"
    else:
        return "No existe"


def in_P1(row):
    if type(row['P1']) == str:
        if str(row['query']) in str(row['P1']).lower():
            return "Si"
        else:
            return "No"
    else:
        return "No existe"


def in_h2(row):
    if type(row['P1']) == str:
        if str(row['query']) in str(row['all_h2']).lower():
            return "Si"
        else:
            return "No"
    else:
        return "No existe"


df_traffic = df_traffic.assign(in_title=df_traffic.apply(in_title, axis=1))
df_traffic = df_traffic.assign(in_h1=df_traffic.apply(in_h1, axis=1))
df_traffic = df_traffic.assign(in_description=df_traffic.apply(in_description, axis=1))
df_traffic = df_traffic.assign(in_P1=df_traffic.apply(in_P1, axis=1))
df_traffic = df_traffic.assign(in_any_H2=df_traffic.apply(in_h2, axis=1))

Ordenamos nuestros resultados por clicks y exportamos un excel con los resultados:

df_traffic.sort_values(['clicks'], inplace=True, ascending=False)
df_traffic.to_excel('SEO-Opportunities.xlsx', index=False)

Conclusión final

Como resultado final vamos a obtener una visión holística de la web/sección en donde de un vistazo podremos evaluar si la query más relevante asociada a cada URL se encuentra en los principales elementos del SEO onpage. Además, solo tendremos aquellas URLs con tráfico cuya consulta más relevante tenga una posición media que se encuentre entre 2-20, que son aquellas que podremos potenciar más fácilmente con una optimización On Page.

Con esto ya podrías establecer un plan de acción para optimizar los principales elementos On Page de cada URL si lo crees conveniente.

¡Espero os haya servido de ayuda!

Sobre el autor

Alex Romero Lopez, Consultor SEO en España
alejandro.romerolopez95@gmail.com Web Otros artículos del autor

Especialista SEO con gran foco en el área técnica. Entusiasta de la programación, en especial Python y Javascript, y la aplicación de ésta en el ámbito SEO para automatizar procesos o profundizar en ciertos ámbitos como el web scraping o el uso de APIs. He trabajado en proyectos SEO de muy diferente tamaño y sector lo que me permite obtener una perspectiva 360º de cómo trabajarlo.

1 comentario en «Optimizar el SEO On Page en bulk con Python»

  1. Añex , excelente trabajo, voy a poner en funcionamiento este colab y a tunear!

    Gracias Bro.

    PSDTA: Te dejo mi mail para tener todas tus publicaciones

    Responder

Deja un comentario