Naar de inhoud
maarten.
Alle stories

Webscraping bouwen: crawling, parsing en datakwaliteit

Maarten Soetens 12 min lezen

Een webscraper verzamelt niet alleen pagina’s: hij moet de juiste URL’s vinden, veranderende HTML verwerken en gegevens opslaan die controleerbaar blijven. In dit artikel lees je hoe crawling, parsing, toegangsregels en datakwaliteit samenkomen in een scraper die in de praktijk te onderhouden is.

URL-selectie bepaalt welke gegevens een scraper verzamelt

Een scraper begint met een afbakening van de pagina’s en gegevens die nodig zijn. Dat klinkt eenvoudig, maar een website kan duizenden URL’s bevatten met filters, sorteringen, taalvarianten en trackingparameters. Zonder selectiecriteria bezoekt de crawler al snel meerdere URL’s met dezelfde inhoud, of mist hij juist relevante detailpagina’s. Leg daarom vast welke domeinen, paden en paginatypen binnen de scope vallen en welke kenmerken een bruikbare pagina heeft.

URL’s kunnen uit een sitemap, een startpagina, categoriepagina’s of een bestaande lijst komen. Een sitemap is efficiënt als die actueel en volledig is, maar geeft niet altijd aan welke pagina’s inhoudelijk relevant zijn. Crawlen vanaf categoriepagina’s levert relaties tussen pagina’s op, maar maakt de uitkomst afhankelijk van de navigatiestructuur. In de praktijk worden bronnen vaak gecombineerd en worden gevonden URL’s genormaliseerd voordat ze worden bezocht.

Normaliseren kan betekenen dat fragmenten na een hekje worden verwijderd, parameters in een vaste volgorde worden gezet en bekende trackingparameters worden genegeerd. Pas daar wel inhoudelijke regels op toe: een parameter kan ook een productvariant of paginanummer aanduiden. Houd bij welke URL-regel een pagina heeft toegelaten of uitgesloten. Zo is later te verklaren waarom een record ontbreekt en voorkom je dat technische aannames ongemerkt de dataset bepalen.

Paginering en crawlvolgorde vragen om expliciete regels

Veel collecties zijn verdeeld over meerdere pagina’s. Paginering kan werken met genummerde URL’s, een knop voor de volgende pagina, cursorwaarden of een knop die resultaten dynamisch bijlaadt. De scraper moet vaststellen welk mechanisme wordt gebruikt en wanneer de collectie eindigt. Alleen aannemen dat de volgende URL steeds een oplopend paginanummer heeft, is kwetsbaar: sommige websites tonen een laatste pagina zonder resultaten, slaan nummers over of veranderen de sortering tijdens het verzamelen.

Bij HTML-paginering kan de crawler de link naar de volgende pagina volgen en controleren of de bestemming nieuw is. Bij cursorpaginering moet de cursor uit de respons worden gelezen en veilig worden doorgegeven aan het volgende verzoek. Stel grenzen in voor het aantal pagina’s en het aantal herhaalde URL’s. Die grenzen voorkomen eindeloze lussen wanneer een website steeds dezelfde volgende link oplevert of een navigatiefout bevat.

De crawlvolgorde heeft invloed op de volledigheid en de belasting van de website. Een breedte-eerst-strategie verzamelt eerst links op hetzelfde niveau; diepte-eerst volgt één pad zo ver mogelijk. Voor productcatalogi is het vaak nuttig categorieën apart te crawlen en de voortgang per categorie vast te leggen. Bewaar bezochte URL’s en resultaten van verzoeken, zodat een onderbroken crawl vanaf een bekende positie kan worden hervat. Dat maakt het eenvoudiger om ontbrekende segmenten gericht opnieuw te verwerken in plaats van alles opnieuw op te halen.

Robots.txt en toegangsbeperkingen horen bij het crawlontwerp

