Sari la conținut

Date despre backlink-uri în format JSON: $100 credit gratuit, fără card, autentificare cu Google.

SEOMasters.dev
SEOMasters.devÎnregistrare

DR în bloc pentru o listă de clienți, ca un job Python de 40 de linii

Ai un spreadsheet cu domenii și un dashboard care are nevoie de un număr pe rând. Un verificator de domenii backlink pentru acea sarcină este în mare parte infrastructură, iar acest script este infrastructura.

Mâini care sortează blocuri de lemn în stive pe o banc de lucru

Scriptul

Citește domains.txt, trimite 200 de domenii per cerere, păstrează fiecare răspuns brut în SQLite și afișează cât a costat rularea. Stocăm întregul payload deoarece numele câmpurilor sunt cele mai bine copiate dintr-un răspuns real, nu dintr-un articol de blog.

python
import os, sqlite3, time, json, requests

BASE = "https://seomasters.dev/api.php"
KEY = os.environ["SEO_API_KEY"]
BATCH = 200

db = sqlite3.connect("dr.db")
db.execute("create table if not exists raw (ts int, batch text, body text)")

domains = [d.strip() for d in open("domains.txt") if d.strip()]
spent = 0
for i in range(0, len(domains), BATCH):
    chunk = domains[i:i + BATCH]
    for attempt in range(4):
        try:
            r = requests.get(BASE, timeout=30,
                params={"action": "bulk_dr", "domains": ",".join(chunk)},
                headers={"Authorization": "Bearer " + KEY})
            break
        except requests.RequestException:
            time.sleep(2 ** attempt)
    else:
        raise SystemExit(f"network gave up at batch {i}")
    if r.status_code in (401, 402):
        raise SystemExit(f"HTTP {r.status_code}: fix the key or top up, do not retry")
    body = r.json()
    if not body.get("ok"):
        raise SystemExit(f"ok=false at batch {i}: {json.dumps(body)[:300]}")
    db.execute("insert into raw values (?,?,?)", (int(time.time()), str(i), r.text))
    db.commit()
    print(body.get("_credits"))

Ce face fiecare parte

action=bulk_dr

Un credit per apel. Limita documentată este de 2,000 de domenii per apel.

domains=

Un parametru GET aici. Endpointul acceptă și un body POST, care este alegerea mai bună odată ce listele devin lungi. Testează separatorul cu două domenii înainte de un rul complet.

BATCH = 200

Obișnuința noastră, nu o limită: 200 de domenii scurte mențin URL-ul mult sub limitele comune ale proxy-urilor.

_credits

Prezent pe răspunsurile autentificate: costul apelului și ce mai rămâne. Afișarea lui la fiecare batch este cea mai ieftină urmă de audit.

Coloana brută body

O parsi mai târziu, o singură dată, pe baza unui eșantion stocat. O modificare de schema din partea noastră îți costă atunci o interogare, nu un rerun.

Cântar de alamă care echilibrează greutăți pentru a arăta calculul precis

Un rul ipotetic, cu aritmetica

Acesta este un exemplu, nu o poveste de client. Imaginează-ți o agenție care urmărește 1,800 de domenii de clienți și prospecte într-un Google Sheet și dorește actualizarea DR în fiecare luni.

La 200 de domenii per batch, sunt 9 cereri. Nouă cereri la 1 credit fiecare înseamnă 9 credite, sau $0.0009 per rul, iar peste 52 de luni totalul este de 468 credite, ceea ce se rotunjește la sub cinci cenți.

Costul nu este constrângerea. Proaspătimea este. Indexul se reconstruiește aproximativ lunar, astfel încât rulările săptămânale vor arăta aceleași valori de trei săptămâni din patru, iar un rul lunar captează aceeași mișcare pentru aproximativ o pătrime din apeluri.

Așa că ruleaz-o lunar și păstrează foaia săptămânală pentru editări umane. Detalii despre de ce scorul poate sta nemișcat sunt în referința DR.

Ceea ce merge greșit în acest script

