Przejdź do treści

Dane o linkach zwrotnych w formacie JSON: $100 darmowego kredytu, bez karty, logowanie przez Google.

SEOMasters.dev
SEOMasters.devZarejestruj się

Masowe DR dla listy klientów jako 40-wierszowy skrypt Pythona

Masz arkusz z domenami i dashboard, który wymaga jednej wartości w każdym wierszu. Narzędzie do sprawdzania domen backlinków do tego zadania to głównie „rury”, a ten skrypt jest właśnie tymi rurami.

Ręce sortujące drewniane klocki na stosy na stole roboczym

Skrypt

Odczytuje domains.txt, wysyła 200 domen w jednym żądaniu, zapisuje każdą surową odpowiedź w SQLite i wypisuje koszt wykonania. Przechowujemy pełną zawartość, ponieważ nazwy pól najlepiej kopiować z rzeczywistej odpowiedzi, a nie z wpisu na blogu.

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"))

Co robi każda część

action=bulk_dr

Jeden kredyt za wywołanie. Dokumentowany limit to 2000 domen na wywołanie.

domains=

Parametr GET. Endpoint akceptuje również ciało POST, co jest lepszą opcją przy długich listach. Przetestuj separator na dwóch domenach przed pełnym uruchomieniem.

BATCH = 200

Nasza praktyka, nie limit: 200 krótkich domen utrzymuje URL znacznie poniżej typowych limitów proxy.

_credits

Obecne w odpowiedziach uwierzytelnionych: koszt wywołania i pozostałe środki. Wypisywanie ich w każdej partii to najtańszy ślad audytowy.

Kolumna surowego body

Parsujesz później, jednorazowo, na podstawie zapisanej próbki. Zmiana schematu po naszej stronie kosztuje Cię wtedy tylko zapytanie, a nie ponowne uruchomienie.

Mosiężna waga równoważąca ciężarki, pokazująca precyzyjne obliczenia

Hipotetyczne uruchomienie z obliczeniami

To jest przykład, nie historia klienta. Wyobraź sobie agencję, która śledzi 1800 domen klientów i potencjalnych klientów w arkuszu Google i chce odświeżać DR każdego poniedziałku.

Przy 200 domenach w partii to 9 żądań. Dziewięć żądań po 1 kredencie to 9 kredytów, czyli $0.0009 za uruchomienie, a w ciągu 52 poniedziałków suma to 468 kredytów, co zaokrąglone daje mniej niż pięć centów.

Koszt nie jest ograniczeniem. Ograniczeniem jest świeżość. Indeks rebuilduje się około raz w miesiącu, więc cotygodniowe uruchomienia będą pokazywać te same wartości przez trzy tygodnie na cztery, a miesięczne uruchomienie odzwierciedla te same zmiany przy około ćwierci liczby wywołań.

Więc uruchamiaj go miesięcznie i utrzymuj cotygodniowy arkusz do ręcznych edycji. Szczegóły dotyczące tego, dlaczego wynik może stać w miejscu, znajdziesz w referencji DR.

Co może pójść nie tak w tym skrypcie

ObjawPrzyczynaNaprawa
SystemExit: HTTP 402Saldo wynosi zeroDoładuj konto na stronie profilu, uruchom ponownie; ukończone partie są już w SQLite
SystemExit: HTTP 401Zmienna środowiskowa pusta lub literówka w kluczuWypisz len(KEY) i sprawdź prefiks sk_
ok=false na partii 3Nieprawidłowa wartość na liście, np. pełny URLUsuń schemat i ścieżkę przed wysłaniem, zobacz tabelę błędów
To samo DR co w zeszłym tygodniuIndeks nie został jeszcze odbudowanyOczekiwane; porównuj miesięcznie
Długi URL odrzuconyPartia za duża dla GETZmniejsz BATCH lub przejdź na ciało POST

Rozmiar partii, GET i POST dla długich list

Limit to 2000 domen na wywołanie, a skrypt wysyła jedną dziesiątą tej wartości. Każde wywołanie kosztuje tyle samo kredytu, więc rozmiar partii to kwestia awarii i ładunku, a nie ceny.

Dlaczego 200, a nie 2000

Mniejsza partia awariuje taniej. Jeśli uruchomienie zatrzyma się w połowie, ogon do ponownego uruchomienia ma długość jednej partii, a nie całej listy.

