Web-scraping is een techniek om op een geautomatiseerde wijze informatie uit websites te “krabben”, zodat je die elders kunt opslaan of hergebruiken. Met Python 3 duiken we hierin.

Pieter van der Hijden

Global Initiative 2
https://fab.city – een lijst van steden met een pop-up van Zagreb, Kroatië

Om de werking van web-scraping te illustreren, kijken we naar de website https:// fab.city van het Fab City Network, een netwerk van steden die allemaal uiterlijk in 2054 economisch volledig circulair willen zijn. Op de homepage staat onder het kopje A Global Initiative een lijst van steden die aan dit Fab City Network deelnemen. Klik je op een van die steden, dan gaat een pop-up venster open met detailinformatie zoals stad en land, het jaartal van toetreden tot het Fab City Network, geo-locatie enzovoorts. Deze informatie willen we op een geautomatiseerde manier “bij elkaar harken”. De lijst van steden zou je nog handmatig met behulp van copy/paste kunnen kopiëren. Maar voor de informatie uit de pop-upvensters zou dat al veel bewerkelijker zijn. Bovendien zou je, telkens als nieuwe steden tot het Fab City Network toetreden, deze procedure weer opnieuw moeten (bedenken en) uitvoeren. Liever bedenken we één keer een geautomatiseerde procedure om de gewenste informatie te verzamelen en op te slaan. Op een later tijdstip kunnen we die procedure klakkeloos herhalen, dit is web-scraping.

Fab City Netwerk Fab City Network.
In plaats van deze
visualisatie willen we
de oorspronkelijke
data in handen krijgen

ANALYSE 
De bron van een webpagina bestaat uit een tekstbestand in HTML-codering. De browser zet deze source-code om in een voor mensen aantrekkelijke opmaak. Tijdens het surfen op internet zijn we vooral in deze opgemaakte webpagina’s geïnteresseerd; voor web-scraping is echter de achterliggende broncode-pagina veel interessanter. Iedere browser biedt de mogelijkheid om heen en weer te schakelen tussen de opgemaakte webpagina en de achterliggende broncode. Bekijk in Chrome bijvoorbeeld een opgemaakte webpagina en klik daarin op Ctrl+U. In een nieuw tabblad van de browser verschijnt dan dezelfde webpagina, nu niet opgemaakt, maar als broncode. 

Web scraping code 1 2
Broncode met het begin van de sectie “myGroup” en
gedetailleerde informatie over de steden Barcelona, Zagreb en Timphu

De broncode van de startpagina van https:// fab.city lijkt in eerste instantie een soepzootje. Probeer daar maar eens de juiste informatie uit te vissen. Bij nader inzien blijkt de broncode-pagina hiërarchisch van opbouw te zijn. Dat lijkt te gebeuren middels inspringen, maar dat is slechts schijn. In HTML-code zijn spaties, tabs en nieuwe regels niet van belang. Het enige wat ertoe doet is de structuur zoals die blijkt uit zogenoemde HTML tags: een label tussen “vishaken”, bijvoorbeeld “<xxx>“ om het begin van een onderdeel aan te geven en “</xxx>“ voor het einde. 
In de broncode gaan we op zoek naar de lijst met steden. Gebruik bijvoorbeeld Ctrl+F om op de stad Zagreb te zoeken. We komen dan in een deel van de hiërarchisch opgebouwde broncode terecht waar een opsomming van alle steden staat. Elke stad staat weer aan de top van een eigen hiërarchie waarin de details van die stad zijn opgenomen. 
In de afbeelding van de broncode zien we bovenaan het begin van een nieuwe sectie, genaamd <div id=“myGroup”>. Binnen deze sectie zien we een aantal malen een onderdeel dat begint met <div class=“city-info” collapse id=“xxx”> (waarbij “xxx” telkens de naam van een van de Fab Cities is in kleine letters). 
Binnen elk van deze steden treffen we vaste rubrieken aan, namelijk HTML-alinea’s (<p> ... </p>) met de labels city-name, focus, org-type, org-name. Binnen deze alinea’s staat de informatie waar we naar op zoek zijn. Soms is die informatie complex, bijvoorbeeld “city-name” bevat “Stad, Land”; uiteindelijk willen we zowel Stad als Land in handen krijgen. 

    

Jupyter

Hieronder zie je de Jupyter Notebook-gebruikersinterface (in de browser) met een leeg notebookdocument. Het geopende document bevat (vooralsnog) één markdown-cel voor documentatie en één code-cel voor programmacode (meestal Python 3). De menuopties en knoppen bieden mogelijkheden om cellen te creëren, bewerken, knippen/plakken en verwijderen, volgordes te veranderen enzovoort. Het runnen van een cel (of klikken op Ctrl+Enter) leidt tot het opmaken van een markup-cel of het uitvoeren van een code-cel. Als dat laatste tot standaarduitvoer leidt (tekst, tabellen, grafieken, enz.) komt die onder het codeblok te staan.

