DR in batch per una lista di clienti, come un lavoro Python di 40 righe
Hai un foglio di calcolo con i domini e una dashboard che richiede un numero per riga. Un controllo dei domini dei backlink per questo lavoro è principalmente un'infrastruttura, e questo script è proprio quell'infrastruttura.

Lo script
Legge domains.txt, invia 200 domini per richiesta, salva ogni risposta grezza in SQLite e stampa il costo della esecuzione. Salviamo l'intero payload perché i nomi dei campi sono meglio copiati da una risposta reale, non da un post sul blog.
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"))Cosa fa ogni parte
action=bulk_dr
Un credito per chiamata. Il limite documentato è di 2.000 domini per chiamata.
domains=
Un parametro GET qui. L'endpoint accetta anche un corpo POST, che è la scelta migliore quando le liste diventano lunghe. Testa il separatore con due domini prima di un'esecuzione completa.
BATCH = 200
La nostra abitudine, non un limite: 200 domini brevi mantengono l'URL ben al di sotto dei limiti comuni dei proxy.
_credits
Presente nelle risposte autenticate: il costo della chiamata e quanto rimane. Stamparlo ogni batch è la traccia di audit più economica.
Colonna body grezza
Lo analizzi in seguito, una volta sola, contro un campione memorizzato. Una modifica allo schema da parte nostra ti costerà una query, non una riesecuzione.

Un'esecuzione ipotetica, con i calcoli
Questo è un esempio, non una storia di un cliente. Immagina un'agenzia che monitora 1.800 domini di clienti e prospect in un Google Sheet e vuole aggiornare il DR ogni lunedì.
A 200 domini per batch sono 9 richieste. Nove richieste a 1 credito ciascuna sono 9 crediti, ovvero $0,0009 per esecuzione, e su 52 lunedì il totale è di 468 crediti, che arrotondati sono meno di cinque centesimi.
Il costo non è il vincolo. La freschezza sì. L'indice si ricostruisce circa mensilmente, quindi esecuzioni settimanali mostreranno gli stessi valori per tre settimane su quattro, e un'esecuzione mensile cattura lo stesso movimento per circa un quarto delle chiamate.
Quindi eseguilo mensilmente e mantieni il foglio settimanale per le modifiche umane. I dettagli sul motivo per cui il punteggio può rimanere fermo sono nel riferimento DR.
Cose che possono andare storte in questo script
| Sintomo | Causa | Soluzione |
|---|---|---|
SystemExit: HTTP 402 | Saldo zero | Ricarica dalla pagina dell'account, riesegui; i batch completati sono già in SQLite |
SystemExit: HTTP 401 | Variabile d'ambiente vuota o errore di battitura nella chiave | Stampa len(KEY) e controlla il prefisso sk_ |
ok=false nel batch 3 | Valore errato nella lista, come un URL completo | Rimuovi schema e percorso prima di inviare, vedi la tabella degli errori |
| Stesso DR della settimana scorsa | L'indice non si è ancora ricostruito | Previsto; confronta mensilmente |
| URL lungo rifiutato | Batch troppo grande per GET | Riduci BATCH o passa a un corpo POST |
Dimensione del batch, GET e POST per liste lunghe
Il limite è di 2.000 domini per chiamata, e lo script invia un decimo di quello. Ogni chiamata costa lo stesso credito fisso, quindi la dimensione del batch è una questione di fallimento e payload, non di prezzo.
Perché 200 e non 2.000
Un batch più piccolo fallisce in modo economico. Se un'esecuzione si interrompe a metà, la coda lasciata da rifare è lunga un batch, non una lista intera.
Liste più brevi mantengono anche ogni corpo salvato abbastanza piccolo da essere scansionato a occhio quando un numero sembra errato, e questo conta più di alcune chiamate salvate.
Se in seguito aumenti la dimensione del batch, fallo una volta sola, in una costante, e riesegui il test con due domini. Un numero più grande non è un motivo per saltare il test.
Pianifica il batch in base alla durata dell'esecuzione che puoi tollerare, non al limite. Un lavoro notturno che deve terminare prima di un rapporto mattutino può permettersi batch più piccoli e più sicuri rispetto a un riempimento una tantum.
GET per liste brevi, POST per quelle lunghe
La forma GET inserisce ogni dominio nell'URL. Questo funziona finché un proxy o una riga di log non tronca la query, motivo per cui la tabella sopra dice di ridurre prima il batch. Una volta che le liste crescono, invia lo stesso valore domains in un corpo POST.
Testa il separatore e l'encoding con due domini prima di un'esecuzione completa. Una virgola stray appare nel primo batch, ed è più economico vederla lì.
Un corpo POST mantiene anche la lista fuori dai log di accesso che molti host tengono di default. Questo è un piccolo guadagno di privacy per le liste di clienti, e costa una riga di intestazione in più nello script.
Quando passi a POST, mantieni la versione GET dello script come fallback per le liste brevi. Due percorsi di codice sembrano pesanti, ma una singola piccola funzione che sceglie in base alla lunghezza è facile da leggere e da testare.
Pulisci e rimuovi i duplicati prima della prima richiesta
Rimuovi gli spazi bianchi, metti in minuscolo l'host e elimina i duplicati prima che qualsiasi cosa lasci la tua macchina. I duplicati occupano spazio sotto il limite di 2.000 domini, e fanno sì che il conteggio nel tuo foglio non corrisponda al conteggio nella risposta.
Scegli una regola per www. e applicala in una singola funzione, in modo che lo stesso sito non venga mai cercato con due grafie diverse. Qualsiasi controllo dei domini dei backlink che scala oltre poche centinaia di nomi ha bisogno di questa disciplina.
Cosa dovrebbe dire il log dell'esecuzione
Stampa il valore _credits dopo ogni batch, e scrivi il numero del batch, il conteggio dei domini e l'ora accanto. Questi tre numeri rispondono a quasi tutte le domande che un lettore finanziario farà su un'esecuzione.
Un'esecuzione che non stampa nulla fino alla fine non ti dà alcun indizio quando si blocca. Una riga per batch è economica, e trasforma un blocco silenzioso in un numero di batch che puoi nominare.
Mantieni il log nella stessa cartella del file SQLite, in modo che un backup copi entrambi. Un log che vive da qualche altra parte è quello che va perso durante un incidente.

