Backlinks finder in Python: een prospectlijst in veertig regels
Vind domeinen die naar je concurrenten linken, maar niet naar jou, score ze in één call en sorteer de CSV. Een uitgewerkt voorbeeld met hypothetische cijfers staat hieronder.
Redactieteam van Linkzoid ·
De logica voor de code
Drie calls doen het werk. intersect neemt twee tot tien domeinen en retourneert wie naar meerdere van hen linkt. refdomains op je eigen site geeft de set om af te trekken. bulk_dr scoort vervolgens wat er overblijft.
De kosten per run zijn minimaal en de rekenkunde is het waard om één keer te doen. Twee credits voor de intersect, twee voor je eigen lijst, één voor het scoren van maximaal 2.000 domeinen. Vijf credits is $0.0005.
Volgorde doet ertoe. Trek af voordat je scoort.
Mensen scoren vaak eerst alles en filteren later. Dat is omgedraaid. Scoren kost weinig, maar het kost veel tijd als de CSV vijftigduizend rijen bevat. Knip de lijst eerst terug door overlap, vraag DR aan de overlevenden en houd het geheel in een gewone dict zodat een tweede run het resultaat van gisteren kan hergebruiken.
prospects.py
Domeinen in RIVALS zijn placeholders. Veldnamen worden gelezen met .get, dus controleer één ruwe rij van je eigen run voordat je je op een kolom verlaat.
python
import csv, json, os, urllib.request as u, urllib.parse as p
KEY = os.environ['LZ_KEY']
ME = 'mysite.example'
RIVALS = ['rival-a.example', 'rival-b.example', 'rival-c.example']
def get(**kw):
q = p.urlencode(kw)
with u.urlopen(f'https://linkzoid.pro/api.php?{q}&key={KEY}', timeout=30) as r:
d = json.load(r)
if not d['ok']:
raise SystemExit(d)
return d
gap = get(action='intersect', q=','.join(RIVALS), per=1000)['rows']
mine = {r.get('domain') for r in get(action='refdomains', q=ME, per=1000)['rows']}
fresh = [r.get('domain') for r in gap if r.get('domain') not in mine]
scores = get(action='bulk_dr', domains=','.join(fresh[:2000]))['rows']
with open('prospects.csv', 'w', newline='') as f:
wr = csv.writer(f)
for row in scores:
wr.writerow([row.get('domain'), row.get('dr')])
print(len(fresh), 'candidates')
Uitgewerkt voorbeeld, hypothetische cijfers
Verzonnen run voor een kleine niche blog; die van jou zal verschillen
Stap
Rijen uit
Credits
intersect van 3 concurrenten
640 domeinen
2
Minus je eigen verwijzende domeinen
410 over
2
bulk_dr op de 410
410 gescoord
1
Houd DR 20 en hoger
ongeveer 120
0
Handmatig controleren van de top 30
30 pagina's geopend
0
Van CSV naar outreach, zonder spammen
01
Sorteren op overlap
Domeinen die naar twee of drie van je concurrenten linken, zijn degenen met een inhoudelijke reden om naar jou te linken. Zet ze op de eerste plaats.
02
Dertig handmatig openen
Kijk naar de pagina die naar de concurrent linkt. Is het een resourcelijst, een review, een nieuwsitem? Alleen sommige accepteren een nieuwe entry.
03
Schrijf één regel reden
Zeg wat jouw pagina toevoegt dat de pagina van de concurrent niet heeft. Als je het niet in één zin kunt zeggen, sla die site dan over.
04
Log wat je hebt verzonden
Voeg kolommen toe voor datum, contact en resultaat aan dezelfde CSV en commit het. Volgend kwartaal zult je jezelf bedanken.
Fouten en fixes
Prospecting scripts gaan op dezelfde paar plekken fout
Fout
Waarom het pijn doet
Fix
Sorteren op alleen DR
Grote directories en scrapers komen naar boven
Sorteer eerst op overlap, daarna op DR
Alles mailen boven een cutoff
Leest als spam, kost goodwill
Open de top 30 handmatig
URL-encoderen handmatig
Komma's en slashes breken de query
Gebruik urllib.parse.urlencode
3.000 domeinen in één call versturen
Boven de limiet van 2.000
Chunk de lijst, één credit per chunk
DR vertrouwen als kwaliteit
Het is een log-schaal telling van verwijzende domeinen
Behandel het als een sorteerkey, geen oordeel
Kiezen van concurrenten die je lezer delen
Concurrenten bepalen wat de intersect retourneert. Een backlinks finder is zo goed als de lijst die je hem voert. Drie directe concurrenten voor dezelfde lezer geven een schone overlap, terwijl een grote publisher die op alles rankt je duizenden links geeft die niets over jouw pagina zeggen.
Stel dat je een kleine blog runt over fietsreparatie. Je concurrenten kunnen twee reparatieblogs en één winkel met een sterke gidsen-sectie zijn. Dat is een goede set. Voeg een nationaal medium toe en de lijst vult zich met pagina's die nooit naar een fietsblog zouden linken.
Twee tot tien domeinen is het venster dat het endpoint accepteert, dus kies de set binnen dat bereik. Houd de lijst kort genoeg zodat je elke concurrent uit je hoofd kunt noemen. Korte lijsten zijn makkelijker te verdedigen.
Waarom grote hubs de set verontreinigen
Directories en aggregators linken bijna aan alles. Ze verschijnen in elke intersect en begraven het handvol domeinen dat uit echte interesse naar buiten linkt. Lees de bovenkant van de gesorteerde lijst voordat je het vertrouwt.
Een eenvoudige exclusielijst lost het meeste van dit op. Houd de domeinen die je nooit wilt hebben in één tekstbestand, één per regel. Laad het in een set en verwijder matches voordat de scoring call, zodat credits alleen naar kandidaten gaan die het waard zijn om te lezen.
Concurrenten en je eigen site gescheiden houden
Je eigen domein zou nooit een concurrent moeten zijn. Het klinkt voor de hand liggend, maar een gekopieerde lijst van een oud project neemt het vaak mee, en dan rapporteert de intersect je eigen links naar jezelf.
Zet de concurrenten in een config dict bovenaan het script, met een commentaar waarom elke er één is. Volgende maand weet je de reden nog, en een vreemde die de repo leest ook.
De ruwe rijen lezen voordat je filtert
De code leest elk veld met .get, wat voorkomt dat een missende key de run crasht. Het verbergt ook een verkeerde key. Print één rij van de intersect voordat je een filter schrijft, en kijk naar de veldnamen en het type van elke waarde.
Een score die als tekst aankomt, sorteert als tekst, dus 9 komt na 80. Zet het om naar een nummer direct na de call, en de rest van het script kan eenvoudig blijven.
Normaliseer domeinen voordat je vergelijkt
Hetzelfde domein kan verschijnen met een www. prefix in de ene lijst en zonder in de andere. Maak alles lowercase en verwijder het prefix voordat je sets vergelijkt. Anders kan je eigen site eruitzien als een nieuwe kandidaat.
Trailing slashes en losse spaties van een geplakte lijst veroorzaken dezelfde problemen. Een eenregelige cleanup functie kost minder dan één verspilte scoring call.
Houd een gedateerde kopie van elke run
Schrijf elke run naar een gedateerd bestand en bewaar de vorige. Je kunt dan nieuwe kandidaten onderscheiden van die je al zag, en zien wanneer een concurrent ergens nieuw naar linkt.
Gedateerde bestanden zijn ook de makkelijkste manier om een vreemd resultaat te debuggen. Open de twee bestanden naast elkaar en het verschil is meestal duidelijk.
Score alleen wat overleeft
De bulk call neemt maximaal 2.000 domeinen in één credit. Geef hem de overlevenden van de aftrek, nooit de volledige intersect. In het verzonnen voorbeeld hierboven kosten 640 rijen en 410 rijen hetzelfde om in één call te scoren, maar de kleinere lijst is veel makkelijker te lezen.
Vragen voordat je de finder runt
De meeste vragen die mensen naar dit deel van de job brengen, komen neer op kosten, sorteren en wat er gebeurt als een call faalt.
Kost een prospectlijst veel om te bouwen?
Niet veel. Het recept gebruikt intersect, refdomains en bulk_dr, dus vijf credits per run in de getoonde grootte, wat $0.0005 is. Een rerun volgende maand kost hetzelfde. Je eigen tijd, besteed aan het lezen van pagina's, is de echte kosten.
Waar niet de intersect sorteren op DR en daar stoppen?
DR telt verwijzende domeinen op een log-schaal. Grote directories komen naar boven ongeacht hun relevantie, dus sorteer eerst op overlap en gebruik DR als tie breaker, niet de hoofdkey.
Kan ik outreach sturen naar alles in de CSV?
Dat kan, maar het is een slecht gebruik van de lijst. Open de pagina die naar de concurrent linkt, beslis of een nieuwe entry past, en schrijf pas daarna. De CSV is een shortlist, geen mailing list.
Hoeveel concurrenten moet ik beginnen met?
Drie is een goed begin, binnen het twee tot tien bereik dat de intersect accepteert. Voeg er alleen meer toe als de eerste run te weinig rijen retourneert om te ranken.
Wat als mijn eigen domein nog geen verwijzende domeinen heeft?
Dan verwijdert de aftrek niets, en wordt elke intersect rij een kandidaat. Dat is correct, maar de lijst zal lang zijn. Knip hem terug door overlap en lees de top dertig handmatig.
Heeft het script een betaalde key nodig?
Ja. De intersect, refdomains en bulk_dr calls zijn geprijsd per credit. De gratis overview actie heeft geen key nodig, en de $100 sign-up credit dekt vele runs van deze grootte.
Voordat er een bericht uitgaat
Open de kandidaat pagina en bevestig dat deze naar de concurrent linkt, niet alleen naar een lijst van links.
Controleer of de pagina past bij je lezer, niet alleen bij je keyword.
Verwijder elk domein dat je al hebt benaderd, en log de datum ernaast.
Schrijf één zin over wat jouw pagina toevoegt, of verwijder de kandidaat.
Verstuur in kleine batches, zodat replies daadwerkelijk gelezen kunnen worden.
De finder op een schema runnen
Prospect lijsten verouderen langzamer dan de meeste mensen verwachten. Maandelijks is meer dan genoeg. Nieuwe links van een concurrent verschijnen met de maandelijkse refresh, dus een run elke paar weken vangt de meeste van hen op. Wekelijkse runs reproduceren vooral het bestand van vorige week, daarom kan dezelfde backlinks finder onbeheerd draaien zonder veel lawaai.
Het verstandige ritme is maandelijks voor de scoring en een snelle blik op de bovenste rijen na elke run. Houd de aftreksstap binnen dezelfde job, zodat de lijst nooit bevat wat je al hebt.
De key buiten het bestand houden
Het script leest de key uit de environment, dus deze staat nooit in de repo. Stel LZ_KEY in als een secret in je scheduler, of exporteer het uit een bestand dat buiten git blijft.
Een crontab regel kan hetzelfde script aanroepen met de variabele ervoor ingesteld. Controleer of het bestand dat de key bevat strakke rechten heeft op de server.
Mislukken voordat de CSV wordt geschreven
Een 401 of een 402 moet de run stoppen, en dat geldt ook voor een ok flag die false leest. De code raise voordat het bestand wordt geopend, dus een mislukte run overschrijft nooit de CSV van gisteren met een gedeeltelijke.
Log de uitgave met elke run
Elke response bevat _credits, dus print het saldo aan het einde van de job. Over een paar maanden vertelt die regel je of een schedule kost wat je plande, en of een loop begonnen is pagina's opnieuw op te halen.
Combineer het met de SQLite diff als je de geschiedenis in een database wilt in plaats van een map met bestanden.
Een woord over wat DR wel en niet kan zeggen
DR hier is round(100 keer log(ref_domains + 1) over log(20.000.000)). Het stijgt met verwijzende domeinen en niets anders. Houd dat in gedachten. Een site kan op 55 zitten en toch nutteloos voor je zijn.
Gebruik het om te ranken, lees dan. Kijk naar wat de site publiceert, of het naar honderd ongerelateerde winkels linkt, en of er recent iets aan veranderd is. Die checks kosten een minuut per site, en geen script vervangt ze.
Zodra de lijst schoon is, houd hem dan als een gedateerd bestand en run hem over een maand opnieuw. De Actions runbook laat zien hoe je het kunt plannen, en de n8n vergelijking behandelt de no-code route als je outreach persoon de voorkeur geeft aan die route.
Rate en size notities
Elke call retourneert maximaal 1.000 rijen en wordt één keer gefactureerd, dus door 5.000 intersect rijen bladeren kost 10 credits, of $0.001. Diep bladeren stopt bij 50.000 rijen. Gebruik sort en order=desc op de server in plaats van een grote lijst in Python te sorteren.