Jupyter

       

TOOLS 
We maken gebruik van de programmeertaal Python 3.
Als werkomgeving gebruiken we Jupyter Notebook op een Raspberry Pi 4 (ook beschikbaar voor Windows en als webservice). 
Met Jupyter Notebook kun je documenten maken waarin blokken met (Python-) broncode en met documentatie elkaar opvolgen.

We gebruiken twee Python 3 packages (bibliotheken), namelijk 
- requests voor het inlezen van een webpagina, en 
- BeautifulSoup (versie 4) voor het opvissen van een onderdeel van een webpagina. 

 

PYTHON 
In Jupyter Notebook ontwikkelen we een Pythonprogramma dat de webpagina inleest en analyseert. Het genereert een CSV-bestand met daarin één kopregel gevolgd door een aantal dataregels, één per stad. De kopregel bevat veldnamen die we uit de webpagina vissen (bijvoorbeeld “city-name”) en enkele automatisch te berekenen velden die we zelf van een naam voorzien. Een dataregel (de inhoud) van de betreffende velden in de webpagina en van de automatisch berekende velden. 

Ons programma doorloopt de volgende stappen: 

    1. Importeer de bibliotheken requests en BeautifulSoup (en ook datetime voor tijdregistratie en os om eventueel een directory aan te maken); 
    2. Lees de webpagina in en zet die om in een soup object (zie uitwerking in Fragment A);
    3. Schrijf een melding hierover in het logbestand; 
    4. Creëer een leeg outputbestand; 
    5. Stel de kopregel samen en schrijf die naar het outputbestand; 
    6. Loop één voor één de steden langs: 
      a. Zoek één voor één de waarde van de velden op (zie uitwerking in Fragment B); 
      b. Bereken de overige velden; 
    7. Schrijf de dataregels weg naar het outputbestand; 
    8. Sluit het outputbestand. 

Overigens schrijven we de output niet alleen naar het outputbestand, maar ook naar standaard-output, oftewel onze Jupyter Notebook. De afbeelding hieronder toont de eerste regels van het geproduceerde CSV-bestand. 

Web scraping code 2 2
Output van het Pythonprogramma

In de volgende paragrafen gaan we in op de stap 2 en stap 6a. De volledige listing staat in de repository. Bij stap 1: Lees de webpagina in en zet die om in een soup-object

Web scraping code 3 2
Fragment A: code uit het Python-programma

De betekenis van de programmaregels uit bovenstaand screenshot is als volgt: 

  1. Commentaar; 
  2. Stel de url van de webpagina in; 
  3. Lees de pagina en sla deze op in variabele req
  4. Sla datum en tijd op in variabele timestamp
  5. Lees de webpagina, interpreteer deze als HTML en sla deze op in soup, een hiërarchisch ingedeelde datastructuur; 
  6. Maak een lijst van de veldnamen die we per stad kunnen aantreffen. Bij deze stap: loop één voor één de steden langs. 
Web scraping code 4 2
Fragment B: code uit het Python-programma 

De betekenis van de programmaregels uit de bovenstaand afbeelding is als volgt: 

  1. Commentaar; 
  2. Geef de variabele linecount (regelnummer) de waarde 0 (nul); geef de variabele fields de waarde {} (lege dictionary);
  3. Loop door alle instanties van onderdeel <div class=“city-info” collapse> en ken dat toe aan city (ook city is een hiërarchie); 
  4. Geef in de fields dictionary het element “line” de waarde van linecount (regelnummer); als string!; 
  5. Loop door alle veldnamen zoals opgeslagen in keys
  6. Zoek in city naar een alinea-onderdeel met de in keys opgeslagen veldnaam; 
  7. Als dat niet te vinden is; 
  8. Geef dan aux de waarde “lege string”; 
  9. Zo niet (het is dus wél te vinden): 
    a. Geef dan aux de waarde van de veldnaam; 
    b. Geef het dictionary element in fields de waarde aux; 
  10. Niet afgebeeld: de code om de output data-regel samen te stellen en weg te schrijven én linecount op te hogen. 

TOT SLOT 
We hebben nu een webpagina ingelezen, de gewenste informatie eruit gevist en deze opgeslagen als CSV-bestand. Alle programmacode en documentatie staan in een Jupyter Notebook-document, fab.city.ipynb. Zie ook de git repository op https://gitlab.fabcloud.org/fl-management/ fab-lab-network-data