Aller au contenu

Données de backlinks en JSON : 100 $ de crédit gratuit, sans carte, connexion Google.

SEOMasters.dev
SEOMasters.devS'inscrire

DR en masse pour une liste de clients, en tant que tâche Python de 40 lignes

Vous avez un tableau de domaines et un tableau de bord qui nécessite un nombre par ligne. Un vérificateur de domaine de backlinks pour ce travail consiste principalement en de la tuyauterie, et ce script est cette tuyauterie.

Mains triant des blocs de bois en piles sur un établi

Le script

Il lit domains.txt, envoie 200 domaines par requête, conserve chaque réponse brute dans SQLite et affiche le coût de l'exécution. Nous stockons la charge utile complète car les noms de champs sont mieux copiés à partir d'une réponse réelle que d'un article 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 que fait chaque partie

action=bulk_dr

Un crédit par appel. Le plafond documenté est de 2 000 domaines par appel.

domains=

Un paramètre GET ici. Le point de terminaison accepte également un corps POST, ce qui est le meilleur choix une fois les listes longues. Testez le séparateur avec deux domaines avant une exécution complète.

BATCH = 200

Notre habitude, pas une limite : 200 domaines courts maintiennent l'URL bien en dessous des limites courantes des proxies.

_credits

Présent sur les réponses authentifiées : le coût de l'appel et ce qui reste. L'imprimer à chaque lot est la piste d'audit la moins chère.

Colonne body brute

Vous analysez plus tard, une seule fois, par rapport à un échantillon stocké. Un changement de schéma de notre côté vous coûte alors une requête, pas une nouvelle exécution.

Balance en laiton équilibrant des poids pour montrer un calcul précis

Une exécution hypothétique, avec l'arithmétique

Ceci est un exemple, pas une histoire client. Imaginez une agence qui suit 1 800 domaines clients et prospects dans un Google Sheet et qui veut actualiser le DR chaque lundi.

À 200 domaines par lot, cela fait 9 requêtes. Neuf requêtes à 1 crédit chacune font 9 crédits, soit 0,0009 $ par exécution, et sur 52 lundis, le total est de 468 crédits, ce qui arrondit à moins de cinq cents.

Le coût n'est pas la contrainte. La fraîcheur l'est. L'index se reconstruit environ mensuellement, donc des exécutions hebdomadaires afficheront les mêmes valeurs trois semaines sur quatre, et une exécution mensuelle capture le même mouvement pour environ un quart des appels.

Donc exécutez-le mensuellement et gardez le tableau hebdomadaire pour les modifications humaines. Les détails sur la raison pour laquelle le score peut rester stable sont dans la référence DR.

Les choses qui mal tournent dans ce script

SymptômeCauseCorrection
SystemExit: HTTP 402Solde à zéroRechargez depuis la page de compte, relancez ; les lots terminés sont déjà dans SQLite
SystemExit: HTTP 401Variable d'environnement vide ou faute de frappe sur la cléImprimez len(KEY) et vérifiez le préfixe sk_
ok=false sur le lot 3Mauvaise valeur dans la liste, comme une URL complèteSupprimez le schéma et le chemin avant l'envoi, voir le tableau des erreurs
Même DR que la semaine dernièreL'index ne s'est pas encore reconstruitPrévisible ; comparez mensuellement
URL longue rejetéeLot trop volumineux pour GETRéduisez BATCH ou passez à un corps POST

Taille du lot, GET et POST pour les longues listes

Le plafond est de 2 000 domaines par appel, et le script envoie un dixième de cela. Chaque appel coûte le même crédit fixe, donc la taille du lot est une question d'échec et de charge utile, pas de prix.

Pourquoi 200 et non 2 000

Un lot plus petit échoue à moindre coût. Si une exécution s'arrête en cours de route, la queue laissée à refaire est longue d'un lot, pas d'une liste entière.

Les listes plus courtes maintiennent également chaque corps enregistré suffisamment petit pour être parcouru à l'œil lorsqu'un nombre semble incorrect, et cela compte plus que quelques appels économisés.

Si vous augmentez ultérieurement la taille du lot, faites-le une fois, dans une constante unique, et relancez le test à deux domaines. Un nombre plus élevé n'est pas une raison pour sauter le test.

Planifiez le lot en fonction de la durée d'exécution que vous pouvez tolérer, pas du plafond. Un travail nocturne qui doit se terminer avant un rapport matinal peut se permettre des lots plus petits et plus sûrs qu'une réinitialisation ponctuelle.

GET pour les courtes listes, POST pour les longues

La forme GET place chaque domaine dans l'URL. Cela fonctionne jusqu'à ce qu'un proxy ou une ligne de journal tronque la requête, c'est pourquoi le tableau ci-dessus recommande de réduire d'abord le lot. Une fois les listes volumineuses, envoyez la même valeur domains dans un corps POST.

Testez le séparateur et l'encodage avec deux domaines avant une exécution complète. Une virgule errante apparaît dans le premier lot, et il est moins cher de la voir là.

Un corps POST garde également la liste hors des journaux d'accès que de nombreux hôtes conservent par défaut. C'est un petit gain de confidentialité pour les listes de clients, et cela coûte une ligne d'en-tête supplémentaire dans le script.

Lorsque vous passez à POST, gardez la version GET du script comme solution de secours pour les courtes listes. Deux chemins de code semblent lourds, mais une seule petite fonction qui en choisit un selon la longueur est facile à lire et à tester.

Trimmez et supprimez les doublons avant la première requête

Supprimez les espaces, mettez l'hôte en minuscule et supprimez les doublons avant que quoi que ce soit ne quitte votre machine. Les doublons prennent de la place sous le plafond de 2 000 domaines, et ils font diverger le compte dans votre feuille de calcul du compte dans la réponse.