SimptomCauzăRemediu
SystemExit: HTTP 402Soldul este zeroCompletează de pe pagina de cont, rulează din nou; batch-urile finalizate sunt deja în SQLite
SystemExit: HTTP 401Var de mediu gol sau greșeală de tastare a cheiiAfișează len(KEY) și verifică prefixul sk_
ok=false pe batch 3Valoare greșită în listă, cum ar fi un URL completElimină schemele și calea înainte de trimitere, vezi tabelul de erori
Același DR ca săptămâna trecutăIndexul nu s-a reconstruit încăAșteptat; compară lunar
URL lung respinsBatch prea mare pentru GETScade BATCH sau mută la un body POST

Dimensiunea batch-ului, GET și POST pentru liste lungi

Limita este de 2,000 de domenii per apel, iar scriptul trimite o zecime din aceasta. Fiecare apel costă același credit fix, astfel încât dimensiunea batch-ului este o întrebare de eșec și payload, nu de preț.

De ce 200 și nu 2,000

Un batch mai mic eșuează ieftin. Dacă un rul se oprește la mijloc, coada lăsată de refăcut este lungă de un batch, nu de o listă întreagă.

Listele mai scurte mențin, de asemenea, fiecare body stocat suficient de mic pentru a fi scanat cu ochiul liber când un număr pare greșit, iar asta contează mai mult decât câteva apeluri salvate.

Dacă mai târziu majori dimensiunea batch-ului, fă-o o dată, într-o singură constantă, și rulează din nou testul cu două domenii. Un număr mai mare nu este un motiv să sari peste test.

Planifică batch-ul în funcție de durata rulării pe care o poți tolera, nu în funcție de limită. Un job nocturn care trebuie să se termine înainte de un raport de dimineață poate permite batch-uri mai mici și mai sigure decât un backfill ocazional.

GET pentru liste scurte, POST pentru cele lungi

Formularul GET plasează fiecare domeniu în URL. Acest lucru funcționează până când un proxy sau o linie de jurnal trunchiază interogarea, motiv pentru care tabelul de mai sus recomandă reducerea lotului mai întâi. Odată ce listele cresc, trimiteți aceeași valoare domains într-un corp POST.

Testați separatorul și codificarea cu două domenii înainte de un rulaj complet. O virgulă reziduală apare în primul lot, iar este mai ieftin să o observați acolo.

Un corp POST menține, de asemenea, lista în afara jurnalelor de acces pe care multe gazde le păstrează în mod implicit. Acesta este un mic câștig de confidențialitate pentru listele de clienți și costă o linie suplimentară de antet în script.

Când treceți la POST, păstrați versiunea GET a scriptului ca soluție de rezervă pentru listele scurte. Două căi de cod par grele, dar o singură funcție mică care alege una în funcție de lungime este ușor de citit și de testat.

Tăiați și eliminați duplicatele înainte de prima solicitare

Îndepărtați spațiile albe, convertiți gazda în litere mici și eliminați duplicatele înainte ca orice să părăsească mașina dumneavoastră. Duplicatele ocupă spațiu sub plafonul de 2.000 de domenii și fac ca numărul din foaia dumneavoastră să difere de numărul din răspuns.

Alegeți o regulă pentru www. și aplicați-o într-o singură funcție, astfel încât același site să nu fie căutat niciodată sub două scrieri. Orice verificator de backlinks care scalează dincolo de câteva sute de nume are nevoie de această disciplină.

Ce ar trebui să spună jurnalul de rulaj

Afișați valoarea _credits după fiecare lot și scrieți numărul lotului, numărul de domenii și timpul alături de acesta. Aceste trei numere răspund la aproape toate întrebările pe care un cititor financiar le-ar avea despre un rulaj.

Un rulaj care nu afișează nimic până la final nu vă oferă niciun indiciu când se blochează. O linie per lot este ieftină și transformă un blocaj silențios într-un număr de lot pe care îl puteți identifica.

Păstrați jurnalul în același folder cu fișierul SQLite, astfel încât o singură copie de rezervă să copieze ambele. Un jurnal care se află în alt loc este cel care dispare în timpul unui incident.

Îmbinare de lemn finită, separată de lemnul brut

Trei extensii care merită după-amiaza

Stocați numărul lotului alături de timestamp. Este deja în tabelul de mai sus și vă permite să reluați doar lotul care a eșuat după un 402 în timpul rulajului.

Scrieți o vizualizare mică peste tabelul brut odată ce ați inspectat un răspuns real: domeniu, scor, preluat-la. Panourile de bord citesc vizualizarea, iar coloana brută rămâne ca dovada dumneavoastră dacă un număr este pus la îndoială vreodată.