Krótsze listy utrzymują każdą zapisaną zawartość na małym poziomie, co pozwala na przeglądnięcie jej wzrokowo, gdy jakaś wartość wydaje się niepoprawna, i to ma większe znaczenie niż kilka oszczędzonych wywołań.

Jeśli później zwiększysz rozmiar partii, zrób to raz, w jednej stałej, i ponownie przetestuj na dwóch domenach. Większa liczba nie jest powodem do pominięcia testu.

Zaplanuj partię względem długości uruchomienia, jaką jesteś w tolerować, a nie względem limitu. Zadanie dzienne, które musi zakończyć się przed porannym raportem, może pozwolić sobie na mniejsze, bezpieczniejsze partie niż jednorazowe uzupełnianie danych.

GET dla krótkich list, POST dla długich

Forma GET umieszcza każdą domenę w URL. Działa to, dopóki proxy lub linia logu nie uetkują zapytania, dlatego tabela powyżej sugeruje najpierw zmniejszenie partii. Gdy listy rosną, wyślij tę samą wartość domains w ciele POST.

Przetestuj separator i kodowanie na dwóch domenach przed pełnym uruchomieniem. Przypadkowy przecinek pojawi się w pierwszej partii, a taniej go zauważyć tam.

Ciało POST utrzymuje również listę poza logami dostępu, które wiele hostów zapisuje domyślnie. To mała korzyść prywatności dla list klientów, a kosztuje jedną dodatkową linię nagłówka w skrypcie.

Po przełączeniu się na POST zachowaj wersję GET skryptu jako rezerwę dla krótkich list. Dwie ścieżki kodu brzzą ciężko, ale jedna mała funkcja wybierająca jedną z nich na podstawie długości jest łatwa do odczytania i testowania.

Wycinanie i usuwanie duplikatów przed pierwszym żądaniem

Usuń białe znaki, zamień host na małe litery i usuń duplikaty przed wysłaniem czegokolwiek z Twojej maszyny. Duplikaty zajmują miejsce pod limitem 2000 domen i powodują rozbieżności między licznikiem w Twoim arkuszu a licznikiem w odpowiedzi.

Wybierz jedną regułę dla www. i zastosuj ją w jednej funkcji, aby ta sama strona nigdy nie była wyszukiwana pod dwiema pisowniami. Każde narzędzie do sprawdzania domen backlinków, które skaluje się powyżej kilku setek nazw, wymaga tej dyscypliny.

Co powinien zawierać dziennik uruchomienia

Wypisuj wartość _credits po każdej partii i zapisuj numer partii, liczbę domen i czas obok niej. Te trzy liczby odpowiadają na prawie każde pytanie, jakie czytelnik z działu finansów zada o uruchomienie.

Uruchomienie, które nic nie wypisuje do końca, nie daje Ci pojęcia, kiedy utknęło. Linia na partię jest tania i zamienia ciche zawieszenie w numer partii, który możesz wskazać.

Przechowuj log w tym samym folderze co plik SQLite, aby jedna kopia zapasowa kopiowała oba. Log znajdujący się gdzieś indziej to ten, który zaginie podczas incydentu.

Ukończone drewniane połączenie stojące osobno od surowego drewna

Trzy rozszerzenia warte popołudnia

Zapisz numer partii obok znacznika czasu. Jest już w tabeli powyżej i pozwala na ponowne uruchomienie tylko partii, która uległa awarii po 402 w trakcie działania.

Stwórz małą widokową tabelę nad surową tabelą, gdy tylko zbadasz rzeczywistą odpowiedź: domena, wynik, data pobrania. Dashboardy odczytują widok, a kolumna surowa pozostaje Twoim dowodem, jeśli jakaś wartość zostanie kiedykolwiek zakwestionowana.

Uruchamiaj go z GitHub Actions lub zwykłego cron na małym VPS. Oboje są OK. Najważniejsze, aby zadanie kończyło się kodem niezerowym w przypadku każdej awarii, ponieważ cicha awaria wygląda jak przestarzały wykres trzy tygodnie później.

