Manual de ejecución

Instantáneas semanales de backlinks en GitHub Actions: un manual de ejecución

Objetivo: cada lunes, un flujo de trabajo escribe los dominios de referencia y los anclajes del día en el repositorio. Nada más. La comparación de diferencias vendrá después.

Puente de hierro que cruza un río, simbolizando infraestructura de flujo de trabajo programado fiable
Antes de comenzar

Necesitas un repositorio, una clave de Linkzoid almacenada como el secreto LZ_KEY y un dominio que poseas. Presupuesto: aproximadamente 6 créditos por destino por ejecución, lo que equivale a $0.0006. Una instantánea es un hecho sobre un mes, por lo que las ejecuciones semanales principalmente vuelven a obtener el mismo índice. Configurar cómo verificar los backlinks a tu sitio web de esta manera toma una tarde.

El manual de ejecución, en orden

01

1. Añade el secreto

Configuración del repositorio, luego Secretos y variables, luego Acciones. Nómbralo LZ_KEY. Si lo pegas en el archivo del flujo de trabajo, rota la clave hoy.

02

2. Confirma el script

Guarda el siguiente Python como snap.py. Escribe data/YYYY-MM-DD/refdomains.json y falla ante cualquier respuesta donde ok sea falso.

03

3. Confirma el flujo de trabajo

Usa el siguiente YAML. Ejecútalo una vez manualmente con el activador workflow_dispatch y lee el registro antes de confiar en la programación.

04

4. Verifica el primer archivo

Abre el JSON. Confirma el recuento de filas contra total y compara el número con lo que informa la llamada overview gratuita para tu dominio.

05

5. Añade la alerta

Un trabajo fallido envía un correo electrónico al propietario del repositorio por defecto. Déjalo así. Un trabajo que se detiene silenciosamente es la forma habitual en que estos entornos fallan.

snap.py

Biblioteca estándar. El bucle termina por el recuento, nunca por una suposición.

python
import json, os, sys, datetime, pathlib, urllib.request as u
KEY = os.environ['LZ_KEY']
TARGET = sys.argv[1]
def get(**p):
    q = '&'.join(f'{k}={v}' for k, v in p.items())
    url = f'https://linkzoid.pro/api.php?{q}&key={KEY}'
    with u.urlopen(url, timeout=30) as r:
        return json.load(r)
rows, page = [], 1
while True:
    d = get(action='refdomains', q=TARGET, page=page, per=1000)
    if not d['ok']:
        sys.exit(f'bad response: {d}')
    rows += d['rows']
    if not d['rows'] or len(rows) >= d['total']:
        break
    page += 1
day = datetime.date.today().isoformat()
out = pathlib.Path('data') / day
out.mkdir(parents=True, exist_ok=True)
(out / 'refdomains.json').write_text(json.dumps(rows))
print(len(rows), 'rows, balance', d['_credits'])

.github/workflows/snapshot.yml

Cron en GitHub se ejecuta en UTC y puede iniciarse tarde cuando los runners están ocupados. No construyas nada que dependa del minuto.

yaml
name: backlink-snapshot
on:
  schedule:
    - cron: '17 6 * * 1'
  workflow_dispatch:
jobs:
  snap:
    runs-on: ubuntu-latest
    permissions:
      contents: write
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: '3.12'
      - run: python snap.py example.com
        env:
          LZ_KEY: ${{ secrets.LZ_KEY }}
      - run: |
          git config user.name snapshot-bot
          git config user.email "snapshot-bot@localhost"
          git add data
          git commit -m "snapshot $(date -u +%F)" || exit 0
          git push
Jardinero podando un joven árbol, representando la preparación antes de iniciar la programación

Antes de activar la programación

  • La clave reside en los secretos del repositorio, y el YAML solo la referencia por nombre.
  • El archivo del flujo de trabajo está en la rama predeterminada, porque esa es la copia que lee la programación.
  • Una ejecución manual con workflow_dispatch finalizó y escribió una carpeta con fecha.
  • El recuento de filas en el archivo coincide con el total que devolvió la API para esa llamada.
  • El trabajo sale con código no cero ante una respuesta incorrecta, por lo que un fallo marca la ejecución en rojo.

