DR em massa para uma lista de clientes, como um job Python de 40 linhas
Você tem uma planilha de domínios e um dashboard que precisa de um número por linha. Um verificador de domínios com backlinks para esse trabalho é basicamente infraestrutura, e este script é essa infraestrutura.

O script
Ele lê domains.txt, envia 200 domínios por solicitação, mantém cada resposta bruta no SQLite e imprime o custo da execução. Armazenamos o payload inteiro porque os nomes dos campos são melhor copiados de uma resposta real, não de um post de 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"))O que cada parte está fazendo
action=bulk_dr
Um crédito por chamada. O limite documentado é de 2.000 domínios por chamada.
domains=
Um parâmetro GET aqui. O endpoint também aceita um corpo POST, que é a melhor escolha quando as listas ficam longas. Teste o separador com dois domínios antes de uma execução completa.
BATCH = 200
Nossa prática, não um limite: 200 domínios curtos mantêm a URL bem abaixo dos limites comuns de proxy.
_credits
Presente em respostas autenticadas: o custo da chamada e o que resta. Imprimi-lo a cada batch é o rastro de auditoria mais barato.
Coluna body bruta
Você analisa depois, uma vez, contra uma amostra armazenada. Uma mudança de esquema do nosso lado então custa uma consulta, não uma nova execução.

Uma execução hipotética, com a aritmética
Este é um exemplo, não uma história de cliente. Imagine uma agência que rastreia 1.800 domínios de clientes e prospectos em uma Planilha Google e quer atualizar o DR toda segunda-feira.
A 200 domínios por batch, isso são 9 solicitações. Nove solicitações a 1 crédito cada são 9 créditos, ou $0,0009 por execução, e ao longo de 52 segundas-feiras o total é de 468 créditos, que arredonda para menos de cinco centavos.
O custo não é a restrição. A atualização é. O índice é reconstruído aproximadamente mensalmente, então execuções semanais mostrarão os mesmos valores três semanas em quatro, e uma execução mensal captura o mesmo movimento por aproximadamente um quarto das chamadas.
Então execute mensalmente e mantenha a planilha semanal para edições humanas. Detalhes sobre por que a pontuação pode ficar parada estão na referência de DR.
Coisas que dão errado neste script
| Sintoma | Causa | Correção |
|---|---|---|
SystemExit: HTTP 402 | Saldo zerado | Recarregue na página da conta, execute novamente; batches concluídos já estão no SQLite |
SystemExit: HTTP 401 | Variável de ambiente vazia ou erro de digitação na chave | Imprima len(KEY) e verifique o prefixo sk_ |
ok=false no batch 3 | Valor incorreto na lista, como uma URL completa | Remova esquema e caminho antes de enviar, veja a tabela de erros |
| Mesmo DR da semana passada | O índice ainda não foi reconstruído | Esperado; compare mensalmente |
| URL longa rejeitada | Batch muito grande para GET | Reduza BATCH ou mude para um corpo POST |
Tamanho do batch, GET e POST para listas longas
O limite é de 2.000 domínios por chamada, e o script envia um décimo disso. Cada chamada custa o mesmo crédito fixo, então o tamanho do batch é uma questão de falha e payload, não de preço.
Por que 200 e não 2.000
Um batch menor falha de forma barata. Se uma execução parar no meio, a parte restante a ser refeita tem o tamanho de um batch, não o tamanho de toda a lista.
Listas menores também mantêm cada corpo salvo pequeno o suficiente para ser escaneado a olho nu quando um número parece errado, e isso é mais importante do que algumas chamadas salvas.
Se você aumentar o tamanho do batch mais tarde, faça isso uma vez, em uma constante, e execute o teste com dois domínios novamente. Um número maior não é motivo para pular o teste.
Planeje o batch com base no tempo de execução que você pode tolerar, não no limite. Um job noturno que deve terminar antes de um relatório matinal pode suportar batches menores e mais seguros do que uma recuperação única.
GET para listas curtas, POST para longas
A forma GET coloca todos os domínios na URL. Isso funciona até que um proxy ou uma linha de log trunque a query, é por isso que a tabela acima diz para reduzir o batch primeiro. Quando as listas crescem, envie o mesmo valor de domains em um corpo POST.
Teste o separador e a codificação com dois domínios antes de uma execução completa. Uma vírgula solta aparece no primeiro batch, e é mais barato vê-la lá.
Um corpo POST também mantém a lista fora dos logs de acesso que muitos hosts mantêm por padrão. Isso é um pequeno ganho de privacidade para listas de clientes, e custa uma linha extra de cabeçalho no script.
Quando você mudar para POST, mantenha a versão GET do script como fallback para listas curtas. Dois caminhos de código parecem pesados, mas uma única função pequena que escolhe um pelo comprimento é fácil de ler e fácil de testar.
Limpe e remova duplicatas antes da primeira solicitação
Remova espaços em branco, coloque o host em minúsculas e elimine duplicatas antes que qualquer coisa saia da sua máquina. Duplicatas ocupam espaço sob o limite de 2.000 domínios, e fazem a contagem na sua planilha divergir da contagem na resposta.
Escolha uma regra para www. e aplique-a em uma única função, para que o mesmo site nunca seja consultado sob duas grafias. Qualquer verificador de domínios com backlinks que escale além de algumas centenas de nomes precisa dessa disciplina.
O que o log da execução deve dizer
Imprima o valor de _credits após cada batch, e escreva o número do batch, a contagem de domínios e o tempo ao lado. Esses três números respondem à quase todas as perguntas que um leitor financeiro fará sobre uma execução.
Uma execução que não imprime nada até o final não dá nenhuma pista quando ela trava. Uma linha por batch é barata, e transforma uma suspensão silenciosa em um número de batch que você pode nomear.
Mantenha o log na mesma pasta do arquivo SQLite, para que um backup copie ambos. Um log que fica em outro lugar é o que se perde durante um incidente.

