Strona produktu sprzedawcy odpowiedziała statusem 200, ale była pusta. Pipeline nie zarejestrował blokady. Zarejestrował pustą półkę.
To awaria, której nikt nie uwzględnia w budżecie przy danych alternatywnych. Nie brakujący zbiór danych, nie wolny dostawca. Warstwa zbierania danych, która wciąż dostarcza wiersze, po cichu mierząc coś innego niż firma, którą analizujesz.
Wyzwanie
W styczniu 2026 r. firma Exabel przeprowadziła ankietę wśród 100 menedżerów portfeli fundamentalnych i analityków z USA, Wielkiej Brytanii, Singapuru i Hongkongu, zarządzających łącznie około 610 miliardami dolarów. 71% uznało łączenie danych z różnych źródeł za najbardziej frustrującą część pracy z danymi alternatywnymi, a 94% stwierdziło, że już wykorzystuje sztuczną inteligencję lub uczenie maszynowe na pewnym etapie procesu badawczego.
Zestaw te dwie liczby ze sobą, a wyłoni się obraz problemu. Strona modelowania ma odpowiednie zasoby. Infrastruktura pod spodem już nie.
Panel zbierany z sieci (ceny, stan zapasów, strony karier, liczba recenzji, asortyment na platformach handlowych) to przede wszystkim szereg czasowy. Każdy szereg czasowy niesie ze sobą założenie, którego nikt nie wpisuje do specyfikacji: dzisiejsza obserwacja została zebrana w taki sam sposób jak wczorajsza. Złam to założenie głośno, a dostaniesz alert. Złam je po cichu, a otrzymasz sygnał.
Trzy z tych cichych naruszeń pojawiają się w prawie każdym panelu zbieranym z sieci.
Status 200, który nie jest treścią. Zabezpieczenia przed botami już dawno przestały odpowiadać czystym statusem 403. Strona z wyzwaniem, okno zgody lub szablon z pustymi wynikami przychodzą ze statusem sukcesu i treścią, którą twój parser odczytuje jako zero wyników. Mniejsza liczba ofert wygląda identycznie jak mniejszy popyt.
Punkt widzenia się przesunął. Cena, waluta, asortyment, baner promocyjny, a czasami to, czy strona w ogóle się renderuje: sprzedawcy uzależniają to wszystko od tego, skąd wydaje się pochodzić request. Jeśli poniedziałkowe zbieranie wychodziło przez Niemcy, a czwartkowe przez Polskę, w twoim szeregu pojawia się skok, który zależy od ciebie, a nie od sprzedawcy.
Rotacja, która wzięła pierwszą otrzymaną odpowiedź. Rotuj przez węzły wyjściowe bez poinformowania kolektora, co oznacza sukces, a zatrzyma się on na pierwszym węźle, który odpowie. Odmowa to też odpowiedź. Więc wiersz trafia do bazy, zadanie świeci na zielono i nikt więcej do tego nie zagląda.
Żadne z tych zdarzeń nie rzuca wyjątku. Proces ingestions liczy wiersze, dashboard pozostaje zielony, a analityk dostaje wykres. Potem model spędza kwartał ucząc się zachowania twojej infrastruktury zbierania danych zamiast zachowania biznesu.
Podejście
Traktuj integralność danych jako właściwość żądania (request), a nie parsera na dalszym etapie. Trzy rzeczy muszą być prawdziwe.
1. Określ, jak wygląda prawdziwa strona. Kolektor nie jest w stanie sam tego ustalić. Przekaż mu ciąg znaków, który zawiera tylko właściwa treść, oraz kilka takich, które występują tylko przy odmowach, a strona z weryfikacją przestanie być traktowana jako obserwacja. Pisaliśmy o tym, gdy wprowadzono reguły validate: sam request decyduje, co oznacza sukces.
import requests
r = requests.post(
"https://api.foura.ai/api/proxy",
headers={"X-API-Key": "YOUR_API_KEY"},
json={
"maxTries": 8,
"exitCountries": ["DE"],
"request": {
"method": "GET",
"url": "https://retailer.example/p/12345",
"validate": {
"status": {"accept": [200]},
"data": {
"accept": ["data-testid=\"price\""],
"fail": ["Access Denied", "Just a moment"]
}
}
}
}
).json()
observation = r["data"] # content your rules accepted, or nothing
exit_id = r["proxy"] # opaque ID of the exit that delivered it
served_from = r["exitCountry"] # verify it against what you asked for
Rotacja ma teraz definicję ukończenia (definition of done). Próbuje używać kolejnych węzłów wyjściowych, dopóki jeden z nich nie zwróci czegoś, co spełnia twoje reguły, zamiast zwracać pierwszy obiekt przypominający stronę, na jaki natrafi.
2. Utrzymaj stały punkt obserwacyjny. exitCountries to ścisła lista dozwolonych kodów krajów widocznych dla celu, a węzły wyjściowe o nieznanej geografii są pomijane, a nie zastępowane. Dwa szczere zastrzeżenia, oba warte poznania, zanim na tym zbudujesz. Metadane kraju są odświeżane cyklicznie (zwykle co około dziesięć minut), więc nie jest to sprawdzanie na żywo w momencie wysyłania request, dlatego response zawiera exitCountry, abyś mógł to sprawdzić. A kiedy w puli nie ma dopasowania do żądanego zakresu, wywołanie wraca z HTTP 200 i obiektem błędu, zamiast z wyjątkiem. Czytaj body, a nie status. Zachowaj zakres i ponów próbę później, zamiast go rozszerzać. Rozszerzony zakres to przerwanie ciągłości w serii.
3. Zachowaj tożsamość węzła wyjściowego. Pole proxy to nieprzezroczysty identyfikator (opaque ID), a nie adres. Przekaż go z powrotem w kolejnym wywołaniu Single lub Browser, a strona ze szczegółami nadejdzie z tego samego punktu obserwacyjnego, co strona wyszukiwania, która go znalazła (jak ponownie użyć węzła wyjściowego). Zapisz ten ID i header X-FourA-Request-Id przy każdym wierszu. Kiedy analityk kwestionuje skok sześć tygodni później, pytanie "czy to było prawdziwe?" staje się wyszukiwaniem w bazie, a nie kłótnią.
Dla źródła, które właśnie wdrażasz i którego jeszcze nie rozumiesz, Auto to najszybszy sposób na znalezienie działającej ścieżki: przechodzi po drabinie od tanich do drogich, mówi, który szczebel wygrał, i zwraca sesję, która zadziałała. Użyj tego do znalezienia trasy, a następnie skieruj ruch produkcyjny na bezpośrednie silniki. Odtwórz tę sesję przez Single, gdzie nic nie wymaga renderowania, i Browser, gdzie jest to faktycznie potrzebne. Znajdowanie ścieżki i zbieranie danych w stanie ustalonym to różne zadania.
Wyniki
Co się zmienia, gdy te trzy właściwości są spełnione, na próbie kilku tysięcy stron produktów dziennie u kilkunastu sprzedawców (scenariusz ilustracyjny oparty na benchmarkach branżowych):
- Luka to luka, nie zgadywanka. Odmowy nigdy nie wchodzą do bazy jako zera, więc pusty zestaw wyników oznacza, że sprzedawca nic nie pokazał. Twój sygnał nieobecności ma wartość handlową.
- Porównywalne wiersze. Każda obserwacja w serii pochodzi z kraju, w którym zdefiniowano serię, więc zmiana ceny jest faktyczną zmianą ceny.
- Odtwarzalna historia. ID węzła wyjściowego plus ID dla request w każdym wierszu oznacza, że każdy kwestionowany punkt danych można prześledzić z powrotem do dokładnego wywołania, które go wyprodukowało.
- Niższy koszt użytecznego wiersza. Żądania, które wygenerowałyby odrzuconą obserwację, są ponawiane w czasie zbierania, a nie opłacane, parsowane, przechowywane, a później usuwane podczas testów wstecznych.
Ale ten ostatni punkt jest tym, co zespoły badawcze niedoceniają. Zły wiersz nie jest darmowy tylko dlatego, że był tani do pobrania. Kosztuje on cykl badawczy, a czasem kosztuje zaufanie osoby, która musi zaakceptować ten sygnał.
Kluczowe wnioski
Nabywcy danych alternatywnych oceniają dostawców pod kątem pokrycia, opóźnień i głębokości historii. Prawie nikt nie zadaje pytania, które decyduje o tym, czy dany zbiór nadaje się do tradingu: jak ten dataset zachowuje się w dniu, w którym źródło odmawia odpowiedzi?
Dostawca, który usuwa taki wiersz, jest uczciwy. Dostawca, który zwraca stronę informacyjną jako obserwację, sprzedał ci pomiar własnej infrastruktury, za co zapłacisz w backteście, który działa bez zarzutu, dopóki nagle nie przestanie. To pytanie powinno znaleźć się na każdej liście kontrolnej due diligence danych, a w pierwszej kolejności w twoim własnym pipeline, ponieważ jeśli zbierasz dane samodzielnie, to ty jesteś dostawcą.