To, co sprawia, że Crawlee jest tak przydatne, to fakt, że jego orkiestracja crawlingu obsługuje zarówno parsowanie HTTP, jak i uruchamianie przeglądarki. Ten sam adres URL może więc zwrócić różne wyniki w zależności od wybranego crawlera i warunku gotowości.
Na publicznej stronie Quotes to Scrape JS CheerioCrawler znalazł 0 docelowych cytatów, a PlaywrightCrawler znalazł 10 po odczekaniu na .quote. Cykl życia crawlingu wygląda podobnie, ale nie była to prosta podmiana jednej klasy na drugą: handler Cheerio korzystał z $, a handler Playwright z page, jawnego oczekiwania i ekstrakcji po stronie przeglądarki.
Czym właściwie jest Crawlee
Crawlee (projekt apify/crawlee, wersja 3.17.0) to biblioteka do web scrapingu i automatyzacji przeglądarki dla Node.js i TypeScript. Obsługuje crawling HTTP oparty na Cheerio lub JSDOM oraz crawling w przeglądarce oparty na Playwright lub Puppeteer. Projekt jest objęty licencją Apache-2.0; przed użyciem w dystrybucji sprawdź wymagania dotyczące informacji licencyjnych i atrybucji.
Najważniejszy model myślenia jest taki: oddziel „pobierz stronę” od „odczytaj stronę”. Jedna ścieżka pobiera surowy HTML i nie uruchamia JavaScriptu. Druga uruchamia Chromium i może wykonywać skrypty strony, ale nadal wymaga odpowiedniego warunku gotowości i może nie zobaczyć treści ukrytej za interakcją, ładowanej leniwie, w shadow DOM, zwracanej przez nieudane API albo blokowanej przez anty-bota. Crawlee udostępnia spójne pojęcia cyklu życia dla obu ścieżek, ale nie daje wymiennych prymitywów DOM.
To właśnie warto zrozumieć zanim napiszesz pierwszy selektor, bo wybór między tymi dwoma silnikami decyduje o tym, czy scraper zwróci dane, czy pusty wynik na danej stronie.
Najważniejsze funkcje: dwa silniki, jedno API

CheerioCrawler pobiera HTML i parsuje go przez Cheerio; PlaywrightCrawler steruje Chromium i może robić zrzuty ekranu. Oba korzystają z requestHandler, udostępniają run() i współdzielą pojęcia takie jak kolejki oraz wykrywanie linków. Różni się jednak kontekst handlera: testowana ścieżka Cheerio pobierała dane przez $, a ścieżka przeglądarkowa używała page, waitForSelector i $$eval. Infrastruktura kolejki i cyklu życia może pozostać znajoma, ale kod ekstrakcji może wymagać adaptera albo przepisania.
Pod spodem Crawlee dostarcza elementy, których potrzebuje prawdziwy crawl. RequestQueue zarządza frontem adresów URL do odwiedzenia, deduplikuje je i śledzi wykonane zadania. enqueueLinks wykrywa i dodaje nowe adresy URL do kolejki (z filtracją po selektorze i hostname), dzięki czemu crawl może rozwijać się samodzielnie. Dataset gromadzi zebrane rekordy do eksportu. Domyślnie Crawlee zapisuje to wszystko do lokalnego katalogu storage/ na dysku — wygodne przy wznawianiu, choć trochę irytujące, gdy po raz pierwszy znajdujesz w projekcie folder storage/, którego nie prosiłeś się tam pojawić (mój harness przekierował to do katalogu tymczasowego i wyłączył trwałość, żeby test był czysty).
Poszczególne elementy same w sobie nie są niczym niezwykłym. Chodzi o to, że są współdzielone przez oba silniki, więc kolejka, wykrywanie linków i dataset działają tak samo niezależnie od tego, czy crawl odbywa się przez HTTP, czy przez przeglądarkę. Uczysz się jednego API i zyskujesz dwie strategie pobierania.
Konfiguracja: przeglądarka instalowana osobno
W testowanej instalacji po zainstalowaniu pakietów nie było dołączonego pliku wykonywalnego Chromium.

