Browserless to Chrome uruchamiany bez interfejsu, spakowany jako usługa hostowana samodzielnie. Jego kontener Docker działa cały czas, przyjmuje zadania przez HTTP albo WebSocket i egzekwuje wspólne limity przyjęć zamiast być osadzany w każdej aplikacji wywołującej. W testach REST ta usługa trzymała zero procesów Chrome w spoczynku, uruchamiała procesy Chrome podczas aktywnego żądania, a po zakończeniu wracała do zera. To, co jest współdzielone, to przepustowość usługi i kolejka, a nie potwierdzony zestaw wcześniej rozgrzanych procesów przeglądarki.
Sprawdziłem wersję v2.55.0 na kontrolowanym lokalnym fixture — startup rozłożony na etapy, kontrolę przyjęć w trzech konfiguracjach, zgodność endpointów z ustalonym wzorcem referencyjnym, 30 sesji soak testu oraz granicę timeoutu. Najbardziej użyteczny efekt był operacyjny, a nie wydajnościowy: limity przyjęć zgadzały się z odpowiedziami widocznymi po stronie klienta, a największe problemy wynikały głównie z charakteru wdrożenia.
Najcenniejszy wynik wcale nie był liczbą opóźnienia. Browserless nie przyspiesza uruchamiania Chrome — tylko nakłada na Chrome politykę wejścia: określoną liczbę sesji wewnątrz, kolejkę za nimi i HTTP 429 dla reszty. Ten pułap zmienił się z 4 na 8 i potem na 10, gdy zmieniłem dwie zmienne środowiskowe, a własne rozliczenia kontenera zgadzały się ze statusami klienta przy każdym pojedynczym żądaniu.
Czym Browserless tak naprawdę jest
Właśnie na tej kategorii wiele osób się potyka. Browserless nie jest biblioteką, którą importujesz i wywołujesz. To obraz Docker — ghcr.io/browserless/chromium — uruchamiany jako długowieczna usługa. Pośredniczy w pracy przeglądarki i wystawia ją na dwa sposoby: endpointy REST (/content, /scrape, /screenshot, /pdf, a także /function i /unblock) oraz interfejs CDP/WebSocket, z którym mogą łączyć się Puppeteer i Playwright przez connect().
Testowałem powierzchnię REST. Ścieżka WebSocket jest realna i szeroko używana, ale jej nie mierzyłem.
Badana wersja to v2.55.0, sprawdzona 27 lipca 2026.
| Element | Wartość |
|---|---|
| Wersja obrazu | v2.55.0, opublikowana 14 lipca 2026 |
| Chrome | 149.0.7827.0 |
| Node | 24.18.0 |
| Bazowy obraz | Ubuntu 24.04 |
| Gwiazdki na GitHub | około 13 525 na dzień 27 lipca 2026 |
Liczba gwiazdek się zmienia; traktuj to jako odczyt z danego momentu.
Bramka licencyjna: SSPL-1.0 albo licencja komercyjna
Repozytorium udostępnia Browserless na warunkach SSPL-1.0 lub komercyjnej licencji Browserless. Przed wyborem ścieżki koniecznie przeczytaj aktualny plik LICENSE w repozytorium oraz oficjalne wytyczne wdrożeniowe open source Browserless. Ten artykuł nie przeprowadzał analizy prawnej produktów komercyjnych, aplikacji closed-source, systemów CI, hostowanych usług ani wdrożeń wewnętrznych, więc nie przypisuje tych scenariuszy do konkretnej licencji. Poproś prawnika albo osobę odpowiedzialną za licencjonowanie o ocenę modelu wdrożenia i dystrybucji.
Browserless sprzedaje też plany hostowane. Ceny i definicje jednostek użycia są zmienne i nie były częścią tego testu self-hosted, więc weryfikuj je na oficjalnej stronie, zamiast traktować starą tabelę z tego tekstu jako dowód zakupowy.
Jak działa model sesji pod maską
Mierzona ścieżka REST zachowywała się jak praca przeglądarki wykonywana per żądanie, ale ten harness nie śledził wnętrza Browserless na tyle głęboko, by odróżnić nowy proces browsera od każdej możliwej strategii ponownego użycia kontekstu. Udało się ustalić coś prostszego: zero procesów Chrome w spoczynku, 11 procesów z rodziny chrome podczas aktywnego żądania i zero po zakończeniu sekwencyjnego runu. W tej konfiguracji nie było dowodów na rozgrzaną wcześniej pulę przeglądarek.
Długowieczna usługa Node przyjmuje ograniczoną liczbę zadań przeglądarki, kolejną ograniczoną pulę ustawia w kolejce, a resztę odrzuca. Traktuj ten model przyjęć jako kontrakt architektoniczny zmierzony poniżej. Nie wyciągaj wniosków o ponownym użyciu procesów lub kontekstów z samego słowa „pool”; harness czasowy nie może tego dowieść.
Kontrola przyjęć ma dwa pokrętła:
CONCURRENT— ile sesji działa jednocześnie.QUEUED— ile dodatkowych żądań może czekać na wolne miejsce.
Endpoint /config w kontenerze zwracał domyślnie CONCURRENT=10, QUEUED=10, TIMEOUT=30000. Wszystko powyżej CONCURRENT + QUEUED jest odrzucane natychmiast.
Uwierzytelnianie nie jest opcjonalne. Browserless v2 zawsze wymaga tokenu — jeśli nie ustawisz TOKEN, wygeneruje losowy i wypisze go do stdout przy starcie. Każde wywołanie REST zawiera ?token=.
Do obserwowalności dostajesz /pressure (running, queued, CPU, memory, recently rejected), /sessions oraz /config. Jest też eksport JSON /metrics, ale wymaga ustawienia METRICS_JSON_PATH i nie korzystałem z niego. Obraz uruchamia też dumb-init jako PID 1, co jest udokumentowaną odpowiedzią na skargi dotyczące procesów zombie, które od lat towarzyszą uruchamianemu w kontenerach Chrome.
Rzeczywistość wdrożenia: jedna komenda i cztery rzeczy, których nikt nie wkłada do tej jednej komendy
Linia instalacyjna, którą wszyscy cytują, to faktycznie jedno docker run. To, co dookoła, trzeba zaplanować samemu.
Obraz ma 4,34 GB. To jest liczba, która powinna ustawić Twoje oczekiwania, a nie czas startu. Manifest obejmuje zarówno linux/arm64, jak i linux/amd64; na moim hoście arm64 Docker pobrał natywny wariant arm64. (User-agent Chrome wewnątrz kontenera i tak pokazuje X11; Linux x86_64 — to kosmetyczny UA Chrome na Linuksie, a nie emulacja. uname -m zwraca aarch64. Ludzie zgłaszają na to błędy.)
Do każdego pomiaru użyłem --shm-size=2g. Harness nie zawierał uruchomienia kontrolnego przy domyślnym /dev/shm Dockera, więc ten artykuł nie może twierdzić, że 2 GiB są uniwersalnie konieczne ani określić punktu awarii. Dobierz wartość do liczby przeglądarek i rodzaju obciążenia.
Token to kwestia wdrożeniowa, nie formalność. Bez niego każdy, kto ma drogę do portu 3000, kontroluje przeglądarkę w Twojej sieci.
Sieć kontenerowa to Twój problem. Mój fixture działał na hoście, więc kontener docierał do niego przez host.docker.internal (colima mapuje to przez --add-host host.docker.internal:host-gateway). Zanim zaufałem jakimkolwiek pomiarom, sprawdziłem zwykłym curl, że kontener rzeczywiście widzi fixture.
Moje środowisko: colima 0.10.3 (6 CPU / 11.6 GiB) z Dockerem 29.2.1 na macOS 26.5.2 arm64. Harness korzystał wyłącznie ze standardowej biblioteki Pythona 3. Dla PNG i PDF sprawdzał sygnatury plików, a nie poprawność dekodera, wymiary, liczbę stron, kompletność ani zgodność wizualną.
Minimalny odpowiednik uruchomienia używa przypiętego obrazu, jawnego tokenu i alokacji pamięci współdzielonej użytej tutaj:
docker run --rm -p 3000:3000 --shm-size=2g \
-e TOKEN=replace-with-a-secret \
ghcr.io/browserless/chromium:v2.55.0
Gdy /pressure?token=... odpowie, autoryzowany POST /content?token=... z ciałem JSON zawierającym docelowy URL uruchamia ścieżkę REST. Produkcyjni klienci potrzebują też ograniczonych prób ponownych z jitterem dla odpowiedzi 429; natychmiastowe ponawianie po prostu zderza się z tą samą pełną kolejką.
Koszt startu rozłożony na etapy