Het bestand robots.txt beschrijft welke delen van een website crawlers volgens de opgegeven regels mogen bezoeken. Een scraper hoort dit bestand op het juiste domein te controleren en de relevante regels voor zijn user-agent toe te passen. Robots.txt is geen toegangscontrole en geeft op zichzelf geen toestemming om gegevens te gebruiken. Het is wel een belangrijk signaal bij het bepalen van de crawlgrenzen. Controleer daarnaast de gebruiksvoorwaarden en de aard van de gegevens die worden verzameld, zeker wanneer het om persoonsgegevens of inhoud met beperkingen gaat.

Toegangsbeperkingen kunnen zichtbaar zijn als HTTP-fouten, een CAPTCHA, een inlogscherm of een blokkade na herhaalde verzoeken. Dat zijn signalen om de crawler te pauzeren of de aanpak te herzien, niet om de blokkade automatisch te omzeilen. Een scraper die proxies, wisselende identiteiten of browsertrucs inzet om beperkingen te ontwijken, kan zowel technisch onbetrouwbaar als ongewenst zijn. Bouw herkenning in voor statuscodes zoals 401, 403 en 429 en leg vast wanneer die optreden.

Een beheerste crawler houdt rekening met de capaciteit van de website. Beperk gelijktijdige verzoeken, voeg vertraging toe en gebruik waar mogelijk caching om dezelfde pagina niet onnodig opnieuw op te vragen. Respecteer expliciete limieten en stop wanneer de server aangeeft dat verzoeken moeten worden vertraagd. Deze keuzes bepalen niet alleen de belasting, maar ook hoe voorspelbaar de verzameling verloopt wanneer de website onder druk staat of haar toegangsbeleid wijzigt.

HTTP-responsen en retries vormen de basis van betrouwbaar crawlen

Een HTTP-verzoek levert meer op dan alleen de HTML-inhoud. Statuscode, headers, redirectinformatie en responstijd helpen bepalen wat de scraper met een pagina moet doen. Een statuscode 200 betekent bijvoorbeeld niet automatisch dat de verwachte pagina is ontvangen: de respons kan een foutmelding, lege template of verificatiepagina bevatten. Controleer daarom ook herkenbare kenmerken van de inhoud en leg relevante metadata naast de opgehaalde body vast.

Fouten vragen om verschillende reacties. Een tijdelijke serverfout kan na een wachttijd opnieuw worden geprobeerd, terwijl een 404 meestal niet beter wordt door direct opnieuw te verzoeken. Bij een 429 is vertragen belangrijker dan vaker proberen. Gebruik een beperkt aantal retries met oplopende wachttijden en voorkom dat meerdere processen dezelfde falende URL tegelijk opnieuw opvragen. Anders versterkt de scraper de belasting precies op het moment dat de server al aangeeft dat er een probleem is.

Redirects verdienen afzonderlijke aandacht. Een omleiding naar een nieuwe URL kan normaal zijn, maar een onverwachte omleiding naar een login- of blokkadepagina verandert de betekenis van de respons. Registreer de oorspronkelijke en uiteindelijke URL en stel grenzen aan het aantal redirects. Ook time-outs moeten onderscheid maken tussen verbindingsproblemen en een trage respons. Met gestructureerde logs van URL, statuscode, duur en fouttype zijn technische storingen te onderscheiden van veranderingen op de website. Zonder die gegevens lijkt een mislukte crawl vaak op ontbrekende brondata.

HTML-parsing zet pagina-elementen om in gestructureerde velden

HTML-parsing is het omzetten van de documentstructuur naar velden zoals titel, prijs, datum, beschrijving of productkenmerk. Begin met het analyseren van echte pagina’s uit verschillende delen van de site. Een selector die op één voorbeeldpagina werkt, kan falen op een categoriepagina, een variant of een oudere publicatie. CSS-selectors en XPath bieden verschillende manieren om elementen te vinden; de beste keuze is meestal de selector die het gewenste element beschrijft zonder afhankelijk te zijn van toevallige posities in de DOM.