Errores y soluciones

Qué falla primero en un trabajo programado de backlinks
ErrorLo que vesSolución
Clave pegada en el YAMLClave visible en el historial del repositorioRótala, muévela a secrets.LZ_KEY
Minuto extraño como 0 0La ejecución comienza 20 minutos tardeElige 17 6; la hora en punto está congestionada
Repositorio inactivo durante 60 díasGitHub pausa la programaciónConfirma algo, o re-actívalo en la pestaña Acciones
El bucle se detiene solo en una página vacíaEjecución infinita en el límite de páginasDetente también cuando len(rows) >= total
Código de salida ignoradoCheck verde, carpeta vacíaUsa sys.exit en ok: false
La confirmación falla por no haber cambiosEjecución roja por nadaAñade || exit 0 después del commit

Mantener la clave y el repositorio seguros

La clave es lo único en esta configuración que vale la pena proteger. Trátala como una contraseña, porque cualquiera que la tenga puede gastar tu saldo.

Los trabajos programados filtran silenciosamente. Una clave pegada en un registro, un flujo de trabajo copiado en un repositorio público o un excompañero con acceso de escritura son las rutas habituales. Verifica cada una una vez al trimestre.

Rota la clave cuando alguien se vaya

Cuando un compañero con acceso se vaya, crea una nueva clave, actualiza el secreto y da por retirada la antigua. Luego confirma que la siguiente ejecución pase. Una ejecución verde después del cambio es la prueba más barata que harás en todo el año. Escribe también la fecha de rotación en las notas del repositorio, para que la siguiente rotación no sea una sorpresa.

Limita quién puede editar el flujo de trabajo

Cualquiera que pueda editar el YAML puede imprimir el secreto en una ejecución. Mantén el acceso de escritura breve y revisa los cambios en el archivo del flujo de trabajo como si revisaras código. Dos personas con acceso de escritura suelen ser suficientes para un repositorio pequeño.

Nunca imprimas la URL de la solicitud

Imprime el saldo y el recuento de filas, nunca la URL de la solicitud. La clave viaja en la cadena de consulta, por lo que una línea de depuración que imprime la URL escribe la clave en el registro. Si debes compartir una solicitud en un issue, reemplaza primero la clave con un marcador de posición.

Brújula y planta en maceta, indicando progreso constante y detección temprana de problemas

Qué es y qué no es la instantánea

Lo que obtienes es una foto mensual. Nuestro propio crawler actualiza el índice aproximadamente una vez al mes, por lo que dos ejecuciones de lunes en el mismo mes a menudo devuelven las mismas filas. Eso es esperado.

Una cadencia semanal funciona. Mantiene el hábito vivo y detectas un trabajo fallido en siete días en lugar de treinta. Si un enlace que construiste el martes falta el lunes, espera a la próxima actualización antes de entrar en pánico.

Cuando tengas tres o cuatro carpetas con fecha, pasa a la diferencia de SQLite. Si estás atascado con un código de respuesta testarudo, la tabla de límites de velocidad lista lo que significa cada estado para un bucle.

Mantén la primera carpeta como línea base. Cada comparación posterior apunta hacia ella, y una carpeta nombrada por fecha es mucho más fácil de confiar que el recuerdo de cómo se veían los números la primavera pasada. Mantén la consistencia.

Añadiendo anclajes y páginas principales

Una acción por archivo mantiene las diferencias legibles. Copia el bucle en snap.py, cambia refdomains por anchors o toppages, y escribe en un segundo nombre de archivo. Cada uno cuesta 2 créditos.

Un archivo combinado oculta qué parte cambió, y un revisor que desplaza una solicitud de extracción quiere ver un concepto por diferencia. Manténlos separados. Si rastreas tres dominios, haz un bucle sobre una lista corta en el flujo de trabajo con una matriz, para que cada destino tenga su propio trabajo y su propio fallo.

Los anclajes son un segundo archivo con su propio límite en la diferencia, así que revísalos por separado de los dominios de referencia. Cada ejecución sigue siendo barata y repetible, que es la idea principal.

Leyendo el registro de ejecución

