DEV Community

Cover image for Van Webtabel naar Pandas DataFrame in 30 Seconden
circobit
circobit

Posted on

Van Webtabel naar Pandas DataFrame in 30 Seconden

Je hebt de perfecte dataset gevonden op een website. Nu heb je die in Pandas nodig.

De traditionele aanpak:

import pandas as pd

# Hopen dat de websitestructuur simpel is
tables = pd.read_html('https://example.com/data')

# Raden welke tabel je wilt
df = tables[0]  # Misschien? Laten we eens kijken...

# De problemen ontdekken
print(df.dtypes)
# Alles is 'object' (string)
# Getallen hebben punten
# Datums zijn niet parseerbaar
# Kolomnamen hebben spaties

# 30 minuten opschonen...
Enter fullscreen mode Exit fullscreen mode

Laat me je een snellere manier laten zien.

Het Probleem met pd.read_html()

Pandas' read_html() is handig maar beperkt:

  1. Geen tabelselectie — Het pakt alle tabellen. Je raadt welke index je nodig hebt.

  2. Geen opschoning — Getallen zoals "1.234.567" blijven strings.

  3. CORS-problemen — Veel sites blokkeren programmatische toegang.

  4. JavaScript-rendering — Dynamische tabellen bestaan niet in de ruwe HTML.

  5. Authenticatie — Kan geen ingelogde content bereiken.

Voor snelle scripts werkt het. Voor serieuze analyse heb je iets beters nodig.

De 30-Seconden Workflow

Dit is wat ik werkelijk doe:

Stap 1: Exporteren vanuit de Browser (5 seconden)

Met HTML Table Exporter:

  1. Klik op de tabel die ik wil
  2. Klik op het extensie-icoon
  3. Selecteer het "Voor Pandas"-profiel
  4. Exporteer als CSV vanuit de gemarkeerde tabel in de extensie

De extensie ziet precies wat jouw browser ziet—JavaScript-gerenderde content, ingelogde pagina's, alles.

Stap 2: Laden in Pandas (5 seconden)

import pandas as pd

df = pd.read_csv('export.csv')
print(df.dtypes)
Enter fullscreen mode Exit fullscreen mode

Dat is het. De data is al schoon.

Wat "Schoon" Echt Betekent

Als ik exporteer met het "Voor Pandas"-profiel, handelt de extensie het volgende af:

Getalnormalisatie

Voorheen: "1.234.567,89" (Europees formaat)
Erna:     1234567.89     (float)

Voorheen: "€1.234,56"
Erna:     1234.56
Enter fullscreen mode Exit fullscreen mode

De CSV bevat genormaliseerde getallen die Pandas correct parset:

# Zonder opschoning:
df['omzet'].sum()  # TypeError: can only concatenate str

# Met opschoning:
df['omzet'].sum()  # 4892341.50 ✓
Enter fullscreen mode Exit fullscreen mode

Boolean-Conversie

Voorheen: "Ja", "Nee", "J", "N", "True", "False"
Erna:     true, false
Enter fullscreen mode Exit fullscreen mode
# Filteren werkt direct
actieve_gebruikers = df[df['is_actief'] == True]
Enter fullscreen mode Exit fullscreen mode

Null-Afhandeling

Voorheen: "-", "N.v.t.", "n.v.t.", "", "null", "—"
Erna:     (leeg, geparsed als NaN)
Enter fullscreen mode Exit fullscreen mode
# Null-detectie werkt
df['optioneel_veld'].isna().sum()  # Correcte telling
Enter fullscreen mode Exit fullscreen mode

Snake Case Headers

Voorheen: "Omzet (€M)", "Aantal Gebruikers", "Groeipercentage %"
Erna:     omzet_m, aantal_gebruikers, groeipercentage
Enter fullscreen mode Exit fullscreen mode
# Schone kolomtoegang
df['omzet_m']  # In plaats van df['Omzet (€M)']
Enter fullscreen mode Exit fullscreen mode

Reëel Voorbeeld: FBRef Voetbalstatistieken

Stel dat ik Premier League spelerstatistieken wil van FBRef.

De Oude Manier

import pandas as pd
import requests
from bs4 import BeautifulSoup

url = 'https://fbref.com/en/comps/9/stats/Premier-League-Stats'
response = requests.get(url)
soup = BeautifulSoup(response.content, 'html.parser')

# De juiste tabel vinden (er zijn er veel)
table = soup.find('table', {'id': 'stats_standard'})

# Handmatig parsen omdat de headers complex zijn
# FBRef gebruikt gegroepeerde headers: "Playing Time" overspant meerdere kolommen
# Dit breekt pd.read_html()

