Majoritatea oamenilor descoperă Crawlee atunci când încearcă să răspundă la altă întrebare: „ce browser headless ar trebui să folosesc?”. Doar că întrebarea corectă nu e asta, iar Crawlee e motivul. Nu este un browser. Este framework-ul Node/TypeScript pe care îl folosești când ai nevoie de el și îl sari atunci când nu ai.
Am petrecut câteva zile rulând Crawlee 3.17.0 pe un set controlat de fixture-uri și pe câteva site-uri demo publice, pe Node v22.22.3 și macOS. Promisiunea principală — o singură bibliotecă, un singur API, fie un crawler HTTP, fie un browser real dedesubt — este exact partea pe care am vrut s-o verific cel mai atent, pentru că de aici se vede dacă merită să-l pui în stack-ul tău sau dacă e mai simplu să mergi direct cu Playwright. Concluzia, pe scurt: povestea cu cele două motoare chiar stă în picioare, cu câteva nuanțe despre care ajung imediat.
Ce este, de fapt, Crawlee — și ce nu este
Crawlee se prezintă ca o bibliotecă de web scraping și automatizare de browser pentru Node.js, construită pentru a crea crawlere fiabile. Poziționarea oficială este foarte largă: extragere de date pentru AI, LLM-uri, RAG sau GPT-uri; descărcare de HTML, PDF, JPG, PNG și alte fișiere; compatibilitate cu Puppeteer, Playwright, Cheerio, JSDOM și HTTP brut; mod headful sau headless; rotație de proxy inclusă. Acoperă mult teren, așa că merită spus și ce nu este Crawlee.
Nu este un motor de randare. Nu are propriul browser. Când vrei să execute JavaScript, Crawlee îl conduce pe Playwright sau Puppeteer, iar acestea controlează mai departe Chromium (sau alt browser). Nici nu este un serviciu găzduit pe care îl chemi prin rețea — este o dependență pe care o instalezi și o rulezi local. Mai exact, Crawlee este stratul de deasupra componentei de fetch: clasele de crawler, coada de cereri, stocarea, logica de urmărire a linkurilor. Gândește-te la el ca la framework-ul de crawl, cu un motor plug-in dedesubt.
Ca referință, versiunea testată a fost 3.17.0 (lansată pe 2026-06-04), este scrisă în TypeScript, licența este Apache-2.0, iar repo-ul avea aproximativ 24,6k stele la data de 2026-07-09 pe apify/crawlee. Numărul de stele se schimbă mereu — repo-ul a mai strâns 53 în cele două zile în care l-am urmărit — așa că tratează cifra ca pe o fotografie de moment, nu ca pe o valoare fixă.
Cele două motoare: CheerioCrawler vs PlaywrightCrawler
Aici își justifică designul existența, și aici am petrecut cel mai mult timp.
CheerioCrawler este varianta HTTP. Ia HTML-ul brut prin rețea și îl parsează cu Cheerio — fără browser, fără execuție JavaScript, fără randare. Este rapid și ieftin. PlaywrightCrawler este varianta de browser. Pornește un Chromium real, randază pagina inclusiv tot ce construiește DOM-ul prin JavaScript și poate chiar să facă screenshot-uri.
Două motoare diferite, cu capabilități cu adevărat diferite. Ideea Crawlee este că la suprafață arată la fel. Ambele acceptă requestHandler. Ambele expun run(). Ambele urmăresc linkuri cu enqueueLinks. Trecerea de la un motor la altul este înlocuirea unei clase, nu rescrierea întregului flux — am verificat asta păstrând logica de extragere identică la nivel de byte și schimbând doar clasa de crawler care o învelea.