Selectors op stabiele attributen, semantische elementen of herkenbare relaties zijn doorgaans minder kwetsbaar dan paden met veel geneste niveaus. Een selector als het derde element in een rij kan breken zodra er een label wordt toegevoegd. Gebruik waar mogelijk de context van een inhoudsblok en controleer hoeveel elementen de selector oplevert. Als een veld precies één waarde hoort te bevatten, zijn nul of meerdere matches aanleiding voor een waarschuwing in plaats van een stilzwijgende keuze.

Na selectie is normalisatie nodig. HTML-entiteiten worden gedecodeerd, witruimte wordt opgeschoond en waarden krijgen een passend formaat, zoals een datum in een uniforme tijdzone of een getal zonder presentatiesymbolen. Bewaar waar nodig zowel de ruwe tekst als de genormaliseerde waarde. Dat maakt fouten in conversieregels onderzoekbaar en voorkomt dat informatie verloren gaat voordat duidelijk is hoe de bron die presenteert. Houd ook rekening met ontbrekende velden; een ontbrekende waarde is iets anders dan een lege tekst of een nul.

Veranderende paginaopbouw vraagt om detectie en herstelbare parsing

Webpagina’s veranderen regelmatig. Een ontwerpupdate kan classnamen aanpassen, een veld verplaatsen of een blok vervangen door een andere component. Soms wijzigt de HTML-structuur terwijl de pagina er in een browser vrijwel hetzelfde uitziet. Als parsing afhankelijk is van één specifieke selector, kan de scraper dan lege of verkeerd gekoppelde gegevens opslaan zonder dat het proces zelf stopt. Detectie van structurele veranderingen is daarom onderdeel van de parser, niet alleen onderhoud achteraf.

Definieer per paginatype verwachtingen voor essentiële velden: een detailpagina hoort bijvoorbeeld een titel en een unieke identificatie te bevatten. Controleer ook aantallen matches, lege velden en opvallende verschuivingen in de verdeling van waarden. Een plotselinge daling van ingevulde datums kan wijzen op een gewijzigde selector, maar ook op een echte wijziging in de bron. Bewaar foutvoorbeelden en representatieve HTML-fragmenten zodat een ontwikkelaar de afwijking kan onderzoeken zonder de hele crawl opnieuw uit te voeren.

Een parser kan meerdere varianten ondersteunen, bijvoorbeeld selectors voor een oudere en een nieuwere paginastructuur. Dat is nuttig wanneer wijzigingen gefaseerd worden uitgerold, maar meerdere brede fallbacks kunnen ook verkeerd geclassificeerde inhoud opleveren. Maak daarom duidelijk welke variant is gebruikt en laat onbekende structuren zichtbaar falen. Een gecontroleerde fout is beter dan een plausibel ogend record met velden uit de verkeerde sectie. Versiebeheer van parserregels en tests met opgeslagen voorbeeldpagina’s maken wijzigingen reproduceerbaar en beperken regressies.

Datakwaliteit controleer je met validatie en bronvergelijking

Een scraper kan zonder technische fout draaien en toch onbruikbare gegevens produceren. Datakwaliteit vraagt daarom om controles op volledigheid, geldigheid, consistentie en actualiteit. Controleer eerst of verplichte velden aanwezig zijn en waarden passen bij hun verwachte type. Een datum moet bijvoorbeeld als datum te verwerken zijn en binnen een zinvol bereik vallen. Een productidentificatie hoort niet onverwacht leeg te zijn, en een URL moet naar een geldige bronpagina verwijzen.

Controleer vervolgens relaties tussen velden. Een einddatum hoort niet vóór een begindatum te liggen, een totaalbedrag moet aansluiten op de afzonderlijke componenten als die beschikbaar zijn en één bron-ID hoort niet ongemerkt aan meerdere verschillende objecten gekoppeld te raken. Grenzen en regels moeten aansluiten op het domein: een generieke controle op een positief getal kan bijvoorbeeld geldige negatieve waarden uitsluiten wanneer het om een saldo of temperatuur gaat.

