De fleste støder på Crawlee, mens de egentlig prøver at besvare et andet spørgsmål: "hvilken headless browser skal jeg bruge?" Det er det forkerte spørgsmål, og Crawlee er grunden. Det er ikke en browser. Det er Node/TypeScript-rammen, der bruger en browser, når du har brug for det, og springer den over, når du ikke gør.
Jeg brugte et par dage på at teste Crawlee 3.17.0 mod et kontrolleret sæt fixtures og nogle få offentlige demosider, på Node v22.22.3 og macOS. Det store løfte — ét bibliotek, ét API, enten en HTTP-crawler eller en rigtig browser under motorhjelmen — var det, jeg især ville presse, fordi det er den påstand, der afgør, om Crawlee er værd at føje til din stack, eller om du bare skal gå direkte til Playwright. Kort version: fortællingen om to motorer holder vand, med et par forbehold, som jeg kommer til.
Hvad Crawlee egentlig er — og ikke er
Crawlee beskriver sig selv som et web scraping- og browser automation-bibliotek til Node.js, bygget til at lave pålidelige crawlers. Den officielle positionering er bred: udtræk data til AI, LLM'er, RAG eller GPT'er; download HTML, PDF, JPG, PNG og andre filer; virker med Puppeteer, Playwright, Cheerio, JSDOM og rå HTTP; både med og uden browser-vindue; proxy-rotation er inkluderet. Det er meget at dække, så det hjælper at sige, hvad Crawlee ikke er.
Det er ikke en rendering-motor. Det har ikke sin egen browser. Når du vil have JavaScript eksekveret, styrer Crawlee Playwright eller Puppeteer, som igen styrer Chromium (eller en anden browser). Det er heller ikke en hostet tjeneste, du kalder over nettet — det er en afhængighed, du selv installerer og kører. Helt præcist er det, Crawlee er, laget oven på hentningen: crawler-klasserne, request-køen, storage, logikken til at følge links. Tænk på det som crawl-rammen, med en udskiftelig motor underneden.
Til orientering var den version, jeg testede, 3.17.0 (udgivet 2026-06-04), det er TypeScript, licensen er Apache-2.0, og repoet lå på omkring 24,6k stars pr. 2026-07-09 på apify/crawlee. Star-tal ændrer sig hele tiden — repoet fik 53 i de to dage, jeg fulgte det — så se tallet som et øjebliksbillede, ikke som en fast sandhed.
De to motorer: CheerioCrawler vs PlaywrightCrawler
Her er det, hvor designet virkelig betaler sig, og hvor jeg brugte det meste af min tid.
CheerioCrawler er HTTP-sporet. Det henter rå HTML over nettet og parser den med Cheerio — ingen browser, ingen JavaScript-eksekvering, ingen rendering. Det er hurtigt og billigt. PlaywrightCrawler er browsersporet. Den starter rigtig Chromium, renderer siden inklusive alt det JavaScript, der bygger DOM'en, og kan endda tage screenshots.
To forskellige motorer med reelt forskellige muligheder. Pointen Crawlee vil understrege er, at de er klædt ens. Begge tager en requestHandler. Begge har run(). Begge crawler links med enqueueLinks. At skifte fra den ene motor til den anden er et klasseskift, ikke en omskrivning — det bekræftede jeg ved at lade min ekstraktionslogik være byte-identisk og kun skifte, hvilken crawler-klasse der omsluttede den.