Un lucru important de spus, pentru că aici se termină paritatea: modul de acces la conținut diferă. Într-un handler CheerioCrawler primești $ — un DOM static, deja pars-at, pe care îl interoghezi ca în jQuery. Într-un handler de browser primești un obiect page live. Așadar, coada, rutarea și partea de infrastructură pentru „pune datele astea, urmează linkurile acelea” rămân identice, dar linia în care citești efectiv pagina arată diferit. Și documentația Crawlee spune cam același lucru — interfața comună acoperă operațiunile de crawl, iar accesul la conținut este partea care se schimbă.
| Motor | Cum preia pagina | Rulează JavaScript? | Testul meu (1 pagină dinamică) | Cel mai bun pentru |
|---|---|---|---|---|
CheerioCrawler | HTTP brut + parsare cu Cheerio | Nu | ~0.035s | HTML static, API-uri JSON, viteză |
PlaywrightCrawler | Chromium real prin Playwright | Da | ~4.967s | Pagini randate prin JS, screenshot-uri |
Timpurile de mai sus vin de pe o singură mașină și dintr-o singură rulare — nu sunt un benchmark, ci doar arată diferența de cost. Calea cu browser a costat cam cu două ordine de mărime mai mult timp pentru același URL. Acesta e prețul randării și motivul pentru care nu o alegi implicit.
Testul: același URL, 0 vs 8/8
Promisiunile sunt ieftine. Motivul pentru care cred povestea celor două motoare e că am putut s-o fac să pice și apoi s-o repar doar schimbând o clasă.
Am construit un fixture dinamic local — o pagină de catalog în care cardurile de produs sunt injectate de JavaScript după încărcare, exact genul de pagină care a devenit standard pe web-ul modern. Am rulat CheerioCrawler pe ea. A returnat 0 carduri de produs. Nu e un bug; e fizică. Cheerio nu a rulat JavaScript-ul, deci cardurile n-au existat niciodată în HTML-ul pe care l-a pars-at. Apoi am rulat PlaywrightCrawler pe exact același URL, fără să schimb nimic altceva, și a randat 8 din 8 produse și a făcut un screenshot ca dovadă.

Ca să mă asigur că nu era ceva specific fixture-ului meu, am repetat același tipar pe un site public — pagina demo JavaScript Quotes to Scrape, care construiește citatele pe client. Același rezultat, în aceeași direcție: CheerioCrawler a văzut 0 citate, PlaywrightCrawler a recuperat 10.

Vreau să fiu atent la ce demonstrează asta. Este o reproducere curată a unei afirmații pe care Crawlee o documentează deja — framework-ul a împărțit aceeași clasă de bază și aceeași interfață între tipurile sale de crawler încă din versiunea 3.0. Așadar, aici vorbim despre verificare, nu despre descoperire. Dar tocmai asta contează: mesajul de marketing „o singură interfață, HTTP sau browser” este real, iar aici ai dovada 0 → date complete, atât pe un fixture pe care îl controlez, cât și pe un site pe care nu-l controlez.
Unde câștigă calea HTTP
Ar fi ușor să citești secțiunea de mai sus ca „folosește mereu browserul”. Nu. Tocmai de aceea contează designul cu două motoare: browserul este fallback-ul scump, nu opțiunea implicită.
Pe conținut static, CheerioCrawler a fost corect și rapid. Fixture-ul meu static de catalog a returnat 12 din 12 produse, cu recuperare completă, urmărind paginarea prin enqueueLinks({ selector: '.next-page' }), în aproximativ 0.155 secunde. O pagină de articol a livrat titlul și toate cele 3 din 3 paragrafe ale corpului, separând curat boilerplate-ul de login/subscriere/copyright de conținutul propriu-zis.
Cazul care merită ținut minte: o pagină ale cărei date sunt încărcate prin JavaScript are adesea în spate un API JSON. Datele fixture-ului meu dinamic existau într-un endpoint, iar când am dat CheerioCrawler direct pe acel API, a recuperat 8 din 8 produse — fără browser, în aproximativ 0.035 secunde. Aceleași date pe care calea de browser le-a randat în aproape cinci secunde. Lecția e veche, dar rămâne valabilă: dacă poți reproduce cererea de bază, fă asta în loc să pornești Chromium. Crawlee îți permite să alegi asta per-crawler, fără să schimbi framework-ul.
Partea de framework de crawl (motivul pentru care alegi Crawlee în locul unei biblioteci browser simple)
Dacă tot ce îți trebuia era să randazi o singură pagină, n-ai avea nevoie de Crawlee — ai folosi Playwright sau Puppeteer direct. Ce nu-ți oferă o bibliotecă browser simplă este un crawl: coadă, deduplicare, control al adâncimii, retry-uri. Asta este partea din Crawlee care nu ține de motoare.
Am rulat un crawl pe același hostname, pornind de la rădăcina fixture-ului, folosind enqueueLinks cu urmărirea adâncimii. Crawlee a parcurs 11 pagini pe adâncimi {0:1, 1:3, 2:7} — una la rădăcină, trei la un hop distanță, șapte la două hop-uri — și a respectat maxRequestsPerCrawl ca limită de oprire. RequestQueue s-a ocupat de evidență. Când am trimis o cerere către o pagină care returna HTTP 500, Crawlee a încercat din nou și apoi a raportat eșecul prin failedRequestHandler, în loc să-l înghită în tăcere sau să prăbușească rularea.

