Scrapy bliver ofte stemplet som “kan ikke håndtere moderne websites”, fordi det ikke kører JavaScript. Men den opfattelse er helt vendt på hovedet. Netop det, at siden ikke rendres, er hele pointen — og når man først ser idéen i praksis, ligner det ikke længere en manglende funktion.
Jeg beviste det for mig selv i ét enkelt forløb. Jeg lavede et katalog-setup, der blev renderet med JavaScript, pegede Scrapy på den side, en browser ville vise, og fik 0 produktkort tilbage. Derefter rettede jeg den samme spider mod det JSON-endpoint, som siden stille og roligt kaldte i baggrunden, og fik 8/8 elementer hjem — helt rent. Samme værktøj, samme session, modsatte resultater — og forskellen mellem de to tal er kernen i denne anmeldelse.
Hvad Scrapy egentlig er — og ikke er

Scrapy er et Python-framework til at crawle websites og hente strukturerede data ud. Det er selv vedligeholdernes egen beskrivelse i oversigtsdokumentationen, og efter at have brugt det, passer den faktisk meget præcist — der er ingen marketing, der skal korrigeres. Det er gammelt og etableret nok til at være det naturlige svar, når en Python-udvikler spørger, hvad seriøse folk bruger til scraping, og repositoriet understøtter det: omkring 62.981 GitHub-stars pr. 2026-07-07 (scrapy/scrapy), med 11.773 forks og 590 åbne issues samme dag. BSD-3-Clause-licens, Python 3.10 eller nyere, og den version jeg testede, var 2.17.0, som tilfældigvis blev frigivet samme morgen, jeg kørte disse tests — altså ingen version med et lille forbehold i denne omgang.
Her er den linje, der adskiller det fra de nyere AI-crawler-værktøjer: Scrapy arbejder som udgangspunkt kun over HTTP. Ingen browser. Ingen renderingsmotor. Det henter HTML over nettet, sender det til en parser og lader dig trække felter ud med CSS-selectors eller XPath. At kalde det en begrænsning er kun halvt sandt — og overser fuldstændigt designet. Scrapy tager udgangspunkt i, at det som regel er forkert at starte en headless Chrome til en rutineopgave; den smartere vej er at finde den dataanmodning, siden allerede sender, og ramme den direkte.
Det er ikke bare min tolkning af værktøjet. Den officielle dokumentation om dynamisk indhold siger det helt direkte: Find og genskab først den underliggende dataanmodning, og brug kun en headless browser som fallback, når det ikke er praktisk at genskabe kaldet. De fleste scrapers åbner browseren først og tænker aldrig på API'et. Scrapy vender standardvalget om.
Nøglefunktioner, og designvalget bag hver af dem
Under motorhjelmen er Scrapy en samling dele, der alle tager udgangspunkt i én antagelse om dig: at du er en udvikler, der vil have kontrol — ikke en wizard med ét klik.
Spiders. Du skriver en klasse, giver den start-URL'er og definerer en parse-callback, der enten returnerer items eller følger flere links. Det er mere at skrive end i et no-code-værktøj — ekstraktionsreglerne er dine egne — men til gengæld får du præcis kontrol over, hvad der samles op, og hvor crawlen fortsætter hen.
Selectors. Parsingen bygger på parsel, som igen ligger oven på lxml. Både CSS og XPath er førsteklasses borgere, ikke noget der er sat på bagefter. At lxml ligger bagved, er en stor del af forklaringen på, at udvælgelsen er hurtig, og at koden læser som intentioner i stedet for en knude af string-manipulation.
Feed exports. Ret en spider mod en fil, og Scrapy serialiserer dine items til JSON, JSON Lines, CSV eller XML uden ekstra limkode. I min test skrev én spider både JSON og CSV uden at jeg skulle skrive en eneste eksportlinje — historien om feed exports holder, og den gør, hvad den lover.
AutoThrottle og crawl-kontrol. Anmodninger planlægges asynkront via Twisted, og du får samtidighedsgrænser, download-forsinkelser, dybdebegrænsninger, AutoThrottle til adaptiv rate limiting og lydighed over for robots.txt. Det er de mekanismer, der forhindrer en bred crawl i at blive til et server-hammerende problem.
Kun HTTP, omformuleret som en fordel. Ingen browser betyder lavt memory-forbrug, høj throughput og ingen renderingsmotor, der skal holdes i live — så længe de data, du vil have, kan nås via almindelig HTTP. Og det kan de, oftere end browser-first-folk antager.
Opsætning: dependency-stakken, ingen lægger på screenshots

