AX/J/002

Dlaczego scraping na produkcji wygląda zupełnie inaczej niż w tutorialach

Tutorial pokazuje BeautifulSoup, pętlę i pięćdziesiąt linijek. Produkcja wymaga pipeline'u z idempotentnością, dead-letter queue, walidacją schematu i obserwowalności. Dlaczego ta przepaść jest tak duża.

Otwierasz tutorial. Pięćdziesiąt linijek Pythona. Biblioteka requests, BeautifulSoup, jedna pętla po listingu, zapisuje do CSV. Działa. Komentarze: "świetne, dzięki!". Komentarze trzy tygodnie później od ludzi którzy próbowali to puścić na produkcji: cisza.

Przepaść między tym co pokazują tutoriale a tym czego wymaga produkcja jest tak duża, że właściwie mówimy o dwóch różnych dyscyplinach. Tutorial pokazuje skrypt. Produkcja wymaga pipeline'u.

Tutorial pokazuje skrypt. Produkcja wymaga pipeline'u. Granica między tymi pojęciami to większość niewidzialnej pracy.

Co produkcja wymaga, a tutoriale pomijają

Lista rzeczy, które są na produkcji obowiązkowe a w tutorialach nie istnieją:

Idempotentność

Tutorial: scrape leci raz, zapisuje wiersze do CSV, kończy się. Produkcja: scrape leci codziennie o 4:00, czasem zwiesza się w połowie, czasem retry odpala dwa razy ten sam batch przez deduplikację Kafki. Jeśli zapis nie jest idempotentny — to znaczy: powtórny przebieg zawsze daje ten sam stan końcowy, nigdy duplikatów — masz pełną bazę śmieci po pierwszym miesiącu.

Rozwiązanie nie jest skomplikowane: INSERT ... ON CONFLICT DO UPDATE w Postgresie, deduplikacja po hashu treści w S3, idempotency keys na poziomie kolejki. Ale wymaga się tego ZAPROJEKTOWAĆ. Z tutoriala tego nie wziąłeś.

Walidacja schematu na granicy

Strona, którą scrape'ujesz, dziś zwraca pole price jako string "1299.00 zł". Za miesiąc zmienią to na liczbę bez waluty. Twój scrape nadal się przeczołga — BeautifulSoup nie ma o tym pojęcia. Wszystkie liczby od tego dnia są niepoprawne, dopóki ktoś nie zauważy.

Produkcja: każdy obiekt wychodzący ze scrape'a przechodzi przez Zod, JSON Schema albo własną walidację. Niepasujące rekordy nie idą do bazy — idą do dead-letter queue z pełnym kontekstem zdarzenia (URL, HTML, timestamp, parser version). Po tygodniu ktoś przegląda DLQ i widzi: aha, strona zmieniła format. Bez DLQ widzisz to dopiero kiedy klient zadzwoni.

Rate limiting i anti-bot

Tutorial: jedna pętla, sleep 1s między requestami. Produkcja: rotacja proxy z residential pool, rotacja fingerprintów, custom headers, randomizacja timing'u, obsługa CAPTCHA (rzadko ręczna, częściej przez 2captcha lub anti-CAPTCHA service), reagowanie na 429-tki z exponential backoff, monitoring blokad per-IP, czasem rotacja przeglądarki przy zwiększonej detekcji. To jest cała dyscyplina, nie jeden parametr.

Obserwowalność

Tutorial: print('done'). Produkcja: structured logs (JSON, z trace ID, request ID, parser version, runtime ms), metryki Prometheus (success rate, latency percentile, error rate per source), alerty (PagerDuty kiedy success rate spadnie poniżej 95% na piętnaście minut), dashboard (Grafana z trendami tygodniowymi), audit log (kto, kiedy, którą wersją parsera dotknął którego rekordu).

Bez tego nie wiesz że scrape się psuje, dopóki nie jest za późno.

Wersjonowanie parserów