Choisissez une règle pour www. et appliquez-la dans une seule fonction, afin qu'un même site ne soit jamais recherché sous deux orthographes. Tout vérificateur de domaine de backlinks qui passe à l'échelle au-delà de quelques centaines de noms a besoin de cette discipline.

Ce que le journal d'exécution devrait dire

Imprimez la valeur _credits après chaque lot, et écrivez le numéro du lot, le nombre de domaines et l'heure à côté. Ces trois nombres répondent à presque toutes les questions qu'un lecteur financier se posera sur une exécution.

Une exécution qui n'imprime rien jusqu'à la fin ne vous donne aucune indication lorsqu'elle se bloque. Une ligne par lot est peu coûteuse, et elle transforme un blocage silencieux en un numéro de lot que vous pouvez nommer.

Gardez le journal dans le même dossier que le fichier SQLite, afin qu'une seule sauvegarde copie les deux. Un journal qui vit ailleurs est celui qui disparaît lors d'un incident.

Assemblage en bois terminé se tenant à part du bois brut

Trois extensions valant l'après-midi

Stockez le numéro du lot à côté de l'horodatage. Il est déjà dans le tableau ci-dessus, et il vous permet de relancer uniquement le lot qui a échoué après un 402 en cours d'exécution.

Écrivez une petite vue sur la table brute une fois que vous avez inspecté une réponse réelle : domaine, score, date de récupération. Les tableaux de bord lisent la vue, et la colonne brute reste votre preuve si un nombre est contesté.

Exécutez-le depuis GitHub Actions ou un cron simple sur un petit VPS. Les deux conviennent. Ce qui compte, c'est que le travail se termine avec un code non nul en cas d'échec, car un échec silencieux ressemble à un graphique périmé trois semaines plus tard.

Trier la sortie est une question de front-end. Classez le portefeuille par score, regroupez-le, ou comparez-le avec dr_distribution (1 crédit) pour voir où se situe chaque client parmi les 181 132 097 domaines.

Dérive de champ et table brute

Un travail à long terme échoue silencieusement lorsqu'un champ change de forme. La colonne brute est là pour que l'échec reste bruyant et peu coûteux à corriger.

Stockez d'abord le corps brut

La colonne brute est le filet de sécurité. Si un champ est renommé ou si un nouveau apparaît, vous relancez une requête sur les réponses stockées au lieu de payer pour toute la liste à nouveau. L'analyse ultérieure est peu coûteuse, tandis que le rachat ne l'est pas.

Conservez un échantillon enregistré par semaine dans un fichier à part. Lorsqu'une analyse échoue, vous comparez l'échantillon de cette semaine avec le dernier qui a fonctionné.

Écrivez le corps exactement tel qu'il est reçu, sans mise en forme et sans troncation. Toute modification que vous apportez au texte avant de le stocker est une modification que vous ne pourrez pas annuler plus tard.

À quoi ressemble une dérive en pratique

Disons qu'un tableau de bord affiche soudainement des scores vides pour un lot. La ligne brute est toujours là. Vous l'ouvrez, comparez ses clés avec l'échantillon de la semaine dernière, et trouvez la différence en quelques minutes.

La correction est alors une seule ligne dans la vue, pas une nouvelle exécution de toute la liste. C'est tout l'intérêt du stockage du corps.

Gardez une courte note à côté de la vue indiquant quel champ elle lit et quand vous l'avez vérifiée pour la dernière fois par rapport à une réponse réelle. La note prend une minute à écrire et économise une longue recherche plus tard.

Ordonnez les migrations avec les données

Créez la table brute avant la vue, et la vue avant toute requête de tableau de bord. Gardez les instructions de création dans un seul fichier, exécutez-les dans l'ordre et enregistrez le numéro du lot avec chaque ligne.

Des bases de données séparées par client dérivent de la même manière qu'une base de données partagée. La règle reste la même : un corps stocké par appel, et un seul endroit pour l'analyser.

Gardez l'analyseur à côté des tests

Placez la fonction d'analyse dans le même dépôt qu'un test qui lit un corps enregistré. Le test est l'endroit où un champ dérivé apparaît en premier, bien avant qu'un graphique ne le fasse.

Nommez les champs que l'analyseur attend dans une constante près du début du fichier. Un réviseur peut alors voir toutes les dépendances sur la forme de la réponse en un seul écran.

Première exécution, dans l'ordre

  1. 1

    Testez un domaine

    Appelez bulk_dr avec un seul domaine que vous connaissez, et lisez toute la réponse. Notez les clés avant d'écrire tout code d'analyse.

  2. 2

    Exécutez deux lots

    Donnez au script une liste de 400 domaines, afin que exactement deux lots s'exécutent. Vérifiez que la baisse de _credits correspond à deux appels à un crédit chacun.

  3. 3

    Comptez les lignes stockées

    Ouvrez le fichier SQLite et comparez le nombre de lignes avec le nombre de lots. Une divergence signifie qu'un lot a été sauté ou stocké deux fois, et vous le découvrez avant que le tableau de bord ne le fasse.

  4. 4

    Planifiez la liste complète

    Uniquement après que les tests sont propres, ajoutez la liste complète et le planificateur. Gardez la sortie non nulle, afin qu'un échec soit bruyant dès la première nuit.

Avant de le planifier

  • Supprimez les doublons et mettez la liste en minuscules d'abord
  • Décidez une fois, dans une seule fonction, si www. reste ou part
  • Gardez la clé dans un magasin de secrets, pas dans crontab
  • Alertez sur un code de sortie non nul
  • Exécutez les chiffres du budget de crédits pour votre propre volume