Wekelijkse backlink-snapshots via GitHub Actions: een actie-rapportage
Doel: elke maandag schrijft een workflow de verwijzende domeinen en ankers van die dag naar de repository. Niets anders. Diffen komt later.
Redactieteam van Linkzoid ·
Voordat je begint
Je hebt een repository, een Linkzoid-sleutel opgeslagen als de variabele LZ_KEY, en één domein dat je bezit. Budget: ongeveer 6 credits per doelwit per run, wat $0.0006 is. Een snapshot is een feit over één maand, dus wekelijkse runs halen meestal dezelfde index opnieuw op. Het instellen van deze manier om backlinks naar mijn website te controleren kost één avond.
De actie-rapportage, in volgorde
01
1. Voeg de variabele toe
Repo-instellingen, dan 'Secrets and variables', dan 'Actions'. Geef het de naam LZ_KEY. Als je het in het workflow-bestand plakt, draai dan de sleutel om.
02
2. Commit het script
Sla de onderstaande Python op als snap.py. Het schrijft data/YYYY-MM-DD/refdomains.json en faalt bij elke respons waarbij ok false is.
03
3. Commit de workflow
Gebruik de onderstaande YAML. Voer het een keer handmatig uit met de trigger workflow_dispatch en lees het log voordat je het schema vertrouwt.
04
4. Controleer het eerste bestand
Open de JSON. Controleer het aantal rijen tegen total en vergelijk het aantal met wat de gratis overview-aanroep rapporteert voor jouw domein.
05
5. Voeg de waarschuwing toe
Een gefaalde taak e-mailt standaard de repo-eigenaar. Laat dat aan staan. Een taak die stil stopt, is de gebruikelijke manier waarop deze setup faalt.
snap.py
Standaardbibliotheek. De lus eindigt op het aantal, nooit op een gok.
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 in GitHub draait in UTC en kan vertraagd starten als de runners druk zijn. Bouw niets dat afhankelijk is van de minuut.
De sleutel staat in de repo-secrets, en de YAML verwijst er alleen naar via de naam.
Het workflow-bestand staat op de standaardtak, omdat dat de kopie is die het schema leest.
Een handmatige run met workflow_dispatch is klaar en heeft één map met datum geschreven.
Het aantal rijen in het bestand komt overeen met het totaal dat de API voor die aanroep teruggeeft.
De taak stopt met een niet-nul exit-code bij een slechte respons, zodat een fout de run rood maakt.
Fouten en oplossingen
Wat als eerste kapotgaat bij een geplande backlink-taak
Fout
Wat je ziet
Oplossing
Sleutel geplakt in de YAML
Sleutel zichtbaar in repo-geschiedenis
Draai de sleutel om, verplaats hem naar secrets.LZ_KEY
Afwijkende minuut zoals 0 0
Run start 20 minuten te laat
Kies 17 6; het begin van het uur is druk
Repo 60 dagen inactief
GitHub pauzeert het schema
Commit iets, of schakel het opnieuw in via het tabblad Acties
Lus stopt alleen bij een lege pagina
Eindeloze run bij de paginacap
Stop ook wanneer len(rows) >= total
Exit-code genegeerd
Groen vinkje, lege map
Gebruik sys.exit bij ok: false
Commit faalt bij geen wijziging
Rode run voor niets
Voeg || exit 0 toe na de commit
De sleutel en de repo veilig houden
De sleutel is het enige dat in deze setup beschermd moet worden. Behandel het als een wachtwoord, want iedereen die het heeft, kan je saldo uitgeven.
Geplande taken lekken stilweg. Een sleutel geplakt in een log, een workflow gekopieerd naar een publieke repo, of een voormalige teamgenoot met write-toegang zijn de gebruikelijke routes. Controleer elk kwartaal één keer.
Draai de sleutel om als iemand vertrekt
Als een teamgenoot met toegang vertrekt, maak je een nieuwe sleutel, update je de variabele en maak je de oude sleutel ongeldig. Controleer daarna of de volgende run slaagt. Één groene run na de wijziging is de goedkoopste test die je het hele jaar doet. Schrijf de datum van de rotatie ook in de repo-notities, zodat de volgende rotatie geen verrassing is.
Beperk wie het workflow-bestand kan bewerken
Iedereen die de YAML kan bewerken, kan de variabele afdrukken in een run. Houd write-toegang kort en review wijzigingen in het workflow-bestand zoals je code reviewt. Twee mensen met write-toegang is meestal genoeg voor een kleine repo.
Druk de request-URL nooit af
Druk het saldo en het aantal rijen af, nooit de request-URL. De sleutel reist in de querystring, dus een debugregel die de URL afdrukt, schrijft de sleutel in de log. Als je een request in een issue moet delen, vervang de sleutel dan eerst door een placeholder.
Wat de snapshot wel en niet is
Wat je krijgt is een maandbeeld. Onze eigen crawler vernieuwt de index ongeveer één keer per maand, dus twee maandagruns in dezelfde maand leveren vaak dezelfde rijen op. Dat is verwacht.
Een wekelijkse cyclus werkt. Het houdt de gewoonte levend en je vangt een falende taak binnen zeven dagen in plaats van dertig. Als een link die je op dinsdag hebt gebouwd op maandag ontbreekt, wacht dan op de volgende vernieuwing voordat je in paniek raakt.
Als je drie of vier mappen met datum hebt, ga dan verder naar de SQLite-diff. Als je vastzit aan een hardnekkige responscode, lijst de rate-limit-tabel op wat elke status betekent voor een lus.
Houd de eerste map als baseline. Elke latere vergelijking wijst terug naar deze map, en een map die met een datum is genoemd, is veel betrouwbaarder dan een herinnering aan hoe de ergetallen er vorige lente uitzagen. Blijf consequent.
Ankers en top pagina's toevoegen
Één actie per bestand houdt diffs leesbaar. Kopieer de lus in snap.py, verander refdomains in anchors of toppages, en schrijf naar een tweede bestandsnaam. Elk kost 2 credits.
Een gecombineerd bestand verbergt welk deel is gewijzigd, en een reviewer die door een pull request scrolt, wil één concept per diff zien. Houd ze gescheiden. Als je drie domeinen bijhoudt, loop dan over een korte lijst in de workflow met een matrix, zodat elk doelwit zijn eigen taak en eigen fout krijgt.
Ankers zijn een tweede bestand met hun eigen cap in de diff, dus review ze apart van de verwijzende domeinen. Elke run blijft goedkoop en herhaalbaar, wat het hele idee is.
De run-log lezen
Open de log van de eerste run. Doe dit voordat je het schema vertrouwt. Kijk naar het aantal rijen, het saldo en de commitregel. Als een van de drie ontbreekt, heeft de taak minder gedaan dan ze beweegt. Houd ook een korte notitie bij van het saldo bij elke run, zodat de maandelijkse uitgaven zichtbaar zijn zonder het dashboard te openen.
Een groen vinkje zegt weinig. Het betekent alleen dat het proces netjes is afgesloten. Het zegt niet dat het bestand de juiste rijen bevat, vandaar dat het script zijn eigen samenvatting afdrukt. Houd die samenvattingsregels tussen versies van het script ongewijzigd, zodat een diff van twee logs alleen echte wijzigingen laat zien.
Hoe een gezonde log eruitziet
E gezonde run drukt één regel af met het aantal rijen en het credit-saldo, gevolgd door een commit met de datum van vandaag. Alles wat deze regels onder extra ruis begraaft, is het waard om een tweede keer te bekijken.
Een stille fout signaleren
Let op een lege map, een commit die nooit verschijnt, of een aantal rijen dat verschilt van het totaal. Elk van deze wijst naar de lus of de parse, niet naar de API zelf. Sla de eerste gezonde log op als referentie voor latere vergelijkingen.
Sommige fouten laten een map achter met minder rijen dan normaal. Vergelijk het aantal met de vorige week voordat je een groene run viert, want een stille truncatie ziet er precies hetzelfde uit als een stille maand.
Een tweede doelwit veilig toevoegen
Een tweede domein is een matrixvermelding, geen kopie van de hele workflow. Geef elk doelwit zijn eigen taak, zodat één fout een andere niet verbergt. Houd elke taak apart. Controleer of de paden de domeinnaam bevatten, zodat twee runs nooit naar hetzelfde bestand schrijven.
Begin met alleen het tweede doelwit. Zodra de map er goed uitziet, voeg je de rest toe. Een matrix die halverwege faalt, is moeilijker te lezen dan twee eenvoudige runs.
Mappen vernoemen naar doelwit
Zet het domein in het pad, bijvoorbeeld data/<domain>/YYYY-MM-DD, en de mappen blijven gescheiden, zelfs als twee taken in dezelfde minuut draaien. Oude mappen kunnen waar ze zijn blijven staan, omdat een datum in het pad ze makkelijk vindbaar maakt.
Gebruik dezelfde naamgevingsregel voor elk doelwit. Een script kan de mappen dan opsnoepen zonder speciale gevallen.
Plan het credit-budget eerst
Vermenigvuldig de calls per doelwit met het aantal doelwitten, en controleer het totaal tegen je saldo voordat je de eerste run start. Een matrix vermenigvuldigt de uitgaven net zo snel als het de taken vermenigvuldigt. Schrijf het verwachte maandtotaal in de repo naast de workflow. Als het saldo sneller daalt dan dat, haalt een lus waarschijnlijk pagina's opnieuw op, en kun je het stoppen voordat de volgende run start.
Vragen die in de eerste week opkomen
Kan ik dit op een private repo gratis draaien?
Meestal ja, binnen de maandelijkse minuten die GitHub gratis accounts geeft. Een snapshot-taak duurt minder dan een minuut, dus een wekelijkse schema gebruikt een klein aandeel. Controleer de huidige toelage van je eigen plan, omdat GitHub dit van tijd tot tijd verandert.
Waar moet de sleutel staan als meerdere mensen pushen?
In een organisatie- of repository-variabele, nooit in de bestanden. Iedereen die het workflow-bestand kan bewerken, kan een variabele afdrukken in een log, dus beperk wie write-toegang heeft, en draai de sleutel om als iemand het project verlaat.
Waarom mijn geplande run niet is gestart?
Drie gebruikelijke redenen. Het workflow-bestand staat niet op de standaardtak, de repo was 60 dagen inactief en GitHub heeft het schema gepauzeerd, of de cron-string heeft een typefout. Voer het een keer uit met workflow_dispatch om de script zelf uit te sluiten.
Hoe groot worden de datamappen?
Klein. Duizend verwijzende domeinen is een paar honderd kilobytes aan JSON. Een jaar aan wekelijkse bestanden voor één domein blijft ruim onder de honderd megabytes, wat prima is voor git, hoewel je oudere mappen kunt comprimeren als dat je stoort.