Strona zmienia layout. Parser musi się zmienić. Stare dane wyciągnięte parserem v1.2 mają inny zestaw pól niż dane parserem v1.3. Zapisujesz wersję parsera z każdym rekordem. Backfill v1.3 na archiwach v1.2 to osobny job, który leci offline. Wszystko to wymaga PROCESU, nie tylko kodu.

Pułapka "po prostu dodam retry"

Najczęstsza odpowiedź developera, który spotyka pierwszą awarię produkcyjną: "po prostu dodam retry". Z 3-krotnym ponowieniem. Z exponential backoff jeśli jest ambitny.

To nie rozwiązuje problemu. Retry przykrywa objaw. Realne pytanie brzmi: dlaczego ten request się wywalił, i co należy zrobić jeśli wywali się 50 razy z rzędu?

  • Network timeout? Retry, ale po 3 próbach idź do DLQ.
  • 429 z proxy? Zmień proxy, retry, ale jeśli 5 IP-ów pod rząd dostaje 429 — alarm, blokada pool'a zaczęła się.
  • Pusta odpowiedź z 200 OK? Coś w anti-bocie się zmieniło, nie retry — alarm.
  • HTML, którego parser nie potrafi sparsować? Nie retry — DLQ + alarm.

Każdy z tych przypadków potrzebuje innego sposobu obsługi. Generyczny retry to przyznanie, że nie wiesz dlaczego coś się stało, i masz nadzieję że samo się naprawi. Czasem tak. Częściej zaśmieca DLQ wpisami które miały dotrzeć do kogoś dwa dni temu.

Właściwy model: pipeline, nie skrypt

Pomyśl o scrape'ingu jak o procesie ETL z dodatkową warstwą "pozyskania". Etapy są wyraźnie rozdzielone, każdy ma swoje metryki, każdy ma swój dead-letter, każdy jest niezależnie skalowalny.

  1. Trigger: cron, webhook, event z kolejki. Punkt startu.
  2. Fetch: pozyskanie HTML/JSON ze źródła. Tu siedzi anti-bot, proxy, retry.
  3. Parse: ekstrakcja danych z surowej odpowiedzi. Wersjonowany parser.
  4. Validate: schemat. Dane poprawne idą dalej, niepoprawne do DLQ.
  5. Persist: idempotentny zapis. Dedup na hashu treści.
  6. Notify: webhook do klienta, event do kolejki, alert jeśli coś poszło źle.

Każdy z tych kroków zostawia ślad w obserwowalności. Każdy potrafi się wycofać niezależnie. Każdy może być re-runowany z dowolnego punktu pipeline'u.

Kiedy NIE scrape'ować

Najczęściej zapominana odpowiedź. Zanim zaczniesz pisać scrape, sprawdź:

  • Czy ten dostawca ma API? Często ma, tylko jest płatne. Płatne API zwykle wygrywa z TCO scrape'a w 12-miesięcznym okresie.
  • Czy dane są w publicznym datasecie? GovInfo, Eurostat, Companies House, KRS, biały rejestr — wiele danych które ludzie scrape'ują, dostępne jest jako dump CSV.
  • Czy dostawca zezwala scrape'owi w ToS? Jeśli nie, prawne ryzyko jest realne — case law w UE rośnie.
  • Czy częstość danych usprawiedliwia engineering? Codzienne ceny 5000 produktów z dostawcy bez API to scrape. Roczne dane bilansowe trzech spółek — może po prostu ktoś przepisuje raz w roku.

Sedno

Scraping to inżynieria oprogramowania. Nie weekendowy projekt, nie skrypt, nie "zrobimy w jeden dzień". Wszystko, co tutorial pomija, jest tym, co decyduje czy pipeline będzie żył rok, czy padnie po tygodniu.

Tutoriale uczą jak złapać dane. Produkcja wymaga, żeby umieć je dostarczyć. Te dwie umiejętności mają zaskakująco mało wspólnego.

Masz podobny problem?

Większość tych technik wdrażamy na produkcję.

Jeśli ten artykuł rezonuje z czymś, co próbujesz rozwiązać — napisz. Wstępna ocena projektu jest bezpłatna.