# 45 minuten later...
Enter fullscreen mode Exit fullscreen mode

De Nieuwe Manier

  1. Open FBRef in de browser
  2. Klik extensie → selecteer tabel → exporteer met "Voor Pandas"-profiel
  3. Laden:
df = pd.read_csv('fbref_stats.csv')
print(df.columns.tolist())
# ['player', 'nation', 'squad', 'playing_time_mp', 
#  'playing_time_starts', 'performance_gls', ...]
Enter fullscreen mode Exit fullscreen mode

De gegroepeerde headers ("Playing Time", "Performance") worden automatisch samengevoegd met subheaders.

De Code Die Ik Niet Meer Schrijf

Hier is opschooncode die ik vroeger voor elke webscrape schreef:

def clean_web_data(df):
    """De functie die ik niet meer nodig heb."""

    # Getalkolommen repareren
    for col in df.select_dtypes(include='object'):
        # Probeer te converteren naar numeriek
        try:
            # Valutasymbolen verwijderen
            cleaned = df[col].str.replace(r'[$€£¥]', '', regex=True)
            # Duizendtalscheidingstekens verwijderen
            cleaned = cleaned.str.replace(',', '')
            # Converteren
            df[col] = pd.to_numeric(cleaned, errors='ignore')
        except:
            pass

    # Boolean-kolommen repareren
    bool_map = {
        'ja': True, 'nee': False,
        'true': True, 'false': False,
        'j': True, 'n': False,
        '1': True, '0': False,
    }
    for col in df.columns:
        if df[col].str.lower().isin(bool_map.keys()).all():
            df[col] = df[col].str.lower().map(bool_map)

    # Null-waarden repareren
    null_values = ['', '-', 'N.v.t.', 'n.v.t.', 'null', 'NULL', '', '']
    df = df.replace(null_values, np.nan)

    # Kolomnamen repareren
    df.columns = (df.columns
        .str.lower()
        .str.replace(r'[^a-z0-9]+', '_', regex=True)
        .str.strip('_'))

    return df
Enter fullscreen mode Exit fullscreen mode

Deze functie draaide op elke dataset. Nu handelt de export dat af.

Wanneer Wat Gebruiken

Scenario Beste Aanpak
Eenmalige analyse Browserexport → CSV → Pandas
Herhaald scrapen Python-script met requests
JavaScript-zware sites Browserexport (ziet gerenderde content)
Ingelogde data Browserexport (gebruikt je sessie)
API beschikbaar Gebruik de API rechtstreeks
Eenvoudige statische tabel pd.read_html() is prima

Pro Tip: JSON voor Complexe Data

Voor geneste of getypeerde data, exporteer als JSON:

import pandas as pd
import json

with open('export.json') as f:
    data = json.load(f)

df = pd.DataFrame(data)
Enter fullscreen mode Exit fullscreen mode

De JSON-export behoudt types:

  • Getallen als getallen (niet strings)
  • Booleans als booleans
  • Nulls als null
print(df.dtypes)
# player         object
# goals          int64   # Al numeriek!
# is_starter     bool    # Al boolean!
# injury_date    object  # Kan geparsed worden als datetime
Enter fullscreen mode Exit fullscreen mode

Zie voor meer details over JSON-workflows Webtabellen Exporteren naar JSON voor Python & Pandas.

De Workflow Samengevat

Oude workflow (30+ minuten):

  1. Scraping-script schrijven
  2. CORS/auth-problemen afhandelen
  3. Complexe HTML parsen
  4. Getallen opschonen
  5. Booleans opschonen
  6. Nulls opschonen
  7. Kolomnamen repareren
  8. Edge cases debuggen
  9. Eindelijk: analyseren

Nieuwe workflow (30 seconden):

  1. Klik extensie
  2. Exporteer met opschoonprofiel
  3. pd.read_csv()
  4. Analyseren

Probeer Het

  1. Installeer HTML Table Exporter
  2. Zoek een tabel die je wilt analyseren
  3. Exporteer met opschoonpresets
  4. Laad in Pandas

De gratis versie handelt basisexporten af. PRO voegt opschoonpresets en profielen toe voor Pandas-geoptimaliseerde output.

Meer informatie op gauchogrid.com/nl/html-table-exporter of probeer het in de Chrome Web Store.


Wat is jouw huidige workflow voor het laden van webdata in Pandas? Ik ben benieuwd hoeveel tijd je besteedt aan de opschoonstap. Laat een reactie achter.

Top comments (0)