Installationen var helt udramatisk, og for et framework i den størrelse er det faktisk værd at sige højt. pip install Scrapy==2.17.0 kørte rent igennem i et friskt virtual environment på macOS arm64, hentede binary wheels og kompilerede ikke sig selv ind i en mur. Intet dramatisk at rapportere — og det er netop pointen.
Men kig på, hvad der faktisk kom ned. scrapy version -v meldte Scrapy 2.17.0 oven på lxml 6.1.1, Twisted 26.4.0, pyOpenSSL 26.3.0 og cryptography 49.0.0, med parsel, cssselect og tldextract som resten af følget. Det er en reel footprint — hele crawler-frameworkets vægt, ikke bare en enkelt HTML-parser. På denne maskine fandtes der wheels til det hele, og installationen forblev gnidningsfri. På andre opsætninger advarer den officielle dokumentation stadig om platformspecifik friktion, og historisk er det især cryptography- og Twisted-delen af stakken, der kan give problemer, så der bør afsættes plads til det, hvis du kører på noget usædvanligt. Her var opsætningen let; men størrelsen på det, der installeres, er stadig god at kende på forhånd, fordi du reelt tager et framework ind — og et framework fylder, som frameworks nu gør.
Håndgribeligt: hvad der holdt stik

Da det først var installeret, var den statiske vej problemfri. Fuld recall, intet tabt.
| Test | Resultat | Runtime |
|---|---|---|
| Lokal statisk katalogside + pagination | 12/12 produkter | 0.557s |
| CSV-eksport fra statisk katalog | 12 rækker skrevet | (samme kørsel) |
| Artikeludtræk | titel + 3/3 brødtekstafsnit | 0.416s |
| Crawl-graf, DEPTH_LIMIT=2 | 11 sider på dybde 0/1/2 | 0.904s |
| Lokal 500-side | status 500 fanget, ingen crash | 0.424s |
| Books to Scrape (offentlig) | 20 produkter | 2.053s |
| Quotes to Scrape spider (offentlig) | 12 quote-items | 3.465s |
Spideren til det statiske katalog gik gennem pagination fra side ét til side to og fangede 12/12 forventede poster, og skrev dem derefter ud som både JSON og CSV i samme forløb. Artikel-testen er den, man bør hæfte sig ved. Scrapy forsøgte ikke selv at rydde siden op til pæn Markdown — i stedet lod det mig målrette article-felter med eksplicitte selectors og holde navigation og footer-tekst i separate felter, så jeg fik 3/3 brødtekstafsnit, mens standardtekst blev isoleret i stedet for at blive blandet ind i outputtet. Det er kompromiset: du skriver selectors, og du får præcis det, du bad om — ikke mere, ikke mindre.
Crawl-kontrollen fungerede også fint i mindre skala. Med DEPTH_LIMIT=2, en kort download-forsinkelse, concurrency pr. domæne og robots.txt slået til, nåede crawl-grafen 11 sider fordelt på dybde 0, 1 og 2, og dybdetællingen opførte sig som forventet. Fejlhåndteringen var lige så udramatisk. Den bevidste 500-side kom tilbage som et struktureret item, hvor status 500 var eksponeret via handle_httpstatus_list — ingen exception, ingen afbrudt kørsel. Scrapy behandler en fejlkode som noget, du håndterer inde i spider-logikken, ikke som en overraskelse, der vælter hele crawlen.
Håndgribeligt: JavaScript-muren og døren ved siden af