npm install crawlee playwright przebiegło u mnie bez problemów — 85 pakietów, 0 podatności, bez dramatu. Jeśli zatrzymasz się na tym etapie i uruchomisz CheerioCrawler, wszystko zadziała, bo crawling HTTP nie potrzebuje przeglądarki.
W tym środowisku Chromium trzeba było doinstalować osobno przez npx playwright install chromium; bez tego PlaywrightCrawler nie był w stanie wystartować. Zaobserwowany rozmiar ładunku przeglądarki wynosił około 82 MiB, ale w oryginalnych notatkach nie zachowano informacji, czy chodziło o rozmiar pobrania, czy o zajętość na dysku. To obserwacja zależna od maszyny, a nie stała cecha produktu. Ścieżki dokumentacji i zachowanie pakietów mogą się zmieniać, więc ten artykuł nie twierdzi, że pominięcie jest uniwersalne albo trwale nieudokumentowane.
Testowaną konfigurację warto planować jako dwa kroki: najpierw zainstalować pakiety Node, a potem doinstalować przeglądarkę używaną przez ścieżkę Playwright. Przed wdrożeniem ponownie sprawdź aktualne instrukcje konfiguracji Crawlee i Playwright dla swojej wersji i platformy.
W praktyce: ta sama strona, dwa bardzo różne wyniki

Główny test przepuścił ten sam fixture renderowany przez JavaScript przez oba crawlery. Adres URL i pola docelowe były wspólne; prymitywy ekstrakcji już nie.
Na lokalnym fixture CheerioCrawler zwrócił 0 docelowych kart, ponieważ nie było ich w surowym HTML. PlaywrightCrawler poczekał na #dynamic-products article.product-card, a następnie zwrócił wszystkie 8 oczekiwanych kart i zapisał zrzut ekranu. Ten wynik potwierdza kompletność fixture dla wybranych pól po tym oczekiwaniu; nie oznacza jednak, że przeglądarka widzi każdy możliwy stan strony. Surowe pliki i zrzut ekranu są w repozytorium benchmarku.

Na publicznej stronie Quotes to Scrape JS CheerioCrawler znalazł 0 docelowych cytatów, a PlaywrightCrawler poczekał na .quote, po czym wyodrębnił 10. To potwierdza tę samą granicę między HTTP a przeglądarką na publicznym celu, przy czym po obu stronach różnią się klasa crawlera, kontekst handlera, warunek oczekiwania i prymityw ekstrakcji.
Wniosek jest węższy, ale praktyczny: najpierw zweryfikuj wymagane pola po ścieżce HTTP, a dopiero gdy surowa odpowiedź ich nie zawiera, przechodź do crawlera przeglądarkowego. Handler przeglądarkowy musi też czekać na warunek powiązany z tymi polami.
Ścieżka HTTP zwróciła wszystkie oczekiwane rekordy na kontrolowanych fixture katalogu i artykułów, odczytała wszystkie osiem oczekiwanych elementów z bezpośredniej odpowiedzi JSON, przeszła 11-węzłowy ograniczony graf i przekazała jedną odpowiedź 500 do failedRequestHandler. To są osobne testy możliwości, a nie jeden wynik dokładności. Wobec publicznej strony Books to Scrape skonfigurowany selektor zwrócił 20 produktów jako test dymny.
| Test | Silnik | Wynik |
|---|---|---|
| Ekstrakcja statyczna: katalog + paginacja | CheerioCrawler | 12/12 oczekiwanych produktów |
| Ekstrakcja artykułu | CheerioCrawler | tytuł + 3/3 akapity |
| Transport: bezpośrednia odpowiedź JSON | CheerioCrawler | 8/8 oczekiwanych produktów |
| Przechodzenie: graf linków wewnętrznych | CheerioCrawler | 11 stron, głębokości {0:1, 1:3, 2:7} |
| Obsługa błędu: HTTP 500 | CheerioCrawler | status trafił do handlera błędów |
| Renderowanie: lokalny fixture | CheerioCrawler | 0 docelowych kart w surowym HTML |
| Renderowanie: lokalny fixture | PlaywrightCrawler | 8/8 po oczekiwaniu na selektor docelowy |
| Renderowanie: Quotes JS | CheerioCrawler | 0 docelowych cytatów w surowym HTML |
| Renderowanie: Quotes JS | PlaywrightCrawler | 10 po oczekiwaniu na selektor docelowy |
Pełne czasy i liczby dla każdego testu znajdują się w results/crawlee-test-summary.json.
Teraz uczciwe zastrzeżenia, bo pojedynczy test na jednej maszynie ma swoje ograniczenia i nie będę udawać, że jest inaczej. To są czasy, nie benchmarki — jedna maszyna, po jednym uruchomieniu, więc wyższy koszt przeglądarki na stronę traktuj jako „wyraźnie wolniejszy niż subsekundowe uruchomienia Cheerio”, a nie jako opublikowaną metrykę. Jest też sporo rzeczy, których w tym podejściu nie testowałem: rotacji proxy, pul sesji, dużych uruchomień liczących setki lub tysiące stron, trwałości RequestQueue i wznawiania po awarii, silnika Puppeteer oraz ergonomii eksportu Dataset/KeyValueStore (eksport pisałem tu ręcznie). Mogę potwierdzić historię dwóch silników i dokładność na poziomie fixture. Nie mogę potwierdzić skalowalności ani zachowania wobec blokad i nie zamierzam tego deklarować.
Co jest wspólne, a co trzeba zmienić