Én ting skal være helt præcis, fordi det er der, ligheden stopper: adgangen til indholdet er forskellig. Inde i en CheerioCrawler-handler får du $ — en statisk, allerede parseret DOM, som du spørger på ligesom i jQuery. Inde i en browser-handler får du et live page-objekt. Så køen, routing og "send disse data videre, følg de links"-mekanikken er identisk, men den linje, hvor du faktisk læser siden, ændrer form. Crawlees egen dokumentation siger det samme — den deler grænsefladen op omkring crawl-operationerne og nævner adgang til indhold som det, der varierer.
| Motor | Hvordan den henter | Kører JavaScript? | Min testkørsel (1 dynamisk side) | Bedst til |
|---|---|---|---|---|
CheerioCrawler | Rå HTTP + Cheerio-parse | Nej | ~0,035 s | Statisk HTML, JSON API'er, hastighed |
PlaywrightCrawler | Rigtig Chromium via Playwright | Ja | ~4,967 s | JS-renderede sider, screenshots |
De tal er fra én maskine og én enkelt kørsel — ikke en benchmark, bare et billede af afvejningen. Browsersporet kostede omtrent to størrelsesordener mere tid på den samme URL. Det er prisen for rendering, og det er derfor, du ikke vælger det som standard.
Testen: Samme URL, 0 vs 8/8
Påstande er billige. Grunden til, at jeg tror på fortællingen om to motorer, er, at jeg kunne få den til at fejle og derefter fikse den ved at skifte én klasse.
Jeg byggede en lokal dynamisk fixture — en katalogside, hvor produktkortene injiceres af JavaScript efter load, altså den type side, der i praksis er blevet standard på nettet. Jeg pegede CheerioCrawler på den. Den returnerede 0 produktkort. Det er ikke en fejl; det er fysik. Cheerio kørte aldrig JavaScript'et, så kortene fandtes aldrig i den HTML, der blev parseret. Derefter pegede jeg PlaywrightCrawler på præcis den samme URL, ændrede ikke andet, og den renderede 8 ud af 8 produkter og tog et screenshot som bevis.

For at sikre, at det ikke bare var en særhed ved min egen fixture, kørte jeg samme mønster mod en offentlig side — Quotes to Scrape-demosiden med JavaScript, som bygger citaterne på klientsiden. Samme resultat i samme retning: CheerioCrawler så 0 citater, PlaywrightCrawler fandt 10.

Jeg vil være omhyggelig med, hvad det her beviser. Det er en ren reproduktion af noget, Crawlee allerede dokumenterer — frameworket har delt samme base class og interface på tværs af crawler-typer siden version 3.0. Så det her er verifikation, ikke opdagelse. Men det er netop pointen: marketinglinjen "ét interface, HTTP eller browser" er reel, og her er kvitteringen for 0 → fulde data på både en fixture, jeg kontrollerer, og en side, jeg ikke gør.
Hvor HTTP-sporet vinder
Det ville være let at læse afsnittet ovenfor som "brug altid browseren". Lad være. Hele pointen med designet med to motorer er, at browseren er den dyre fallback, ikke standardvalget.
På statisk indhold var CheerioCrawler både præcis og hurtig. Min statiske katalogfixture returnerede 12 ud af 12 produkter med fuld recall, og fulgte pagination via enqueueLinks({ selector: '.next-page' }), på cirka 0,155 sekunder. En artikelside gav titel og alle 3 ud af 3 brødtekst-afsnit, mens login-/abonnements-/copyright-tekst blev holdt rent adskilt fra indholdet.
Det vigtigste at tage med: En side, hvis data hentes via JavaScript, har ofte et JSON API lige bagved. Dataene i min dynamiske fixture lå på et endpoint, og da jeg pegede CheerioCrawler direkte mod API'et, fik den 8 ud af 8 produkter — ingen browser, på cirka 0,035 sekunder. De samme data tog browser-sporet næsten fem sekunder at renderere. Læringen er gammel, men stadig sand: hvis du kan genskabe den underliggende request, så gør det i stedet for at starte Chromium. Crawlee lader dig vælge det pr. crawler uden at skifte framework.
Crawl-rammedelen (grunden til at vælge Crawlee frem for et rent browser-bibliotek)
Hvis alt, du havde brug for, var at renderere én side, behøvede du ikke Crawlee — så ville du bare bruge Playwright eller Puppeteer alene. Det et rent browserbibliotek ikke giver dig, er et crawl: en kø, deduplikering, dybdekontrol, retries. Det er den del af Crawlee, som slet ikke handler om motorer.
Jeg kørte et crawl inden for samme hostname fra roden af en fixture ved hjælp af enqueueLinks med depth tracking. Crawlee gennemløb 11 sider fordelt på dybderne {0:1, 1:3, 2:7} — én rodkort, tre sider et hop ude, syv sider to hop ude — og respekterede maxRequestsPerCrawl som stopbetingelse. RequestQueue tog sig af bogføringen. Da jeg pegede en request mod en side, der returnerede HTTP 500, prøvede Crawlee igen og sendte derefter fejlen videre via sin failedRequestHandler i stedet for bare at sluge den stille eller crashe kørslen.