Og nu til det resultat, som denne anmeldelse egentlig handler om.
Jeg pegede Scrapy's HTTP-fetcher mod et katalog-setup, der blev renderet med JavaScript. Den hentede kilde-HTML'en, fandt 0 .product-card-noder og gik videre — fordi den aldrig kørte det script, der skulle have tegnet kortene. Den offentlige Quotes to Scrape JS-side fortalte samme historie: 0 renderede quote-noder. Hvis man stoppede testen dér, ville man skrive Scrapy af som uegnet til alt, der er bygget i dette årti.
Men man skal ikke stoppe dér. JS-kataloget blev i baggrunden fyldt via et JSON-API, som det jo ofte er. Jeg pegede den samme Scrapy-spider mod det endpoint og fik 8/8 produkter hjem på 0.416s — ingen browser, ingen rendering, bare et kald til den URL, siden allerede brugte, og en parsing af den JSON, der kom tilbage.
Den side-om-side sammenligning er reproduce-the-request-filosofien i mini-format. Den renderede side er en afledning; data lå hele tiden bag et API, og Scrapy's design skubber dig hen mod at ramme det direkte i stedet for at betale for en headless browser, der skal sidde og se siden bygge sig selv op. Det er hurtigere, lettere og går sjældnere i stykker — en API-kontrakt er langt mere stabil at bygge på end en bunke client-side DOM. Men der er et forbehold: det er manuelt. Du skal selv åbne network-tabben, finde requesten og genskabe dens headers og parametre. Scrapy finder ikke API'et for dig; det gør det bare meget nemt at kalde det, når du først har fundet det.
To grænser, helt tydeligt sagt. Når der reelt ikke findes en underliggende request at genskabe — altså hvis data er indbygget via client-side rendering uden noget API bagved — har Scrapy brug for en headless-browser-integration, som du selv kobler på, og den vej testede jeg ikke i denne gennemgang. Og alt ovenstående kørte på små fixtures og offentlige demosider. Jeg lavede ikke en crawl på 100 til 1.000 sider, så jeg gør ingen påstande om memory, throughput eller retry-adfærd i stor skala — den asynkrone kerne og crawl-kontrollen er stærke signaler, men et signal er ikke en måling.
Fordele og ulemper
Fordele:
- HTTP-only-design er hurtigt og let — 12/12 statisk recall på omkring et halvt sekund, 8/8 fra et JSON-API på 0.416s, ingen browseroverhead.
- Reproduce-the-request-tilgangen virker i praksis: en JS-side, der gav 0, afleverede alle 8 elementer via sit bagvedliggende API.
- CSS- og XPath-selectors med
lxmli ryggen holder udtrækskoden læsbar og hurtig. - Feed exports til JSON/CSV/XML uden ekstra eksportkode.
- Tydelig fejlhåndtering — en 500 kommer tilbage som en status, du kan fange, ikke som et crash.
- Modne crawl-kontroller: concurrency, delays, depth limits, AutoThrottle, robots.txt.
- BSD-3-Clause-licens; ren installation på en moderne maskine.
Ulemper:
- Renderer ikke JavaScript efter design — 0 noder på en client-rendered side, indtil du selv finder API'et.
- Det er manuelt at finde den underliggende request; Scrapy peger dig ikke hen til endpointet.
- En relativt stor dependency-stak (Twisted, lxml, cryptography, pyOpenSSL, parsel, tldextract) — glat her, men historisk en friktionskilde på usædvanlige platforme.
- Mere kode end no-code- eller auto-extraction-værktøjer; spiders er dine at skrive og vedligeholde.
- Min test dækkede små fixtures og demosider, ikke store crawls — driftssikkerhed i stor skala er ikke bevist i denne omgang.
Hvem det er til — og hvem der bør gå videre