Wspólna jest orkiestracja crawlingu. Obie klasy crawlerów przyjmują requestHandler i udostępniają run(). Kolejki, metadane żądań, wykrywanie linków, hooki błędów i pojęcia storage można organizować spójnie wokół obu ścieżek wykonania. To zmniejsza ilość infrastruktury, którą zespół musi poznawać od nowa, gdy jeden cel wymaga przeglądarki.
Wspólny nie jest natomiast dostęp do strony. Handler CheerioCrawler otrzymuje dostęp w stylu Cheerio, np. $, i może pracować z treścią odpowiedzi bez przeglądarki. Testowany handler PlaywrightCrawler otrzymuje page; czeka na selektor i wykonuje zapytania po DOM przeglądarki. Nawet jeśli oba handlery zwracają ten sam schemat rekordu, dochodzą do niego przez różne API. Reużywalny adapter mógłby ukryć część tej różnicy, ale ten harness nie implementował ani nie demonstrował takiego rozwiązania.
To rozróżnienie ma znaczenie przy szacowaniu prac. Zmiana klasy crawlera może zachować kolejkę, dataset i politykę URL, ale selektory, warunki gotowości, zrzuty ekranu, kroki interakcji i obsługa błędów nadal mogą się zmienić. Artykuł traktuje więc „wspólną infrastrukturę crawlingu” jako potwierdzoną korzyść, a nie wspiera obietnicy „migracji jednym wierszem”.
Praktyczny schemat wyboru silnika
Zacznij od ścieżki HTTP, jeśli zwracany HTML lub bezpośrednia odpowiedź JSON zawiera wymagane pola. Zdefiniuj kontrakt kompletności — wymagane klucze, minimalną liczbę elementów lub docelowy selektor — i jawnie zgłaszaj błąd, gdy nie jest spełniony. Pusta tablica nie dowodzi, że strona nie ma danych; w dwóch przypadkach JavaScript z tego testu oznaczała po prostu, że wybrana reprezentacja nie zawierała docelowych elementów.
| Warunek docelowy | Zacznij od | Eskaluj, gdy |
|---|---|---|
| Wymagane pola są w zwróconym HTML | CheerioCrawler | Brakuje wymaganych selektorów lub pól |
| Dane znajdują się w powtarzalnej odpowiedzi JSON | CheerioCrawler | Żądanie zależy od stanu dostępnego tylko w przeglądarce |
| Strona wstawia elementy docelowe dopiero po wykonaniu skryptów | PlaywrightCrawler | Nie dotyczy; zdefiniuj warunek gotowości specyficzny dla celu |
| Mieszanka celów jest nieznana | Najpierw HTTP z walidacją kompletności | Walidacja zwraca typowany wynik „reprezentacja niekompletna” |
Tę typowaną porażkę przekaż dalej do handlera przeglądarkowego, gdy wykonanie JavaScriptu jest konieczne. W tym harnessie lokalna strona czekała na #dynamic-products article.product-card, a publiczna strona z cytatami na .quote. Te warunki są częścią kontraktu ekstrakcji. Ogólny event załadowania strony nie potwierdziłby, że dane aplikacji już się pojawiły, a test nie uzasadnia uniwersalnej reguły oczekiwania.
Po eskalacji utrzymuj stabilny schemat wyjścia, nawet jeśli prymitywy DOM są różne. Rejestruj, który silnik zwrócił wynik, jaki warunek gotowości został spełniony i czy walidacja wymaganych pól zakończyła się sukcesem. Dzięki temu fallback z HTTP do przeglądarki jest widoczny, zamiast po cichu zamieniać brakujące pola w zaakceptowane rekordy.
Na koniec traktuj instalację i koszt działania przeglądarki jako wejściowe założenia wdrożeniowe. Obserwacja około 82 MiB jest przydatna jedynie jako lokalny rząd wielkości; w swoim środowisku zmierz dokładny build przeglądarki, platformę, zachowanie cache i wpływ obrazu. Rotacja proxy, sesje, trwałość, odzyskiwanie po awarii i stała współbieżność nadal wymagają własnych testów, zanim ten fixture posłuży do wyboru na poziomie produkcyjnym.
Zalety i wady
Zalety:
- Crawlery HTTP i przeglądarkowe współdzielą pojęcia cyklu życia, a jednocześnie udostępniają kontekst ekstrakcji specyficzny dla silnika.
- Ekstrakcja HTTP z pełną zgodnością na statycznych katalogach, artykułach i API JSON.
- Wspólna infrastruktura dla obu silników:
RequestQueue,enqueueLinksz kontrolą głębokości,Dataset. - Ścieżka przeglądarkowa wykonała skrypty fixture i odzyskała wszystkie oczekiwane elementy w dwóch testach renderowanych przez JS.
- Czysta obsługa błędów — HTTP 500 pojawił się bez awarii procesu.
- Licencja Apache-2.0; użytkownicy downstream powinni sprawdzić obowiązki dotyczące informacji licencyjnych i atrybucji.
Wady:
- W testowanym środowisku silnik przeglądarkowy wymagał osobnej instalacji Chromium; bez tego
PlaywrightCrawlernie startował. - Ścieżka HTTP nie pokaże elementów docelowych, których nie ma w surowym HTML; bez walidacji kompletności może to wyglądać jak poprawny pusty wynik.
- Ścieżka przeglądarkowa wiąże się z dodatkowym binarium przeglądarki i wyższym lokalnym kosztem na stronę w tym uruchomieniu; rozmiar i czas zależą od buildu i platformy.
- Domyślne uruchomienia zostawiają na dysku katalog
storage/. - Tylko Node/TypeScript — brak wsparcia, jeśli Twój stack to Python.
Dla kogo to jest — a kto powinien odpuścić
Crawlee dobrze pasuje do zespołów Node lub TypeScript, które potrzebują zarówno crawlingu HTTP, jak i przeglądarkowego w ramach wspólnej orkiestracji i wspólnych pojęć cyklu życia. Praktyczna ścieżka to najpierw próbować crawlera HTTP, walidować wymagane pola, a typowaną porażkę kompletności eskalować do handlera przeglądarkowego z warunkiem gotowości dopasowanym do celu. Kod DOM w handlerze jest zależny od silnika, nawet jeśli infrastruktura kolejki i wykrywania linków jest współdzielona.
Zresetuj oczekiwania albo poszukaj innego narzędzia, jeśli pracujesz w Pythonie (Crawlee jest dla Node/TS — istnieje osobny port dla Pythona, ale ten test dotyczył biblioteki Node), jeśli wszystkie cele są statyczne i wolisz lżejszy, wyspecjalizowany scraper HTTP, albo jeśli potrzebujesz potwierdzonego działania na dużą skalę — rotacji proxy, pul sesji, wznawiania po awarii — czego to praktyczne sprawdzenie nie obejmowało. A jeśli sięgasz po PlaywrightCrawler, najpierw zainstaluj Chromium, bo inaczej po prostu nie ruszy.
Alternatywy, w tym miejsce Thunderbit
Crawlee to oprogramowanie open source, które uruchamiasz i utrzymujesz samodzielnie. Nie ma opłaty vendorowej za każde wywołanie, ale koszty operacyjne nadal obejmują moc obliczeniową przeglądarki, transfer, proxy, storage, obserwowalność i pracę inżynierską. To Ty odpowiadasz za wybór crawlera, binarium przeglądarki, stan storage i logikę gotowości.
Powiązana recenzja: recenzja scrapy-playwright.
Usługa zarządzana do ekstrakcji przenosi odpowiedzialność za pobieranie i kształtowanie schematu na dostawcę. Tworzymy Thunderbit, ale nie uruchamialiśmy go na tych fixture, więc ten artykuł nie pozwala na porównanie jakości, opóźnień, zgodności funkcji ani kosztów. Kluczowa decyzja brzmi: czy Twój zespół chce kontroli w procesie Crawlee, czy granicy usługi rozliczanej za wywołanie.
Powiązane recenzje benchmarkowe: pełne porównanie open-source scraperów, Playwright vs Puppeteer na tych samych stronach oraz recenzja Scrapy bez żądań przez przeglądarkę.
Wypróbuj Thunderbit do ekstrakcji danych z sieci
Werdykt
Crawlee to mocny kandydat dla zespołów Node lub TypeScript, które chcą wspólnej orkiestracji crawlingu dla HTTP i przeglądarki. Testowane handlery nie były wymienne: przejście na Playwright wymagało page, oczekiwania na selektor docelowy i ekstrakcji po stronie przeglądarki. Zachowanie proxy, sesji, trwałości, wznowienia i działania na dużą skalę pozostaje otwartym pytaniem.
Wypróbuj Thunderbit do ekstrakcji danych z sieci Get Started Free
FAQ
Jaka jest prawdziwa różnica między dwoma crawlerami Crawlee?
CheerioCrawler pobiera HTML przez HTTP i nie uruchamia JavaScriptu. PlaywrightCrawler steruje Chromium i może wykonywać skrypty strony oraz robić zrzuty ekranu, ale wiąże się z wyższym lokalnym kosztem na stronę. Współdzielą pojęcia cyklu życia, ale nie identyczny kontekst handlera: w tym teście ścieżka HTTP używała $, a ścieżka Playwright korzystała z page, oczekiwania na selektor docelowy i ewaluacji po stronie przeglądarki.
Dlaczego PlaywrightCrawler nie uruchamia się po zainstalowaniu Crawlee?
W testowanym środowisku instalacja pakietu nie dostarczyła wykonywalnego pliku przeglądarki. Instalacja Chromium przez npx playwright install chromium rozwiązała problem uruchomienia. Zaobserwowany ładunek miał około 82 MiB, ale oryginalny pomiar nie zachował informacji, czy był to transfer, czy rozmiar na dysku, więc należy to zmierzyć ponownie dla swojej platformy i buildu.
Czy CheerioCrawler potrafi scrapować strony renderowane przez JavaScript?
Nie uruchamia JavaScriptu strony. Może jednak pobrać dostępny endpoint JSON używany przez klienta, jak pokazuje fixture z bezpośrednią odpowiedzią. Jeśli wymagane dane pojawiają się dopiero po wykonaniu skryptów w przeglądarce, użyj crawlera przeglądarkowego i warunku gotowości powiązanego z tymi polami.
Czy Crawlee jest dokładne przy zwykłej ekstrakcji statycznej? Na kontrolowanych fixture handlery zwróciły 12/12 oczekiwanych produktów katalogu, 3/3 oczekiwane akapity artykułu i 8/8 oczekiwanych elementów z bezpośredniego JSON. To są testy kompletności fixture, a nie ogólny wynik dokładności dla nieprzetestowanych stron.
Czy Crawlee jest darmowe do użytku komercyjnego? Jest wydane na licencji Apache-2.0. Sprawdź aktualną licencję w repozytorium i zweryfikuj obowiązki dotyczące informacji licencyjnych oraz atrybucji dla swojej dystrybucji.
Przed wdrożeniem produkcyjnym przetestuj elementy, których ten fixture nie obejmuje: powtarzalną współbieżność na reprezentatywnych stronach, działanie proxy i sesji, trwałe odzyskiwanie kolejki po przerwaniu, zamykanie procesów przeglądarki oraz eksport datasetu przy błędach. Zachowaj z tymi wynikami wersję przeglądarki i ścieżkę instalacji. Dwie klasy crawlerów ograniczają rozbieżność w orkiestracji, ale nie eliminują potrzeby specyficznych dla silnika testów gotowości, budżetów zasobów i obsługi błędów operacyjnych.