Vergelijk resultaten over tijd en met de bron. Een plotselinge verdubbeling van het aantal records kan het gevolg zijn van een gewijzigde URL-regel, terwijl een daling in veldvulling kan wijzen op een parserprobleem. Steekproeven waarbij opgeslagen waarden naast de oorspronkelijke pagina worden gelegd, vinden fouten die automatische regels missen. Bewaar ook aantallen gevonden, succesvol verwerkte en afgekeurde pagina’s. Met die verhouding wordt zichtbaar of een ogenschijnlijk complete dataset in werkelijkheid is ontstaan uit een kleine selectie van de bedoelde bron.

Opslag, deduplicatie en monitoring maken crawls beheersbaar

Opslag bepaalt of verzamelde gegevens later terug te vinden, te vergelijken en opnieuw te verwerken zijn. Gebruik een stabiele sleutel, zoals een bron-ID of een genormaliseerde URL, om records aan dezelfde entiteit te koppelen. Een URL is niet altijd een betrouwbare unieke sleutel: URL’s kunnen veranderen, terwijl hetzelfde object blijft bestaan, of meerdere URL’s kunnen naar dezelfde inhoud verwijzen. Leg daarom waar mogelijk zowel de bronidentificatie als de URL vast en documenteer de gekozen deduplicatieregel.

Bewaar naast de actuele waarden ook informatie over het moment van ophalen en de bronpagina. Afhankelijk van het gebruik kan een wijzigingsgeschiedenis nodig zijn, bijvoorbeeld om te zien wanneer een veld veranderde. Ruwe HTML is handig voor foutanalyse en het opnieuw uitvoeren van parsing, maar vraagt om bewuste keuzes rond opslagvolume, bewaartermijnen en gegevensbescherming. Scheid ruwe bronresponsen van genormaliseerde records, zodat parseraanpassingen niet betekenen dat de oorspronkelijke inhoud al verloren is.

Monitoring moet verder gaan dan de vraag of een proces is gestart en geëindigd. Volg onder meer het aantal bezochte URL’s, responsstatussen, parsefouten, ontbrekende velden en nieuwe of dubbele records. Stel signalen in voor onverwachte afwijkingen, maar interpreteer die in samenhang: een lager aantal pagina’s kan een seizoenseffect zijn of een gebroken crawler. Maak herverwerking mogelijk voor specifieke URL’s of batches en zorg dat dezelfde batch niet onbedoeld dubbele records toevoegt. Zo blijft de dataset navolgbaar wanneer bronpagina’s, parserregels of crawlconfiguratie veranderen.

Veelgestelde vragen

Hoe scrape je een website die inhoud via JavaScript laadt?

Onderzoek eerst of de JavaScript-inhoud ook via een gewone HTTP-aanvraag beschikbaar is; gebruik pas browserautomatisering als dat nodig blijkt. Bekijk in de browser welke netwerkverzoeken de pagina doet en of die een gegevensrespons opleveren die je volgens de toegangsvoorwaarden mag gebruiken. Als de informatie alleen na uitvoering van JavaScript verschijnt, kan een headless browser de pagina laden en de gerenderde inhoud beschikbaar maken. Dat kost doorgaans meer tijd en middelen dan HTML rechtstreeks ophalen, dus beperk browserautomatisering tot de pagina’s waarvoor het nodig is.

  • Controleer of een openbare API of gegevensfeed beschikbaar is.
  • Gebruik opgeslagen voorbeeldpagina’s om wijzigingen in de geladen inhoud te testen.

Wanneer kun je beter een API gebruiken dan een webscraper?