Rulați-l din GitHub Actions sau de la un cron simplu pe un VPS mic. Orice este bine. Ceea ce contează este că jobul iese cu cod non-zero în cazul oricărei eșecuri, deoarece un eșec silențios arată ca un grafic învechit peste trei săptămâni.

Sortarea ieșirii este o problemă de front-end. Clasificați portofoliul în funcție de scor, grupați-l sau comparați-l cu dr_distribution (1 credit) pentru a vedea unde se află fiecare client printre toate cele 181.132.097 de domenii.

Deriva câmpurilor și tabelul brut

Un job pe termen lung eșuează silențios când un câmp își schimbă forma. Coloana brută este acolo pentru ca eșecul să fie zgomotos și ieftin de reparat.

Stocați mai întâi corpul brut

Coloana brută este plasamentul de siguranță. Dacă un câmp este redenumit sau apare unul nou, reluați o interogare peste răspunsurile stocate în loc să plătiți pentru întreaga listă din nou. Analiza ulterioară este ieftină, în timp ce re-cumpărarea nu este.

Păstrați un eșantion salvat pe săptămână într-un fișier separat, de asemenea. Când o analiză se strică, comparați eșantionul acestei săptămâni cu ultimul care a funcționat.

Scrieți corpul exact așa cum a fost primit, fără formatare estetică și fără tăiere. Orice modificare faceți textului înainte de a-l stoca este o modificare pe care nu o puteți anula ulterior.

Cum arată o deriva în practică

Să presupunem că un panou de bord arată dintr-o dată scoruri goale pentru un lot. Rândul brut este încă acolo. Deschideți-l, comparați cheile acestuia cu eșantionul din săptămâna trecută și găsiți diferența în câteva minute.

Repararea constă apoi într-o singură linie în vizualizare, nu în reluarea întregii liste. Acesta este întregul punct de stocare a corpului.

Păstrați o notă scurtă lângă vizualizare spunând câmpul pe care îl citește și când l-ați verificat ultima dată împotriva unui răspuns real. Nota durează un minut să fie scrisă și salvează o căutare lungă ulterior.

Ordonați migrațiile cu datele

Creați tabelul brut înainte de vizualizare, și vizualizarea înainte de orice interogare de panou de bord. Păstrați declarațiile de creare într-un singur fișier, rulați-le în ordine și înregistrați numărul lotului cu fiecare rând.

Bazele de date separate per client derivă în același mod în care face o singură bază de date partajată. Regula rămâne aceeași: un corp stocat per apel și un singur loc pentru a-l analiza.

Păstrați parserul lângă teste

Puneți funcția de analiză în același depozit cu un test care citește un corp salvat. Testul este locul unde un câmp derivat apare prima dată, mult înainte ca un grafic să o facă.

Numiți câmpurile pe care le așteaptă parserul într-o constantă lângă partea de sus a fișierului. Un revizor poate vedea astfel toate dependențele de forma răspunsului pe un singur ecran.

Primul rulaj, în ordine

  1. 1

    Testați un domeniu

    Apelați bulk_dr cu un singur domeniu pe care îl cunoașteți și citiți întregul răspuns. Notați cheile înainte să scrieți orice cod de analiză.

  2. 2

    Rulați două loturi

    Dați scriptului o listă de 400 de domenii, astfel încât să ruleze exact două loturi. Verificați că scăderea _credits se potrivește cu două apeluri la un credit fiecare.

  3. 3

    Numărați rândurile stocate

    Deschideți fișierul SQLite și comparați numărul de rânduri cu numărul loturilor. O neconcordanță înseamnă că un lot a fost omis sau stocat de două ori, și aflați acest lucru înainte ca panoul de bord să o facă.

  4. 4

    Programați lista completă

    Doar după ce testele curg corect, adăugați lista completă și programatorul. Păstrați ieșirea non-zero, astfel încât un eșec să fie zgomotos în prima noapte.

Înainte să îl programați

  • Eliminați duplicatele și convertiți în litere mici lista mai întâi
  • Decideți o dată, într-o singură funcție, dacă www. rămâne sau dispare
  • Păstrați cheia într-un depozit de secret, nu în crontab
  • Alertați pe un cod de ieșire non-zero
  • Rulați numerele bugetului de credite pentru volumul dumneavoastră