Três extensões que valem a tarde
Armazene o número do batch ao lado do timestamp. Já está na tabela acima, e permite que você reexecute apenas o batch que falhou após um 402 no meio da execução.
Escreva uma pequena visão sobre a tabela bruta assim que inspecionar uma resposta real: domínio, pontuação, data de busca. Dashboards leem a visão, e a coluna bruta permanece como sua evidência se um número for questionado.
Execute-o do GitHub Actions ou de um cron simples em um VPS pequeno. Qualquer um está bom. O que importa é que o job saia com código não-zero em qualquer falha, porque uma falha silenciosa parece um gráfico desatualizado três semanas depois.
Ordenar a saída é uma questão de front-end. Classifique o portfólio por pontuação, agrupe-o ou compare-o com dr_distribution (1 crédito) para ver onde cada cliente está entre todos os 181.132.097 domínios.
Deriva de campos e a tabela bruta
Um job de longo prazo falha silenciosamente quando um campo muda de forma. A coluna bruta está lá para que a falha permaneça visível e barata de corrigir.
Armazene o corpo bruto primeiro
A coluna bruta é a rede de segurança. Se um campo for renomeado ou um novo aparecer, você reexecuta uma consulta sobre respostas armazenadas em vez de pagar pela lista inteira novamente. Analisar depois é barato, enquanto recomprar não é.
Mantenha uma amostra salva por semana em um arquivo próprio também. Quando uma análise falha, você compara a amostra desta semana com a última que funcionou.
Escreva o corpo exatamente como recebido, sem formatação bonita e sem recorte. Qualquer alteração que você faça no texto antes de armazená-lo é uma alteração que você não poderá desfazer depois.
Como uma deriva se parece na prática
Digamos que um dashboard repentinamente mostre pontuações vazias para um batch. A linha bruta ainda está lá. Você a abre, compara suas chaves com a amostra da semana passada e encontra a diferença em poucos minutos.
A correção é então uma única linha na visão, não uma reexecução de toda a lista. Esse é o ponto principal de armazenar o corpo.
Mantenha uma nota curta ao lado da visão dizendo qual campo ela lê e quando você a verificou pela última vez contra uma resposta real. A nota leva um minuto para ser escrita e economiza uma longa busca depois.
Ordene as migrações com os dados
Crie a tabela bruta antes da visão, e a visão antes de qualquer consulta de dashboard. Mantenha as instruções de criação em um arquivo, execute-as na ordem e registre o número do batch com cada linha.
Bancos de dados separados por cliente derivam da mesma forma que um banco de dados compartilhado. A regra permanece a mesma: um corpo armazenado por chamada, e um lugar para analisá-lo.
Mantenha o parser próximo aos testes
Coloque a função de análise no mesmo repositório que um teste que lê um corpo salvo. O teste é o lugar onde um campo derivado aparece primeiro, muito antes de um gráfico.
Nomeie os campos que o parser espera em uma constante próxima ao topo do arquivo. Um revisor pode então ver todas as dependências na forma da resposta em uma única tela.
Primeira execução, em ordem
- 1
Teste um domínio
Chame
bulk_drcom um domínio único que você conhece, e leia toda a resposta. Anote as chaves antes de escrever qualquer código de análise. - 2
Execute dois batches
Dê ao script uma lista de 400 domínios, para que exatamente dois batches sejam executados. Verifique se a queda de
_creditscorresponde a duas chamadas de um crédito cada. - 3
Conte as linhas armazenadas
Abra o arquivo SQLite e compare a contagem de linhas com a contagem de batches. Uma discrepância significa que um batch foi pulado ou armazenado duas vezes, e você descobre isso antes que o dashboard faça.
- 4
Agende a lista completa
Apenas após as execuções de teste limpas, adicione a lista completa e o agendador. Mantenha a saída não-zero, para que uma falha seja visível na primeira noite.
Antes de agendá-lo
- Remova duplicatas e coloque em minúsculas a lista primeiro
- Decida uma vez, em uma função, se
www.permanece ou vai - Mantenha a chave em um armazenamento de segredos, não no crontab
- Alerte sobre um código de saída não-zero
- Execute os números do orçamento de crédito para o seu próprio volume