Gebruik bij voorkeur een API wanneer die de benodigde gegevens officieel en binnen de toegestane voorwaarden beschikbaar stelt. Een API levert vaak gestructureerde velden, waardoor je minder afhankelijk bent van wijzigingen in de HTML-opmaak. Controleer wel of de API de gewenste dekking, actualiteit en gebruiksrechten biedt; een endpoint dat technisch bereikbaar is, is niet automatisch bedoeld voor elk gebruik. Als een API ontbreekt of onvoldoende gegevens bevat, kan scraping een alternatief zijn, mits de websitevoorwaarden en toepasselijke regels dat toelaten.

  • Vergelijk welke velden en pagina’s beide bronnen dekken.
  • Controleer authenticatie, limieten, versiebeleid en toegestane toepassingen.

Hoe test je een webscraper voordat je die op grote schaal uitvoert?

Test een webscraper eerst met een kleine, representatieve set pagina’s en controleer de opgeslagen uitkomsten handmatig. Neem verschillende paginatypen, ontbrekende velden en bekende varianten van de paginaopbouw mee. Zo ontdek je fouten voordat ze zich over een volledige verzameling verspreiden. Maak daarna automatische tests voor verwachte velden, datatypen en relaties tussen waarden, en voer die uit wanneer scraper- of parserregels veranderen. Test ook foutscenario’s, zoals time-outs en onverwachte HTTP-statussen, zodat duidelijk is hoe de crawler daarop reageert.

  • Bewaar voorbeeldpagina’s als vaste testinvoer.
  • Vergelijk geëxtraheerde waarden met de bron en controleer foutmeldingen.

Hoe vaak moet je een webscraper opnieuw laten draaien?

Laat een webscraper zo vaak draaien als nodig is om aan de actualiteitsbehoefte van de gegevens te voldoen, niet vaker. De juiste frequentie hangt af van hoe snel de bron verandert en hoe recent de gegevens moeten zijn voor het beoogde gebruik. Een dagelijks bijgewerkte voorraad kan een andere planning vragen dan een catalogus die zelden verandert. Begin met een beperkte frequentie, meet hoe vaak waarden daadwerkelijk wijzigen en pas het schema daarop aan. Houd rekening met de belasting voor de website en eventuele toegangs- of gebruiksvoorwaarden.

  • Leg per gegevenstype vast hoe actueel het moet zijn.
  • Haal ongewijzigde pagina’s niet onnodig vaak opnieuw op.

Welke programmeertaal is geschikt om een webscraper te bouwen?

Python is voor veel webscrapers een geschikte keuze, maar de beste programmeertaal is de taal die past bij je team, infrastructuur en technische eisen. Python heeft veel beschikbare hulpmiddelen voor HTTP-verzoeken, HTML-parsing en geautomatiseerde tests. JavaScript kan handig zijn wanneer je bestaande webtechnologie wilt hergebruiken of browserautomatisering nodig hebt. Bij de keuze tellen ook onderhoudbaarheid, kennis binnen het team, schaal en koppelingen met bestaande systemen mee. Probeer de aanpak eerst op een kleine set pagina’s voordat je een grotere architectuur vastlegt.

  • Kies hulpmiddelen die passen bij de gebruikte paginatypen.
  • Beoordeel naast bouwgemak ook testen, logging en onderhoud.
Portret van Maarten

Maarten

Freelance developer in Nijmegen

Even kennismaken?

Vertel kort wat er speelt. Dan hoor je wat er kan, wat ik anders zou doen en waar AI bij jou wél en niet iets toevoegt. Vrijblijvend.

[email protected]
Het kantoor in Nijmegen
© 2026 maarten.online Sitemap Privacy Algemene voorwaarden
Het kantoor in Nijmegen

Maarten.

Freelance developer in Nijmegen. Liever direct contact? Dat kan ook.

Kennismaken

Laat je gegevens achter, dan kijken we of het klikt. Vrijblijvend en zonder verkooppraat.

Maarten

Stuur een bericht via WhatsApp

Hoi! Waar kan ik je mee helpen?

nu