Det er det stærkeste argument for Crawlee frem for et selvstændigt browserværktøj: crawl-orchestreringen er indbygget, og vigtigst af alt er den den samme, uanset om motoren underneden er HTTP eller browser. Du skriver din kø- og følge-links-logik én gang. Du beslutter separat, om hver crawler skal renderere JavaScript.
Opsætning og den skjulte browser-download
Installationen var mestendels problemfri, med én fælde, der vil ramme nye brugere.
npm install crawlee playwright kørte uden problemer — 0 sårbarheder blev rapporteret. Men PlaywrightCrawler vil ikke starte, før du også kører npx playwright install chromium, som henter en Chromium-binær på omkring 81,7 MiB. At installere crawlee-pakken alene henter ikke en browser. Hvis du springer det trin over og går direkte til en browser-crawler, får du en launch-fejl, som ikke er oplagt, hvis du ikke allerede kender Playwrights pakkemodel. Det er nedarvet Playwright-adfærd, ikke en Crawlee-fejl, men det er en reel friktion ved første kørsel, som er værd at nævne.

En ekstra driftsnote: Som standard skriver Crawlee til en lokal storage/-mappe. Min testopsætning sendte det til en midlertidig scratch-mappe og slukkede for persistens for at holde tingene rene, men en helt almindelig kørsel vil efterlade en storage/-mappe i dit projekt. Ikke et problem, bare noget du bør kende til, før det dukker op i din git status.
En tredje motor, kort
Crawlees parity-historie stopper ikke ved Cheerio og Playwright. Der er også PuppeteerCrawler, og jeg tjekkede, hvor langt påstanden om "samme interface" rækker dér — på klasse- og API-niveau, ikke med et live crawl.
Alle tre crawler-klasser kan spores tilbage til den samme BasicCrawler-base. CheerioCrawler går via en HttpCrawler; PlaywrightCrawler og PuppeteerCrawler går begge via en delt BrowserCrawler. Ved at inspicere den installerede pakke fandt jeg 24 offentlige metoder, som deles på tværs af alle tre motorer, inklusive kø- og storage-operationerne, som hele designet hviler på — run, addRequests, pushData, getData, getDataset, exportData, getRequestQueue, useState, stop. PuppeteerCrawler og PlaywrightCrawler har faktisk identisk sæt offentlige metoder. De eneste forskelle på tværs af motorer ligger langs HTTP-versus-browser-sømmen, hvilket er præcis, hvor man ville forvente dem.
Det grænsepunkt, der skal siges klart: Jeg kørte ikke et live PuppeteerCrawler-crawl. puppeteer-peer dependency er valgfri og var ikke installeret i min testpakke, og at teste det ville betyde endnu en browser-download. Så Puppeteeer-pariteten er her verificeret strukturelt — samme base class, samme delte metoder, samme shape på handler-context — ikke via en udført kørsel. Og selv når interfacet matcher, er adfærden underneden ikke helt den samme: Crawlees egen vejledning påpeger, at Playwright auto-venter på elementer, mens Puppeteer kræver, at du venter eksplicit. Det er en egenskab ved motoren, ikke en Crawlee-fejl, men det betyder, at "samme API" ikke er det samme som "samme kode inde i alle handlers."
Hvad jeg ikke testede
Her er det, denne omgang bevidst lod ligge, så du ikke læser mine resultater bredere, end de er.
- Skala. Alt kørte på små fixtures og korte offentlige crawls. Ingen 100–1.000-siders langtidskørsel, så jeg kan ikke sige noget om Crawlees autoskalering eller stabilitet under reelt load.
- Kø-persistens og genoptagelse. Jeg dræbte aldrig et crawl midt i en kørsel for at se, om
RequestQueuekommer pænt op igen efter et crash. Det er en vigtig funktion til lange jobs, og den er ikke testet her. - Dataset- og KeyValueStore-export. Jeg skrev mine JSON/CSV-exports i hånden i testharnesset. Crawlees indbyggede
Dataset/KeyValueStore-export-oplevelse — måske den mest ergonomiske gevinst ved at bruge frameworket — testede jeg ikke. - Proxy- og session-pools. Crawlee leverer proxy-rotation og fingerprinting. Jeg betragter det strengt som et emne om compliance og drift, ikke som et "anti-bot bypass"-salgsargument, og jeg stress-testede det ikke i nogen retning.
Og tidsmålingerne gennem hele testen er fra én maskine og én enkelt kørsel. De viser formen på omkostningen ved HTTP versus browser. De er ikke benchmarks, og jeg ville ikke citere dem som sådan.
Fordele og ulemper
Fordele
- Ét API-område på tværs af HTTP og browser-crawling — motor-skiftet er virkelig et klasseskift, bekræftet med 0 → fulde data på både en lokal fixture og en offentlig side.
- En reel crawl-ramme:
RequestQueue,enqueueLinksmed dybdekontrol, retries og enfailedRequestHandler, ikke bare en side-renderer. - Præcis HTTP-ekstraktion (12/12 statiske produkter, 3/3 artikelafsnit, 8/8 via JSON API), når JavaScript ikke står i vejen.
- Browsersporet kan hente indhold, som HTTP-sporet fysisk ikke kan se, og det kan tage screenshots.
- Apache-2.0, TypeScript, aktivt vedligeholdt.
Ulemper
- Browser-crawlerne kræver en separat
npx playwright install chromium(~81,7 MiB), somnpm install crawleeikke håndterer — let at overse. - Browser-rendering har en reel sidepris (~5 s vs. under et sekund i min énsides-test).
- Standard-sideeffekt med
storage/-mappe ved almindelige kørsler. - Skala, kø-persistens/genoptagelse og ergonomien i Dataset-export er ikke bevist i min test.
- Proxy- og fingerprinting-funktioner skal bruges inden for sitets vilkår og loven — et ansvar, ikke en genvej, man skal læne sig op ad.
Hvornår du skal vælge Crawlee frem for en managed API
Crawlee er et bygg-selv-værktøj, og for mange teams er det det rigtige valg. Vælg det, når du vil eje crawleren i din egen Node-kodebase, kombinere HTTP- og browser-crawling i ét projekt uden at skifte framework, og selv styre kø og storage. Hvis du er tryg ved at køre og senere skalere en browser-flåde, giver Crawlee dig en ren og veludført rygrad at hænge det på.
Det andet spor er slet ikke at drive den infrastruktur selv. Hvis du ikke har lyst til at bruge din ingeniørtid på at babysitte Chromium-instanser, proxy-rotation og anti-bot-håndtering, er en managed API alternativet — og det er dér, vores egen developer stack hos Thunderbit passer ind. For tekniske brugere er Thunderbit ikke Chrome-udvidelsen; det er en AI scraping API, MCP-server og CLI. Du kalder POST /distill for at gøre en side til ren, LLM-klar Markdown, eller POST /extract med et JSON Schema for at få strukturerede data retur, med renderMode sat til none, basic eller full, så du selv vælger, hvornår fuld browser-rendering er pengene værd. MCP-serveren lader en AI-agent (Claude, Cursor og andre MCP-klienter) scrape midt i en opgave, og CLI'en kører fra terminalen eller CI:
Prøv Thunderbit til udtræk af webdata
npx -y @thunderbit/thunderbit-cli distill "<url>" -f markdown > out.md
Forskellen, der betyder noget for udviklere: Crawlee giver dig råmaterialet — renderet HTML, parserede noder — og du ejer hele pipelinen; en managed API giver dig schema-matchet, struktureret JSON tilbage, mens rendering, CAPTCHA'er og anti-bot-håndtering klares server-side. Forskellige jobs. Hvis du vil have maksimal kontrol og ikke har noget imod drift, er Crawlee vejen. Hvis du vil have data uden browser-flåden, er managed den nemme rute. Mange teams ender med at bruge begge dele: én til skræddersyede crawls og én til "giv mig bare de strukturerede data"-tilfælde. Du kan se afvejningen på pris hos Thunderbits prisside.
Konklusion
Skal du bruge Crawlee? Ja — hvis du er Node- eller TypeScript-udvikler og vil have ét framework, der dækker både HTTP- og browser-crawling med en rigtig crawl-kø underneden. Løftet om to motorer er netop grunden til at vælge det, og det holdt fint i mine tests: den samme URL gik fra 0 til fulde data med et klasseskift, statisk ekstraktion var præcis og hurtig, og kø- og dybdecrawling virkede som dokumenteret.
Gå ind med to ting i baghovedet. Sæt budget af til den skjulte browser-download første gang, du bruger PlaywrightCrawler, og antag ikke, at de dele, jeg ikke testede — skala, crash-resume, indbyggede exports — fungerer lige så godt som de dele, jeg testede, før du har kørt dem på din egen workload. Som fundament til at bygge din egen crawler er Crawlee et stærkt og veludført stykke ingeniørarbejde. Som færdig, hands-off datapipe er det et startpunkt, ikke destinationen.
Prøv Thunderbit til udtræk af webdata Get Started Free
Ofte stillede spørgsmål
Er Crawlee gratis, og hvilken licens bruger det?
Ja. Crawlee er open source under Apache-2.0-licensen og installeres fra npm (npm install crawlee). Den version, jeg testede, var 3.17.0. At køre browser-crawlerne kræver en separat Chromium-download via Playwright, som også er gratis, men tilføjer cirka 81,7 MiB til din opsætning.
CheerioCrawler vs PlaywrightCrawler — hvilken skal jeg bruge?
Brug CheerioCrawler, når dataene ligger i den rå HTML eller i et bagvedliggende JSON API — det er meget hurtigere og starter aldrig en browser. Brug PlaywrightCrawler, når indholdet renderes af JavaScript, hvilket du kan se, når HTTP-sporet giver tomme resultater. I mine tests returnerede HTTP-motoren 0 elementer på en JS-renderet side, mens browser-motoren returnerede det hele. Fordi de deler samme API, er skiftet et klasseskift, ikke en omskrivning.
Skal Crawlee bruge en browser for at køre?
Kun for browser-crawlerne. CheerioCrawler kræver slet ingen browser. PlaywrightCrawler (og PuppeteerCrawler) kræver en browser-binær — installér den med npx playwright install chromium. Bemærk, at npm install crawlee alene ikke henter en browser, og det er den mest almindelige første-faldgrube.
Kan Crawlee håndtere pagination og crawl over flere sider?
Ja, og det er en af hovedgrundene til at vælge det frem for et rent browserbibliotek. enqueueLinks følger links (inklusive pagination-selectors som .next-page), RequestQueue deduplikerer og styrer crawl'et, og du får dybdekontrol samt grænser via maxRequestsPerCrawl. I testen gik et crawl inden for samme hostname igennem 11 sider på tværs af dybde 0–2, og fejlede requests blev sendt videre via en failedRequestHandler.
Hvordan står Crawlee i forhold til en hosted scraping API?
Crawlee er self-hosted: du skriver og kører crawleren selv og ejer skalering, proxies og anti-bot-håndtering. En managed API som Thunderbits distill/extract-endpoints returnerer ren Markdown eller schema-matchet struktureret JSON, mens rendering og anti-bot håndteres server-side, eksponeret via en API, en MCP-server og en CLI. Vælg Crawlee for maksimal kontrol over din egen pipeline; vælg en managed API, når du helst vil slippe for selv at drive og skalere browser-infrastrukturen.