Scrapy er til udviklere, der vil have kontrol ned på kodeniveau og tænker i requests, ikke i sider. Hvis din første tanke ved et langsomt JavaScript-site er "der ligger et API her et sted", så er værktøjet bygget præcis til den intuition. Det belønner folk, der er trygge ved at skrive selectors, læse network-tabben og eje deres ekstraktionslogik fra ende til anden. Til statiske sites, kataloger med pagination og alt, der ligger bag et opdageligt JSON-endpoint, er det hurtigt og præcist.
Gå videre — eller brug det sammen med noget andet — hvis du ikke har lyst til at skrive og vedligeholde spider-kode, eller hvis dine mål udelukkende renderer data client-side uden nogen reproducerbar request, og du helst ikke selv vil sætte en headless browser op. Og hvis drømmen var at pege et værktøj mod en URL og få ren, struktureret output uden selv at definere ekstraktionsregler, så var det aldrig Scrapy's opgave, og det har det heller aldrig påstået.
Alternativer, og hvor Thunderbit passer ind
Prøv Thunderbit til udtræk af webdata
Start med, hvad du faktisk skriver dig op til: et gratis open source-framework, som du selv drifter og vedligeholder. Du ejer spiders, dependency-stakken og arbejdet med at finde hvert websites datarequest. Til gengæld betaler du intet pr. request, beholder alt internt og får fuld kontrol. For mange teams er det det rigtige valg, og denne anmeldelse handler ikke om at tale nogen fra det.
Afvejningen ligger i renderings- og drift-problemet, og Scrapy's svar er, at du selv løser det: du finder API'et, genskaber requesten og håndterer tilfælde uden API ved selv at koble en browser på. En administreret AI-scraping-API løfter den del af dine skuldre. Det er her, Thunderbit's developer stack passer ind for tekniske læsere — en AI scraping API plus MCP-server plus CLI, ikke den browser-extension, som salgs- og driftsfolk bruger. POST /distill omdanner en side til ren, LLM-klar Markdown; POST /extract returnerer struktureret JSON ud fra et schema, du selv definerer; og begge håndterer JavaScript-rendering, anti-bot og dynamisk indhold server-side — også i de client-renderede tilfælde, hvor Scrapy beder dig om at bruge en browser. Der findes en MCP-server til AI-agenter og kodningsassistenter (med en gratis thunderbit_suggest_fields til at afgrænse siden, før du bruger noget), og en CLI via npx @thunderbit/thunderbit-cli til terminal, CI eller cron-opgaver.
Forskellen handler ikke om kvalitet, men om ejerskab. Scrapy er et bevidst engineering-framework: du vedligeholder spideren, pipelinen og JS-strategien, og du får total kontrol uden per-kald-omkostning. Thunderbit's stack overtager renderings- og ekstraktionslaget som en administreret service, så du slipper for at grave i network-tabben og betaler pr. kald i stedet. Lille, kode-først og glad for at eje hvert skridt? Så passer Scrapy bedre. Skal du skalere på tværs af hundredvis af websites og vil du helst ikke genskabe requests manuelt pr. site? Så fjerner den administrerede løsning hele den kategori af arbejde.
For det bredere felt dækker disse benchmark-indlæg naboerne: den fulde open-source scraper-sammenligning, Colly's anmeldelse af den browserløse Go-crawler og Scraplings anmeldelse af adaptive selectors.
Konklusion
Skal du bruge Scrapy? Ja — hvis du er udvikler og vil have kontrol, og hvis du køber verdenssynet: render ikke siden, find requesten bag den. I testen gav den filosofi præcis det udbytte, den lover. Et JavaScript-katalog gav HTTP-fetcheren 0 kort; det JSON-API, der fodrede siden, afleverede alle 8 elementer til den samme spider. Statisk udtræk ramte 12/12, artikel-selectors holdt 3/3 afsnit fri for boilerplate, crawl-grafen respekterede sin dybdegrænse på 11 sider, og en 500'er kom tilbage som en håndteret status i stedet for et crash.
Men man skal kende rammerne for påstanden. Scrapy renderer ikke JavaScript, og det finder ikke API'et for dig — den refleks skal du selv bygge. Dependency-stakken er så stor, som et framework nu er, og kan drille på særlige platforme, selv om den var ren her. Og jeg testede fixtures og demosider, ikke en crawl på tusind sider, så behandl skaleringshistorien som lovende, men ikke bevist. Inden for de grænser er Scrapy det værktøj, der mest konsekvent står bag en stille, næsten radikal idé: den hurtigste vej gennem en webside er som regel ikke gennem websiden overhovedet.
Prøv Thunderbit til udtræk af webdata Get Started Free
Ofte stillede spørgsmål
Kan Scrapy scrape sider, der renderes med JavaScript? Ikke med standard-HTTP-fetcheren — den returnerede 0 noder på både en JS-fixture og den offentlige Quotes JS-side, fordi den henter HTML uden at køre en browser. Den tilsigtede vej er at finde den underliggende dataanmodning, siden laver, og ramme den direkte; i min test gav JSON-API'et bag et JS-katalog alle 8 elementer fra sig. På sider uden en reproducerbar request må du selv koble en headless browser på.
Hvad betyder "gengive requesten" egentlig? De fleste dynamiske sider henter deres data fra et JSON-API i baggrunden og renderer det derefter client-side. I stedet for at køre en browser og se det ske, åbner du network-tabben, finder API-kaldet og peger Scrapy direkte på det. Det er hurtigere og mere stabilt end rendering — en API-kontrakt bryder sjældnere end en DOM — men det er manuelt arbejde, og Scrapy finder ikke endpointet for dig.
Er Scrapy svær at installere?
For mig var det nemt — pip install Scrapy==2.17.0 gennemførte uden kompileringsfejl i et frisk venv på macOS, via binary wheels. Men den trækker en ret stor stak ind (Twisted, lxml, cryptography, pyOpenSSL, parsel, tldextract), og den officielle dokumentation advarer stadig om platformspecifik friktion på nogle systemer, så der bør være lidt luft, hvis du kører på noget usædvanligt.
Hvilke output-formater understøtter Scrapy? Feed exports dækker JSON, JSON Lines, CSV og XML direkte fra start — peg en spider mod en fil, og den serialiserer dine items uden ekstra kode. I min test producerede én spider både JSON og CSV i samme gennemløb. Bemærk, at den eksporterer de felter, du selv har valgt; den rydder ikke automatisk en side op til Markdown.
Er Scrapy gratis til kommerciel brug? Ja, BSD-3-Clause er en permissiv licens, som også er kommercielt venlig. Som altid bør du dobbelttjekke den aktuelle licens på repo'et, før du bygger videre på det, og husk at være ansvarlig med user-agent, proxy og rate limits — at man kan, betyder ikke, at man bør.