Abre el registro de la primera ejecución. Hazlo antes de confiar en la programación. Busca el recuento de filas, el saldo y la línea de commit. Si falta alguno de los tres, el trabajo hizo menos de lo que afirma. Guarda también una nota breve del saldo en cada ejecución, para que el gasto mensual sea visible sin abrir el panel de control.

Un check verde dice poco. Solo significa que el proceso salió limpiamente. No dice que el archivo contenga las filas correctas, por eso el script imprime su propio resumen. Mantén esas líneas de resumen sin cambios entre versiones del script, para que una diferencia de dos registros muestre solo cambios reales.

Cómo se ve un registro saludable

Una ejecución saludable imprime una línea con el recuento de filas y el saldo de créditos, luego un commit con la fecha de hoy. Cualquier cosa que entierre esas líneas bajo ruido adicional merece una segunda mirada.

Detectando un fallo silencioso

Vigila una carpeta vacía, un commit que nunca aparece o un recuento de filas que difiere del total. Cada uno de estos apunta al bucle o al análisis, no a la API en sí. Guarda el primer registro saludable como referencia para comparaciones futuras.

Algunos fallos dejan una carpadera detrás con menos filas de lo habitual. Compara el recuento con la semana anterior antes de celebrar una ejecución verde, porque una truncación silenciosa se ve exactamente como un mes tranquilo.

Añadiendo un segundo destino de forma segura

Un segundo dominio es una entrada de matriz, no una copia de todo el flujo de trabajo. Asigna a cada destino su propio trabajo para que un fallo no oculte a otro. Mantén cada trabajo separado. Verifica que las rutas incluyan el nombre del dominio, para que dos ejecuciones nunca escriban en el mismo archivo.

Comienza solo con el segundo destino. Una vez que su carpeta se vea correcta, añade el resto. Una matriz que falla a mitad de camino es más difícil de leer que dos ejecuciones simples.

Nombra las carpetas por destino

Pon el dominio en la ruta, por ejemplo data/<domain>/YYYY-MM-DD, y las carpetas permanecen separadas incluso cuando dos trabajos se ejecutan en el mismo minuto. Las carpetas antiguas pueden permanecer donde están, ya que una fecha en la ruta las hace fáciles de encontrar.

Usa la misma regla de nomenclatura para cada destino. Un script puede entonces listar las carpetas sin casos especiales.

Planifica el presupuesto de créditos primero

Multiplica las llamadas por destino por el número de destinos, luego verifica el total contra tu saldo antes de la primera ejecución. Una matriz multiplica el gasto tan rápido como multiplica los trabajos. Escribe el total mensual esperado en el repositorio junto al flujo de trabajo. Cuando el saldo caiga más rápido que eso, probablemente un bucle esté volviendo a obtener páginas, y puedes detenerlo antes de la siguiente ejecución.

Preguntas que surgen en la primera semana

¿Puedo ejecutar esto en un repositorio privado gratis?
Generalmente sí, dentro de los minutos mensuales que GitHub ofrece a las cuentas gratuitas. Un trabajo de instantánea se ejecuta en mucho menos de un minuto, por lo que una programación semanal usa una pequeña parte. Verifica la asignación actual de tu propio plan, porque GitHub la cambia de vez en cuando.
¿Dónde debe vivir la clave si varias personas hacen push?
En un secreto de organización o repositorio, nunca en los archivos. Cualquiera que pueda editar el flujo de trabajo puede imprimir un secreto en un registro, así que limita quién tiene acceso de escritura y rota la clave si alguien abandona el proyecto.
¿Por qué no se disparó mi ejecución programada?
Tres razones habituales. El archivo del flujo de trabajo no está en la rama predeterminada, el repositorio estuvo inactivo durante 60 días y GitHub pausó la programación, o la cadena cron tiene un error tipográfico. Ejecútalo una vez con workflow_dispatch para descartar el script en sí.
¿Qué tamaño tienen las carpetas de datos?
Pequeñas. Mil dominios de referencia son unos pocos cientos de kilobytes de JSON. Un año de archivos semanales para un dominio se mantiene muy por debajo de los cien megabytes, lo cual está bien para git, aunque puedes comprimir las carpetas más antiguas si te molesta.