Acesta e cel mai puternic argument pentru Crawlee în comparație cu un browser tool separat: orchestratrea crawl-ului este inclusă și, foarte important, este aceeași indiferent dacă dedesubt ai HTTP sau browser. Scrii o singură dată logica de coadă și urmărire a linkurilor. Separat decizi dacă fiecare crawler trebuie să randaze JavaScript.
Instalare și descărcarea ascunsă a browserului
Instalarea a mers în mare fără probleme, cu o capcană care îi va lovi pe utilizatorii aflați la prima utilizare.
npm install crawlee playwright a rulat curat — fără vulnerabilități raportate. Dar PlaywrightCrawler nu pornește până nu rulezi și npx playwright install chromium, care descarcă un binar Chromium de aproximativ 81.7 MiB. Instalarea pachetului crawlee singur nu aduce browserul. Dacă sari peste pasul ăsta și treci direct la un crawler de browser, vei primi o eroare de lansare care nu e evidentă dacă nu cunoști deja modelul de packaging al Playwright. Este un comportament moștenit de la Playwright, nu un defect al Crawlee, dar este un punct real de fricțiune la prima rulare și merită menționat.

Încă o notă operațională: în mod implicit, Crawlee scrie într-un director local storage/. Harness-ul meu de test a redirecționat asta către un director temporar și a dezactivat persistența ca să păstrez lucrurile curate, dar o rulare standard va lăsa un folder storage/ în proiect. Nu e o problemă, doar ceva de știut înainte să apară în git status.
Un al treilea motor, pe scurt
Povestea parității în Crawlee nu se oprește la Cheerio și Playwright. Mai există și PuppeteerCrawler, iar eu am verificat cât de departe ajunge afirmația „aceeași interfață” și în cazul lui — la nivel de clasă și de API, nu printr-un crawl live.
Toate cele trei clase de crawler pornesc din aceeași clasă de bază BasicCrawler. CheerioCrawler trece printr-un HttpCrawler; PlaywrightCrawler și PuppeteerCrawler trec ambele printr-un BrowserCrawler comun. Prin introspecția pachetului instalat, am găsit 24 de metode publice comune tuturor celor trei motoare, inclusiv operațiunile de coadă și stocare pe care se sprijină întregul design — run, addRequests, pushData, getData, getDataset, exportData, getRequestQueue, useState, stop. PuppeteerCrawler și PlaywrightCrawler expun de fapt un set identic de metode publice. Singurele diferențe dintre motoare apar exact pe muchia HTTP-versus-browser, adică tocmai unde te-ai aștepta.
Limita importantă de spus clar: nu am rulat un crawl live cu PuppeteerCrawler. Dependența peer puppeteer este opțională și nu a fost instalată în pachetul meu de test, iar folosirea ei ar fi însemnat încă o descărcare de browser. Așadar, paritatea pentru Puppeteer este verificată structural — aceeași clasă de bază, aceleași metode comune, aceeași formă a contextului handlerului — nu printr-o execuție efectivă. Și chiar când interfața se potrivește, comportamentul intern nu este perfect identic: ghidul oficial notează că Playwright așteaptă automat elementele, în timp ce Puppeteer cere așteptare explicită. Asta ține de motor, nu de un defect Crawlee, dar înseamnă că „același API” nu înseamnă „același cod în fiecare handler”.
Ce nu am testat
Iată ce am lăsat intenționat pe dinafară, ca să nu interpretezi rezultatele ca fiind mai largi decât sunt.
- Scală. Totul a rulat pe fixture-uri mici și crawl-uri publice scurte. Nu am făcut un test de 100–1.000 de pagini, deci nu pot vorbi despre autoscaling-ul Crawlee sau despre stabilitatea lui sub sarcină reală.
- Persistența cozii și reluarea după crash. Nu am întrerupt niciodată un crawl în mijlocul execuției ca să văd dacă
RequestQueueîși reia curat activitatea după o cădere. Este o capabilitate importantă pentru joburile lungi și aici nu a fost testată. - Exportul Dataset și KeyValueStore. În harness am scris manual exporturile JSON/CSV. Ergonomia exportului built-in prin
Dataset/KeyValueStore— probabil unul dintre marile avantaje ale framework-ului — nu am testat-o. - Proxy și pool-uri de sesiuni. Crawlee include funcții de rotație a proxy-urilor și fingerprinting. Le tratez strict ca subiect de conformitate și operațiuni, nu ca argument de „ocolire anti-bot”, și nu le-am stresat nici într-un sens, nici în altul.
Și timpii de pe tot parcursul articolului sunt de pe o singură mașină și dintr-o singură rulare. Arată forma diferenței de cost între HTTP și browser. Nu sunt benchmark-uri și nu le-aș cita ca atare.
Pro și contra
Pro
- O singură suprafață API pentru crawl HTTP și browser — schimbarea motorului chiar este o schimbare de clasă, verificată cu 0 → date complete atât pe un fixture local, cât și pe un site public.
- Un framework real de crawl:
RequestQueue,enqueueLinkscu control al adâncimii, retry-uri șifailedRequestHandler, nu doar un renderer de pagini. - Extracție HTTP exactă (12/12 static, 3/3 paragrafe de articol, 8/8 prin API JSON) atunci când JavaScript-ul nu stă în cale.
- Calea de browser recuperează conținut pe care HTTP pur și simplu nu îl poate vedea și poate face screenshot-uri.
- Apache-2.0, TypeScript, întreținut activ.
Contra
- Crawler-ele de browser necesită un
npx playwright install chromiumseparat (~81.7 MiB), pe carenpm install crawleenu îl rezolvă — ușor de ratat. - Randarea în browser are un cost real per pagină (~5s vs sub o secundă în testul meu pe o singură pagină).
- Directorul implicit
storage/apare ca efect secundar la rulările standard. - Scalarea, reluarea după crash și ergonomia exportului Dataset nu au fost demonstrate în testele mele.
- Funcțiile de proxy și fingerprinting trebuie folosite în limitele termenilor unui site și ale legii — o responsabilitate, nu un avantaj de exploatat.
Când să alegi Crawlee vs o API gestionată
Crawlee este un instrument de tip „construiește singur”, iar pentru multe echipe asta e alegerea potrivită. Folosește-l când vrei să controlezi crawlerul în propriul tău codebase Node, să combini crawl-ul HTTP și cel de browser într-un singur proiect fără să schimbi framework-ul și să administrezi singur coada și stocarea. Dacă ești confortabil să rulezi și, în timp, să scalezi o flotă de browsere, Crawlee îți oferă o bază curată și bine proiectată pe care să construiești.
Cealaltă variantă este să nu rulezi deloc infrastructura asta. Dacă nu vrei să-ți consumi timpul de inginerie cu administrarea instanțelor Chromium, rotația proxy-urilor și handling-ul anti-bot, alternativa este o API gestionată — iar aici intră și stack-ul nostru pentru dezvoltatori de la Thunderbit. Pentru utilizatorii tehnici, Thunderbit nu înseamnă extensia Chrome; înseamnă un API de scraping AI, server MCP și CLI. Apelezi POST /distill ca să transformi o pagină în Markdown curat, pregătit pentru LLM, sau POST /extract cu un JSON Schema ca să primești date structurate înapoi, iar cu renderMode setat la none, basic sau full decizi singur când merită o randare completă în browser. Serverul MCP permite unui agent AI (Claude, Cursor și alți clienți MCP) să facă scraping chiar în timpul sarcinii, iar CLI-ul rulează din terminal sau CI:
Încearcă Thunderbit pentru extragerea datelor web
npx -y @thunderbit/thunderbit-cli distill "<url>" -f markdown > out.md
Diferența care contează pentru dezvoltatori: Crawlee îți oferă materialul brut — HTML randat, noduri parsate — iar tu deții pipeline-ul; o API gestionată îți întoarce JSON structurat, aliniat la schemă, cu randarea JavaScript, CAPTCHA-urile și anti-bot-ul gestionate pe server. Misiuni diferite. Dacă vrei control maxim și nu te deranjează partea de ops, Crawlee. Dacă vrei datele fără să administrezi o flotă de browsere, varianta gestionată. Multe echipe ajung să le folosească pe ambele: una pentru crawl-uri personalizate și una pentru cazurile „doar dă-mi datele structurate”. Poți vedea diferențele de cost la prețurile Thunderbit.
Verdict
Merită să folosești Crawlee? Da — dacă ești developer Node sau TypeScript și vrei un singur framework care acoperă atât crawl HTTP, cât și crawl de browser, cu o coadă reală dedesubt. Promisiunea celor două motoare e exact motivul pentru care merită ales, iar în testele mele s-a confirmat clar: același URL a trecut de la 0 la date complete prin schimbarea unei singure clase, extracția statică a fost rapidă și corectă, iar crawl-ul cu coadă și adâncime a funcționat exact cum era documentat.
Intră însă cu două lucruri în minte. Bugetează prima dată descărcarea ascunsă a browserului când folosești PlaywrightCrawler și nu presupune că părțile pe care nu le-am testat — scalare, reluare după crash, exporturile built-in — se comportă la fel de bine ca părțile testate, până nu le rulezi pe volumul tău real de lucru. Ca fundație pentru a-ți construi propriul crawler, Crawlee este o piesă de inginerie solidă, bine gândită. Ca pipeline de date final, complet hands-off, este un punct de pornire, nu destinația.
Încearcă Thunderbit pentru extragerea datelor web Get Started Free
Întrebări frecvente
Crawlee este gratuit și sub ce licență se află?
Da. Crawlee este open source sub licența Apache-2.0 și se instalează din npm (npm install crawlee). Versiunea pe care am testat-o a fost 3.17.0. Rularea crawlerelor de browser necesită o descărcare separată de Chromium prin Playwright, care este și ea gratuită, dar adaugă aproximativ 81.7 MiB la setup.
CheerioCrawler vs PlaywrightCrawler — pe care ar trebui să-l folosesc?
Folosește CheerioCrawler atunci când datele sunt în HTML-ul brut sau într-un API JSON din spate — este mult mai rapid și nu pornește niciodată un browser. Folosește PlaywrightCrawler atunci când conținutul este randat de JavaScript, lucru pe care îl vezi când calea HTTP întoarce rezultate goale. În testele mele, motorul HTTP a returnat 0 elemente pe o pagină randată prin JS, iar motorul de browser a recuperat tot. Pentru că au același API, trecerea între ele este o schimbare de clasă, nu o rescriere.
Are Crawlee nevoie de browser ca să ruleze?
Doar pentru crawler-ele de browser. CheerioCrawler nu are nevoie de browser deloc. PlaywrightCrawler (și PuppeteerCrawler) au nevoie de un binar de browser — instalează-l cu npx playwright install chromium. Ține minte că npm install crawlee singur nu descarcă browserul, acesta fiind cel mai comun obstacol la prima rulare.
Poate Crawlee să gestioneze paginarea și crawl-urile pe mai multe pagini?
Da, și acesta este unul dintre motivele principale pentru care îl alegi în locul unei biblioteci browser independente. enqueueLinks urmărește linkurile (inclusiv selectori de paginare precum .next-page), RequestQueue deduplichează și organizează crawl-ul, iar tu primești control al adâncimii plus limite maxRequestsPerCrawl. În testare, un crawl pe același hostname a parcurs 11 pagini la adâncimi 0–2, iar cererile eșuate au fost raportate prin failedRequestHandler.
Cum se compară Crawlee cu o API de scraping găzduită?
Crawlee este self-hosted: tu scrii și rulezi crawlerul, iar tu deții scalarea, proxy-urile și handling-ul anti-bot. O API gestionată precum endpoint-urile Thunderbit distill/extract îți returnează Markdown curat sau JSON structurat conform schemei, cu randarea și anti-bot-ul tratate pe server, expuse printr-un API, un server MCP și un CLI. Alege Crawlee când vrei control maxim asupra propriului pipeline; alege o API gestionată când preferi să nu rulezi și să scalezi singur infrastructura de browser.