Sortowanie wyniku to kwestia front-endu. Posortuj portfel według wyniku, podziel go na przedziały lub porównaj go z dr_distribution (1 kredyt), aby zobaczyć, gdzie znajduje się każdy klient wśród wszystkich 181 132 097 domen.

Drgania pól i surowa tabela

Długotrwałe zadanie cicho awariuje, gdy zmieni się kształt pola. Kolumna surowa istnieje po to, aby awaria była głośna i tania do naprawy.

Najpierw zapisz surowe ciało

Kolumna surowa to sieć bezpieczeństwa. Jeśli pole zostanie zmienione lub pojawi się nowe, ponownie uruchamiasz zapytanie nad zapisanymi odpowiedziami zamiast płacić za całą listę ponownie. Parsowanie później jest tanie, podczas gdy ponowne kupowanie nie jest.

Przechowuj jedną zapisaną próbkę na tydzień w osobnym pliku. Gdy parsowanie się zepsuje, porównaj próbkę z tego tygodnia z ostatnią, która działała.

Zapisz ciało dokładnie tak, jak zostało odebrane, bez formatowania i bez przycinania. Każda zmiana, którą wprowadzisz w tekście przed zapisaniem, jest zmianą, której nie będziesz mógł cofnąć później.

Jak drgania wyglądają w praktyce

Załóżmy, że dashboard nagle pokazuje puste wyniki dla jednej partii. Wiersz surowy jest nadal obecny. Otwierasz go, porównujesz jego klucze z próbką z zeszłego tygodnia i znajdujesz różnicę w ciągu kilku minut.

Naprawa to wtedy jedna linia w widoku, a nie ponowne uruchomienie całej listy. O to właśnie chodzi przy przechowywaniu ciała.

Zachowaj krótką notatkę obok widoku mówiącą, które pole odczytuje i kiedy ostatnio sprawdzałeś ją na podstawie rzeczywistej odpowiedzi. Notatka zajmuje minutę do napisania i oszczędza długie wyszukiwanie później.

Kolejność migracji z danymi

Stwórz tabelę surową przed widokiem, a widok przed jakimkolwiek zapytaniem dashboardu. Trzymaj instrukcje tworzenia w jednym pliku, uruchamiaj je w kolejności i zapisuj numer partii z każdym wierszem.

Oddzielne bazy danych dla klientów drgają tak samo, jak jedna wspólna baza danych. Zasada pozostaje ta sama: jedno przechowywane ciało na wywołanie i jedno miejsce do jego parsowania.

Trzymaj parser obok testów

Umieść funkcję parsowania w tym samym repozytorium co test, który odczytuje jedną zapisaną zawartość. Test jest miejscem, w którym zdrętwiałe pole pojawia się po raz pierwszy, długo przed tym, jak zrobi to wykres.

Nazwij pola, których oczekuje parser, w jednej stałej blisko początku pliku. Recenzent może wtedy zobaczyć wszystkie zależności od kształtu odpowiedzi na jednym ekranie.

Pierwsze uruchomienie, w kolejności

  1. 1

    Przetestuj jedną domenę

    Wywołaj bulk_dr z jedną znaną domeną i przeczytaj całą odpowiedź. Zapisz klucze przed napisaniem jakiegokolwiek kodu parsującego.

  2. 2

    Uruchom dwie partie

    Daj skryptowi listę 400 domen, aby uruchomiły się dokładnie dwie partie. Sprawdź, czy spadek _credits odpowiada dwóm wywołaniom po jednym kredencie.

  3. 3

    Policz zapisane wiersze

    Otwórz plik SQLite i porównaj liczbę wierszy z liczbą partii. Rozbieżność oznacza, że partia została pominięta lub zapisana dwukrotnie, i dowiesz się o tym przed dashboardem.

  4. 4

    Zaplanuj pełną listę

    Tylko po czystym uruchomieniu testów dodaj pełną listę i harmonogram. Zachowaj wyjscie niezerowe, aby awaria była głośna w pierwszą noc.

Przed zaplanowaniem go

  • Najpierw usuń duplikaty i zamień listę na małe litery
  • Zdecyduj raz, w jednej funkcji, czy www. zostaje, czy znika
  • Przechowuj klucz w magazynie sekretów, a nie w crontab
  • Alert przy kodzie wyjścia niezerowym
  • Przelicz liczby budżetu kredytów dla swojego własnego wolumenu