Trzy świeże starty docker run, mediany z min–max:
| Etap | Mediana | Zakres | Czym to naprawdę jest |
|---|---|---|---|
docker run → /pressure zwraca 200 | 0.78 s | 0.70–0.87 s | endpoint HTTP odpowiada; ten test nie potwierdza uruchomienia przeglądarki |
gotowe → pierwszy render /content | 0.32 s | 0.28–0.41 s | zaobserwowano pierwsze żądanie: praca przeglądarki + nawigacja + zwrot HTML |
późniejsze wywołania /content | 0.15 s | 0.147–0.154 s | zaobserwowane opóźnienie kolejnych żądań w tym samym kontenerze |
Środkowy wiersz łatwo nadinterpretować. Nie mierzy on uruchomienia przeglądarki w izolacji i nie pokazuje, że Browserless startuje Chrome szybciej niż biblioteka działająca w tym samym procesie. To jest podróż HTTP do kontenera plus praca przeglądarki, nawigacja i transfer odpowiedzi. Około 0,17 sekundy różnicy między pierwszym a kolejnymi wywołaniami może wynikać z systemu plików, systemu operacyjnego, Chrome, Node albo cache kontenera. Ponieważ procesy Chrome były zerowe w spoczynku, a harness nie zebrał żadnego śladu CDP ani osi czasu procesów dla tych wywołań, nie da się przypisać tej różnicy ponownemu użyciu przeglądarki ani „rozłożonemu w czasie” kosztowi startu.
I jeszcze jedno: to są liczby z colima-VM na macOS. Na czystym Linuksie będą inne. Nie cytuj 0.78 s swojemu SRE tak, jakby to była wartość przenośna.
Praktyka: wyznaczanie sufitu z obu stron
Kontrakt CONCURRENT + QUEUED → 429 jest wszędzie powtarzany, ale nigdzie nie pokazany.
Ustawienie było takie: route fixture, który po stronie serwera śpi 5 sekund, dzięki czemu każde żądanie niezawodnie zajmuje jedną sesję przez znany czas. Następnie wyślij jednocześnie CONCURRENT + QUEUED + 4 żądania i sprawdź, co wróci — podczas gdy osobny wątek próbkujący odczytuje /pressure, czyli własne rozliczenia kontenera.
| Konfiguracja (CONCURRENT, QUEUED) | Wysłano | HTTP 200 | HTTP 429 | Szczyt na serwerowym /pressure (running / queued / recentlyRejected) |
|---|---|---|---|---|
| (2, 2) | 8 | 4 | 4 | 2 / 2 / 4 |
| (3, 5) | 12 | 8 | 4 | 3 / 5 / 4 |
| (5, 5) | 14 | 10 | 4 | 5 / 5 / 4 |
Z tego wynikły trzy rzeczy.
Sufit to zawsze dokładnie CONCURRENT + QUEUED. Odpowiedzi udane wyniosły 4, 8 i 10 — czyli w każdym przypadku skonfigurowaną sumę. Odrzucenia równały się nadmiarowi, a ten wynosił 4 we wszystkich trzech testach.
Sufit się przesuwa. Nie jest to wartość na stałe wpisana w obraz; to to, co skonfigurujesz. Przejście 4 → 8 → 10 przez zmianę zmiennych środowiskowych jest właśnie tym, co czyni to użytecznym, a nie jedynie ciekawostką.
Oba sygnały są niezależne. Statusy mojego klienta pochodziły z rzeczywistych odpowiedzi HTTP; /pressure pochodził z wewnętrznego rozliczenia kontenera, odczytywanego przez inny wątek. W tych trzech krótkich przebiegach zgadzały się. To czyni /pressure kandydatem na sygnał produkcyjny, ale nie kompletny kontrakt autoskalowania: częstotliwość próbkowania, semantyka resetu, agregacja wielu replik i zachowanie przy dłuższych mieszanych obciążeniach nadal wymagają weryfikacji.
Jeden niuans ukryty przez liczby zaliczone/odrzucone. Żądanie z kolejki nie kończy się błędem — czeka, i może czekać długo. Przy (2, 2) i 5-sekundowej pracy udane odpowiedzi pojawiały się od 5,7 s do 11,0 s, mediana wyniosła 8,3 s. End-to-end latency doszła więc mniej więcej do dwóch czasów sesji. Harness nie rejestrował oddzielnych znaczników czasu przyjęcia i wykonania, więc nie da się przypisać całego opóźnienia samemu czekaniu w kolejce.
Jak to wygląda przy prawdziwym zadaniu
Załóżmy, że co noc renderujesz do PDF 4 000 stron produktowych, a każda strona zajmuje około 5 sekund. Ustawiasz CONCURRENT=5, QUEUED=5. Twój limit przepustowości to 5 stron na 5 sekund — czyli jedna strona na sekundę — więc zadanie zajmie około 67 minut, jeśli utrzymasz potok dokładnie pełny. To arytmetyka oparta na zmierzonym zachowaniu, a nie benchmark, ale dokładnie taką arytmetykę powinieneś wykonać przed wdrożeniem.
Każde żądanie, które pojawi się po zajęciu wszystkich slotów wykonywania i kolejki, może od razu dostać 429; jednoczesne wysłanie nie gwarantuje, które żądanie przegra wyścig. Runner zadań powinien traktować tę odpowiedź jako backpressure i stosować ograniczone ponawianie z jitterem. W przeciwnym razie ryzykuje utratę stron, podczas gdy wyższy poziom rozliczania zadań nadal idzie dalej — to ryzyko operacyjne, a nie scenariusz awarii pokazany przez ten harness.
Praktyka: co faktycznie widzą endpointy
Żeby uczciwie sprawdzić zgodność renderowania, strona fixture ukrywa tekst markerowy przed każdym, kto nie uruchamia prawdziwej przeglądarki. Widoczny ciąg Runtime Injected Marker 88 jest składany z fragmentów JavaScript w czasie ładowania, więc w żadnym bajcie wysyłanym przez serwer nie istnieje ciągły literal tego tekstu. Zwykły statyczny fetch tej strony zwraca 702 bajty i nie zawiera żadnego markera.
| Endpoint | Wynik | Bajty |
|---|---|---|
/content | marker wstrzyknięty w runtime obecny, plus oba markery statyczne | 811 |
/scrape na #scrape-me (node wstrzykiwany przez JS) | zwrócono SCRAPE_TARGET_VALUE_CC | 422 |
/screenshot | odpowiedź z sygnaturą PNG 89 50 4E 47 | 18 621 |
/pdf | odpowiedź z sygnaturą PDF %PDF- | 40 974 |
| wszystkie cztery, bez tokenu | HTTP 401 (nie 403) | — |
To, że /content zwrócił 811 bajtów z wstrzykniętym markerem, oznacza, że prawdziwy Chromium wyrenderował stronę, zanim HTML wrócił. /scrape wyciągnął wartość z węzła, który nie istnieje, dopóki nie uruchomi się JavaScript. Oba działały przy zerowym kodzie automatyzacji po stronie klienta — pojedynczym autoryzowanym POST-em.
To jest faktyczna obietnica tego rozwiązania. W tej samej serii testów statyczny crawler całkowicie przeoczył ten typ treści, a biblioteki przeglądarkowe działające w procesie (chromedp, rod, Selenium) wyłapały ją dopiero po dodaniu jawnego oczekiwania. Browserless złapał ją żądaniem o kształcie curl. Zamieniasz kod automatyzacji na ciężar wdrożeniowy.
Dwie granice tego stwierdzenia. Dowody obejmują klasy treści z mojego fixture, a nie przegląd całego współczesnego internetu. I endpoint /unblock, służący do omijania detekcji, został celowo pominięty — żadnego z tych wyników nie należy czytać jako deklaracji możliwości anti-bot. /function, /download i /performance też nie były testowane.
Praktyka: krótki test pozostałości
Chrome uruchamiany w kontenerach ma opinię zostawiania trupów po sobie, więc wykonałem 30 kolejnych sesji z CONCURRENT=3 i policzyłem procesy wewnątrz kontenera.
Zanim uwierzyłem w cokolwiek, skalibrowałem detektor. Gdy sesja była w toku, enumerator /proc widział 11 procesów z rodziny chrome (browser, zygote, GPU, renderery, utilities). To ważne: dowodzi, że instrument potrafi zobaczyć Chrome, więc wynik zero po zakończeniu to pomiar, a nie ślepota. Test wycieków, który raportuje „0 procesów” bez dowodu, że umie liczyć, jest bezwartościowy.
Po 30 sesjach: 0 procesów chrome, 0 zombie. Jedynymi ocalałymi były dumb-init, node, Xvfb, start.sh i sh. /sessions pokazywał 0 w spoczynku.
Zużycie pamięci kontenera z docker stats (czyli liczba widoczna dla operatora, a nie RSS pojedynczego procesu):
| Po N sesjach | 0 | 5 | 10 | 15 | 20 | 25 | 30 |
|---|---|---|---|---|---|---|---|
| Pamięć kontenera (MiB) | 294 | 300 | 301 | 302 | 302 | 303 | 303 |
Łączny wzrost po 30 sesjach: około 9,5 MB, a obserwowana krzywa spłaszczyła się po 10. To nie zgadza się z prostym liniowym wyciekiem na sesję w tak krótkim oknie. Jednym z możliwych wyjaśnień jest rozgrzewka Node, ale sam licznik procesów i seria pamięci nie są w stanie tego dowieść.
Zakres: 30 kolejnych sesji to mały soak test, nie test wytrzymałości ani test współbieżny. Długotrwałe ostrzeżenia EventEmitter listener obecne w trackerze zgłoszeń to rodzaj problemu, który może wyjść po godzinach i tysiącach sesji, a ja tego nie uruchamiałem. Wspierany wniosek brzmi tylko tyle, że w tym oknie na v2.55.0 nie zaobserwowano narastania procesów Chrome ani zombie.
Granica timeoutu
TIMEOUT jest opisany jako pokrętło. Chciałem zobaczyć, jak zadziała.
| Przypadek | Utrzymanie strony | Status | Czas |
|---|---|---|---|
| Poniżej budżetu | 2 000 ms | 200 | 2,406 s |
| Powyżej budżetu | 15 000 ms | 408 | 5,007 s |
Przy TIMEOUT=5000 sesja, która próbowała utrzymać stronę przez 15 sekund, zwróciła HTTP 408 po 5,007 s zamiast wisieć. Ta pojedyncza obserwacja potwierdza egzekwowanie w pobliżu skonfigurowanej granicy. Nie ujawnia mechanizmu timera ani nie dowodzi zwolnienia slotu; mocniejszy test powtórzyłby próbę, obserwowałby powrót /sessions i /pressure do stanu idle, a następnie potwierdził, że kolejne żądanie przejmuje uwolniony slot.
Pułapka migracji: PREBOOT jest martwe i nic Ci o tym nie powie
Ze wszystkich zmierzonych rzeczy to wynik, który najchętniej dostałbym do ręki przed aktualizacją.
Browserless 2.0.0 usunął PREBOOT i KEEP_ALIVE — changelog mówi, że usunięto je, bo były mylące, niewiele robiły i powodowały błędy. Rozsądna decyzja. Problem zaczyna się wtedy, gdy konfigurację z v1 przekopiuje się do v2, a właśnie tak robi większość osób aktualizujących.
Uruchomiłem kontener z -e PREBOOT=true i porównałem go z domyślną konfiguracją:
| Sygnał | PREBOOT=true | Domyślnie, bez flagi |
|---|---|---|
| Czas gotowości | 0,716 s | 0,776 s |
| Cold render | 0,314 s | 0,318 s |
| Warm render | 0,163 s | 0,150 s |
| Procesy Chrome w spoczynku | 0 | 0 |
Wszystkie czasy mieszczą się we własnym paśmie min–max domyślnej gałęzi — to szum, nie efekt. I nic nie zostało rozgrzane wcześniej: kontener z PREBOOT=true stoi bez żadnej przeglądarki w spoczynku, identycznie jak ten bez flagi. Dwa kolejne sygnały, żaden z nich nie jest liczbą:
/confignie pokazuje żadnego kluczapreboot. Klucze toconcurrent,queued,timeout,token,maxCPU,maxMemory,retriesi podobne.- Żadnego błędu. Żadnego ostrzeżenia. Nic w logach kontenera.
Tak więc konfiguracja v1 z PREBOOT na v2 jest cichym no-opem przy zwykłym starcie i sprawdzaniu logów. Brak klucza /config plus niezmienione zachowanie to wykrywalny sygnał; Browserless nie emituje jawnego odrzucenia ani ostrzeżenia. Kontrola migracji musi sprawdzać zastosowaną konfigurację, zamiast traktować zielony startup jako dowód, że każda zmienna środowiskowa zadziałała.
KEEP_ALIVE to przypadek odwrotny i nie należy ich wrzucać do jednego worka. Został usunięty w tej samej wersji, ale nie milczy — szybki probe kontenera pokazuje, że loguje Environment variable of "KEEP_ALIVE" is deprecated and ignored. prosto do stdout. To jest prawidłowe ostrzeżenie dla operatora. Nie przepuszczałem KEEP_ALIVE przez ten sam mierzalny harness, przez który przeszedł PREBOOT, więc podaję to jako sprawdzenie, a nie jako pomiar. Kierunek jest jednak wystarczająco jasny, by mieć znaczenie: tylko PREBOOT jest cichą pułapką. Browserless jest bardziej szczery w sprawie KEEP_ALIVE, niż sugerowałoby ogólne stwierdzenie, że „v2 ignoruje flagi z v1”.
Plusy i minusy
Plusy
- Kontrola przyjęć działająca dokładnie tak, jak opisano, i zmieniająca się wraz z konfiguracją — potwierdzona przy trzech różnych sufitach, jednocześnie po stronie statusów klienta i własnych rozliczeń serwera.
/pressurezgadzał się z widocznymi po stronie klienta licznikami running, queued i rejected w trzech krótkich przebiegach; można go rozważyć jako jeden z kandydatów na wejście do autoskalowania i alertingu.- Prawdziwy Chromium renderujący bez żadnego kodu automatyzacji po stronie klienta: jeden autoryzowany POST ujawniał DOM wstrzyknięty przez JS, którego statyczny fetch tej samej strony nie widzi.
- W 30-krotnej sekwencyjnej sesji nie zaobserwowano narastania procesów Chrome; po zakończeniu było 0 procesów Chrome i 0 zombie.
- Jedna próba
TIMEOUTzwróciła 408 po 5,007 s przy budżecie 5,000 s; osobno nie weryfikowano cleanupu ani zwalniania slotu. - Uwierzytelnianie włączone domyślnie: wszystkie cztery endpointy REST zwracają 401 bez tokenu.
- Jedno
docker rundo gotowej usługi w około 0,78 s, a pierwszy render 0,32 s później.
Minusy
- Obraz 4,34 GB. To uczciwy koszt na wejściu, widoczny w rejestrze, cache CI i czasie cold deployu.
- SSPL-1.0 albo komercyjna licencja Browserless. Oceniaj dokładne aktualne warunki względem swojego modelu wdrożenia i dystrybucji.
PREBOOTz v1 jest akceptowane i po cichu ignorowane w v2 — bez błędu, bez ostrzeżenia, bez klucza/config.- Obsługujesz usługę, a nie dodajesz zależność: kontener, token, ścieżkę sieciową, limit przyjęć i odpowiedzialność za aktualizacje.
- Żądania w kolejce podnosiły opóźnienie end-to-end do mniej więcej dwóch czasów sesji w teście
(2, 2); osobno czasu oczekiwania w kolejce nie mierzono. - Zmierzone czasy REST obejmują dodatkowy skok HTTP i nie izolują kosztu startu przeglądarki ani nie dowodzą ponownego użycia przeglądarki.
Kto powinien, a kto nie powinien tego używać
Browserless ma sens, gdy więcej niż jedna rzecz potrzebuje przeglądarki. Wspólny serwis renderujący dla kilku aplikacji, zespół, który chce screenshoty i PDF-y przez endpoint HTTP zamiast zależności od Chrome w każdej usłudze, pipeline zadań naprawdę potrzebujący limitu pojemności z mierzalnym backpressure — to jest właśnie ten kształt. Jeśli już uruchamiasz Docker i ktoś odpowiada za wdrożenia, historia operacyjna jest jasna: przewidywalne przyjęcia, obserwowalny backpressure i brak narastania procesów Chrome lub zombie w 30-krotnym teście sekwencyjnym.
To też dobry wybór, jeśli alternatywą jest instalowanie własnego Chromium w każdej usłudze w stacku. Zcentralizowanie tego w jednym kontenerze z tokenem i limitem to naprawdę dobra decyzja architektoniczna.
Pomiń go, jeśli piszesz jeden skrypt. Pobieranie 4,3 GB i uruchamianie kontenera tylko po to, żeby pojedynczy plik Pythona pobrał wyrenderowaną stronę, to sporo ceremonii jak na małe zadanie — biblioteka przeglądarkowa w tym samym procesie zrobi to bez osobnej usługi. Pomiń go, jeśli warunki SSPL nie pasują do Twojego produktu komercyjnego i nie możesz ich rozwiązać. Pomiń go, jeśli tak naprawdę chcesz przeglądarki, która przychodzi już rozgrzana i bez kosztu cold startu, bo PREBOOT nie da Ci tego w v2. I pomiń go, jeśli Twój prawdziwy problem to obsługa anti-bot, bo to siedzi w endpointcie, którego celowo nie testowałem i za który nie ręczę.
Alternatywy, w tym miejsce Thunderbit
Warto porównywać nie Browserless z innym kontenerem, tylko to, gdzie żyje przeglądarka i kto odpowiada za jej utrzymywanie.
Powiązana recenzja: recenzja Browsertrix Crawler.
Powiązana recenzja: recenzja chromedp.
| Biblioteka przeglądarkowa (chromedp, rod, Selenium, Playwright) | Browserless self-hosted | Zarządzana ekstrakcja Thunderbit | |
|---|---|---|---|
| Gdzie działa przeglądarka | W Twoim procesie | W Twoim kontenerze | Na cudzej infrastrukturze |
| Koszt startowy | Instalacja pakietu | Obraz 4,3 GB + kontener + token | Klucz API |
| Mierzone tutaj czasy | Nie mierzone w tym artykule | 0,32 s do pierwszego renderu po gotowości HTTP; późniejsze wywołania mediana 0,15 s | Nie mierzone w tym artykule |
| Co piszesz | Kod automatyzacji z jawnymi waitami | Jeden autoryzowany POST | Jedno wywołanie HTTP |
| Co wraca | To, co sam zaprogramujesz | HTML, odpowiedzi PNG/PDF zgodne po sygnaturze, zeskrobane węzły | Ustrukturyzowany JSON lub Markdown zależny od produktu |
| Limit pojemności | Twoja maszyna | CONCURRENT + QUEUED, potem 429 | Plan dostawcy |
| Kto dyżuruje | Ty | Ty | Oni |
Jeśli chcesz przeglądarkę we własnym procesie i nie przeszkadza Ci pisanie waitów, biblioteka jest lżejsza i nie wymaga osobnego wdrożenia. Opisałem tę stronę w porównaniu Playwright vs Puppeteer oraz w szerszym zestawieniu open-source’owych projektów do web scrapingu.
Jeśli nie chcesz w ogóle obsługiwać przeglądarki, naszym własnym Thunderbit jest jedna z zarządzanych alternatyw. Browserless zwraca renderowany materiał, który Twoja aplikacja interpretuje; Thunderbit może zwrócić Markdown albo dane dopasowane do schematu, podczas gdy infrastruktura renderująca pozostaje po stronie dostawcy. Ten artykuł nie benchmarkował opóźnień, pojemności, zachowania przy awarii, jakości ekstrakcji ani kosztu Thunderbit, więc tabela opisuje granice odpowiedzialności, a nie porównanie wydajności.
Powiązana lektura z tej samej serii testów: recenzja Crawl4AI opisuje pipeline Markdown oparty na przeglądarce, który uruchamiasz samodzielnie, a przegląd narzędzi do web scrapingu mapuje szerszą kategorię.
Wypróbuj Thunderbit do ekstrakcji danych webowych
Werdykt
Czy warto uruchomić Browserless? Tak, jeśli kilku klientów potrzebuje pracy przeglądarki, ktoś może obsługiwać kontener, a przegląd licencyjny akceptuje model wdrożenia. W trzech syntetycznych testach przyjęć liczba zaakceptowanych żądań równała się CONCURRENT + QUEUED, nadmiar dostawał 429, a /pressure zgadzał się z licznikami widocznymi po stronie klienta. W osobnym 30-sesyjnym sprawdzeniu sekwencyjnym nie narosły procesy Chrome ani zombie. Jedna próba timeoutu zwróciła 408 blisko skonfigurowanej granicy. To użyteczne, ograniczone obserwacje, a nie uniwersalne gwarancje.
Trzeba jednak uczciwie ocenić koszty. To obraz 4,34 GB i usługa, którą operujesz, a nie zależność, którą po prostu dodajesz; ten test nie wykazał porównania szybkości z biblioteką przeglądarkową działającą w procesie. Jego wartość polega na tym, że daje przeglądarkę, którą możesz racjonować: znany sufit i mierzalny backpressure. W 30-sekundowym teście sekwencyjnym nie zaobserwowano narastania procesów Chrome ani zombie. Koszt to ciężar wdrożeniowy i licencja, którą trzeba przeczytać. Jeśli renderujesz garść stron z jednego skryptu, taki handel się nie opłaca. Jeśli prowadzisz warstwę renderującą, od której zależy kilka usług, to już tak — tylko sprawdź po drodze swoje zmienne środowiskowe z v1, bo PREBOOT będzie tam stało jakby było zatrudnione, choć nie robi absolutnie nic.
Wypróbuj Thunderbit do ekstrakcji danych webowych Get Started Free
FAQ
Czy Browserless przyspiesza headless Chrome?
Ten test nie może na to odpowiedzieć. Endpoint HTTP stał się dostępny 0,78 s po docker run; pierwszy /content zajął potem 0,32 s, a kolejne wywołania w tym samym kontenerze około 0,15 s. Te liczby łączą podróż HTTP, pracę przeglądarki, nawigację i transfer odpowiedzi. Harness nie izolował czasu uruchomienia, nie śledził ponownego użycia procesów i nie opublikował porównywalnego benchmarku w procesie. Używaj Browserless jako wspólnej granicy usługi i do kontroli przyjęć, a potem zmierz własną ścieżkę opóźnień.
Co się dzieje, gdy przekroczysz limit współbieżności Browserless?
Dostajesz natychmiast HTTP 429. Sufit to dokładnie CONCURRENT + QUEUED, i potwierdziłem to w trzech konfiguracjach: (2,2) przyjęło 4 i odrzuciło 4, (3,5) przyjęło 8 i odrzuciło 4, (5,5) przyjęło 10 i odrzuciło 4. Endpoint /pressure serwera za każdym razem pokazywał zgodne liczniki running, queued i recentlyRejected. Warto wiedzieć: żądania w kolejce nie failują, tylko czekają — przy (2,2) i 5-sekundowej pracy udane odpowiedzi trwały od 5,7 s do 11,0 s. Po stronie klienta traktuj 429 jako backpressure i stosuj retry z backoffem.
Czy PREBOOT nadal działa w Browserless v2?
Nie. PREBOOT został usunięty w 2.0.0, a v2 akceptuje -e PREBOOT=true bez błędu i bez ostrzeżenia, ale nic z tym nie robi. Potwierdziłem jego martwość na trzy sposoby: opóźnienia były nieodróżnialne od domyślnych, kontener PREBOOT=true w spoczynku miał 0 oczekujących procesów chrome, a /config w ogóle nie pokazuje klucza preboot. Jeśli przeniosłeś konfigurację z v1, Twoje instancje nie są rozgrzane. Zwróć uwagę, że KEEP_ALIVE, usunięty w tej samej wersji, loguje ostrzeżenie „deprecated and ignored” — więc problem cichej porażki dotyczy konkretnie PREBOOT.
Czy Browserless jest darmowy do użytku komercyjnego? Repozytorium oferuje SSPL-1.0 albo komercyjną licencję Browserless, ale ten artykuł nie mapuje konkretnych scenariuszy komercyjnych ani closed-source do jednej z tych opcji. Przejrzyj aktualny LICENSE i oficjalne wytyczne wdrożeniowe, a potem poproś osobę odpowiedzialną za licencjonowanie o ocenę modelu wdrożenia i dystrybucji.
Czy Browserless zostawia po sobie zombie Chrome?
W krótkim badanym oknie nie narosły. Po 30 kolejnych sesjach kontener miał 0 procesów Chrome i 0 zombie, a przetrwały jedynie dumb-init, node, Xvfb, start.sh i sh. Detektor widział 11 procesów z rodziny chrome, gdy sesja była aktywna, więc nie był ślepy. Pamięć kontenera wzrosła z 294 MiB do 303 MiB i potem się wypłaszczyła. To nie jest wynik z testu wielogodzinnego, współbieżnego ani z tysięcy sesji.