Tre estensioni che valgono il pomeriggio
Memorizza il numero del batch accanto al timestamp. È già nella tabella sopra, e ti permette di rieseguire solo il batch che è fallito dopo un 402 a metà esecuzione.
Scrivi una piccola vista sulla tabella grezza una volta che hai ispezionato una risposta reale: dominio, punteggio, data di recupero. Le dashboard leggono la vista, e la colonna grezza rimane come tua prova se un numero viene messo in discussione.
Eseguilo da GitHub Actions o da un semplice cron su un piccolo VPS. Entrambi vanno bene. Ciò che conta è che il lavoro esiti con codice diverso da zero in caso di errore, perché un errore silenzioso sembra un grafico obsoleto tre settimane dopo.
L'ordinamento dell'output è una questione di front-end. Ordina il portafoglio per punteggio, raggruppalo o confrontalo con dr_distribution (1 credito) per vedere dove si trova ogni cliente tra tutti i 181.132.097 domini.
Deriva dei campi e la tabella grezza
Un lavoro a lungo termine fallisce silenziosamente quando un campo cambia forma. La colonna grezza c'è affinché il fallimento rimanga rumoroso e facile da risolvere.
Memorizza prima il corpo grezzo
La colonna grezza è la rete di sicurezza. Se un campo viene rinominato o ne appare uno nuovo, riesegui una query sulle risposte memorizzate invece di pagare per l'intera lista di nuovo. Analizzare in seguito è economico, mentre riacquistare no.
Tieni anche un campione salvato per settimana in un file a parte. Quando un'analisi si interrompe, confronta il campione di questa settimana con l'ultimo che ha funzionato.
Scrivi il corpo esattamente come ricevuto, senza formattazione e senza trimming. Qualsiasi modifica apportata al testo prima di salvarlo è una modifica che non potrai annullare in seguito.
Come appare la deriva nella pratica
Supponiamo che una dashboard mostri improvvisamente punteggi vuoti per un batch. La riga grezza è ancora lì. La apri, confronti le sue chiavi con il campione della settimana scorsa e trovi la differenza in pochi minuti.
La correzione è poi una singola riga nella vista, non una riesecuzione dell'intera lista. Questo è il punto principale dello storage del corpo.
Tieni una breve nota accanto alla vista che dice quale campo legge e quando l'hai controllata l'ultima volta contro una risposta reale. La nota richiede un minuto per essere scritta e risparmia una lunga ricerca in seguito.
Ordina le migrazioni con i dati
Crea la tabella grezza prima della vista, e la vista prima di qualsiasi query della dashboard. Tieni le istruzioni di creazione in un file, eseguile in ordine e registra il numero del batch con ogni riga.
Database separati per cliente derivano allo stesso modo di un database condiviso. La regola rimane la stessa: un corpo memorizzato per chiamata, e un unico punto dove analizzarlo.
Tieni il parser accanto ai test
Metti la funzione di parsing nello stesso repository di un test che legge un corpo memorizzato. Il test è il punto in cui un campo derivato appare per la prima volta, molto prima che lo faccia un grafico.
Nomina i campi che il parser si aspetta in una costante vicino all'inizio del file. Un revisore può così vedere tutte le dipendenze dalla forma della risposta in un'unica schermata.
Prima esecuzione, in ordine
- 1
Testa un dominio
Chiama
bulk_drcon un singolo dominio che conosci, e leggi l'intera risposta. Annota le chiavi prima di scrivere qualsiasi codice di parsing. - 2
Esegui due batch
Fornisci allo script una lista di 400 domini, in modo che vengano eseguiti esattamente due batch. Controlla che la diminuzione di
_creditscorrisponda a due chiamate a un credito ciascuna. - 3
Conta le righe memorizzate
Apri il file SQLite e confronta il conteggio delle righe con il conteggio dei batch. Una discrepanza significa che un batch è stato saltato o memorizzato due volte, e lo scopri prima che lo faccia la dashboard.
- 4
Pianifica la lista completa
Solo dopo che i test sono puliti, aggiungi la lista completa e il scheduler. Mantieni l'uscita non zero, in modo che un errore sia rumoroso dalla prima notte.
Prima di pianificarlo
- Rimuovi i duplicati e metti in minuscolo la lista prima
- Decidi una volta, in una funzione, se
www.rimane o va via - Tieni la chiave in un archivio segreto, non nel crontab
- Allerta su un codice di uscita diverso da zero
- Esegui i numeri del budget di crediti per il tuo volume