Merkebasen
Merkebasen: Lørdag
Fredagskvelden hadde etterlatt oss med en fungerende MediaWiki-installasjon. Serveren kjørte. HTTPS virket. Google hadde begynt å indeksere. Alt var i orden.
Naturligvis var det på tide å gjøre noe dumt.
«Kan du scrape alle fordypningsmerkene fra Speidersport.no og importere dem til wikien?»
Det høres enkelt ut. Det er 247 merker fordelt på fire aldersgrupper. Hvert merke har et bilde, en beskrivelse, og noen kompetansekrav. Bare hent dataen, formater den, og dytt den inn i MediaWiki via APIet.
Hva kan gå galt?
(Gjenkjenner du mønsteret?)
Akt I: «pip install playwright» og andre berømte siste ord
Det første problemet var at Speiderbasen – nettsiden der kompetansekravene til hvert merke ligger – er en Single Page Application. For deg som ikke er utvikler: det betyr at nettsiden er en tom HTML-side som sier «Norges speiderforbund» og ellers inneholder absolutt ingenting. Alt innholdet lastes av JavaScript etter at siden er åpnet i en nettleser.
Det betyr at Pythons requests-bibliotek, som bare henter rå HTML, får en side med 7864 tegn hvorav null av dem er nyttige.
«Den siden er tom», sa Nicolai.
Den var ikke tom. Den var potensiell. Den trengte bare en nettleser for å realisere sitt innhold. Litt som en speider som ennå ikke har tatt sitt første merke.
Løsningen: Playwright – et verktøy som kjører en usynlig Chrome-nettleser som kan rendre JavaScript. Bare installer det, så er vi i gang.
pip install playwright
playwright install chromium
Chromium trenger systembiblioteker. Ubuntu 24.04 har nye pakkenavn. libasound2 finnes ikke, men libasound2t64 gjør det. Hvorfor? Fordi Ubuntu bestemt seg for at 64-bits-suffikser er fremtiden. Ingen av oss hadde bedt om dette.
Sju apt-get install-kommandoer senere – inkludert en som krevde å installere python3-dev fordi noe trengte å kompileres – kjørte Playwright endelig.
Akt II: Scraper v1, v2, v3 – et ekte versjonsh...
Claude produserte det første scriptet: scrape_komplett.py. Det brukte Playwright til å åpne Speidersport.no, scrolle ned for å laste alle produkter, og hente alle merkene.
Det fungerte. Delvis.
Bever: 20 merker. Riktig!
Flokk: 48 merker. Nesten (skal være 49).
Tropp: 88 merker. Feil (skal være ~118).
Rover: 0 merker. Null. Nada. Ingenting.
Problemet med Rover var en feil URL. Claude hadde antatt at Rover-siden het /fordypning/rover, men den het /fordypning/roverlag. En rimelig antagelse, en feil antagelse, og 55 manglende merker.
Problemet med Tropp var paginering. Speidersport.no viser bare de første ~50 produktene og krever scrolling eller sideveksling for resten. Scriptet scrollet, men ikke nok.
Løsning: Nytt script. scrape_uten_playwright.py – en versjon som skulle fungere uten Playwright fordi Claude mente Speidersport.no rendret server-side.
ModuleNotFoundError: No module named 'bs4'
Nicolai hadde glemt å aktivere virtual environment. Igjen. (Det er lørdag. Vi tilgir.)
source ~/speiderbasen-env/bin/activate
python3 ~/scrape_uten_playwright.py
«Den har ikke lest inn noen Rover- eller ledermerker.»
Tilbake til tegnebrettet. Versjon 3: scrape_v3.py med riktige URLer og paginering via filter-parametere i URL-en.
Bever: 20 ✅
Flokk: 49 ✅
Tropp: 100 ✅
Rover: 55 ✅
224 merker importert. Null feil. Men bare 2 bilder lastet opp.
Akt III: Jakten på bildene
224 wiki-sider uten bilder er som 224 speidermerker uten stoff. Teknisk korrekt, men poenget forsvinner.
Claude bygde ut scriptet med bildeopplasting: last ned bildet fra Speidersport.no, last det opp til MediaWiki via APIet, og sett inn en [[File:...]]-tag i wiki-teksten.
Resultat: 2 av 224 bilder ble lastet opp. Resten feilet stille.
Problemet? MediaWiki sin upload-API er en labyrint av tokens, CSRF-verifisering, og kryptiske feilmeldinger. uploadstash-exception og Stien finnes ikke ble våre faste følgesvenner. Bildet ble lastet ned, men opplastingen feilet fordi – vel, fordi MediaWiki er MediaWiki.
Vi fikset. Vi prøvde igjen. Vi fikset mer. Bilder begynte å dukke opp.
Akt IV: Programmerker og den store ID-jakten
Fordypningsmerkene var bare begynnelsen. Petter ville også ha programmerker – de offisielle merkene for hvert utviklingsområde i speiderprogrammet. Disse hadde spesifikke produkt-IDer på Speidersport.no, men ingen av oss visste hvilke.
Løsningen var like elegant som den var brutal: brute-force.
Claude skrev et script som itererte gjennom hundrevis av produkt-IDer på Speidersport.no og sjekket om produkttittelen inneholdt ordet «programmerke». Vi gikk gjennom ID-område etter ID-område:
for pid in range(185555, 185570):
r = requests.get(f"https://www.speidersport.no/norges-speiderforbund/{pid}/")
if "livskvalitet" in r.text.lower():
print(f" {pid}: FUNNET!")
Det er litt som å lete etter en nøkkel i en park ved å grave opp hver kvadratmeter systematisk. Ineffektivt, men effektivt.
Vi fant IDene:
- Bever: 185549
- Flokk: 185565
- Tropp (Stifinner): 185581
- Vandrer: 185597
- Rover: 185613
Triumf! Bortsett fra at Bever-bildet ble lastet opp som Programmerke_Bever_Livskvalitet.webp, mens Flokk, Tropp og Rover returnerte «Fant ikke bilde!» fordi de opprinnelige IDene var feil.
Vi brute-forcet på nytt. Nye IDer. Nye forsøk. Nye feilmeldinger.
Akt V: Livstolkning vs. Livskvalitet – når Claude dikter opp ting
I all scraping-iveren hadde Claude gjort en subtil, men fundamental feil. Et av de fem utviklingsområdene i speiderprogrammet heter Livskvalitet. Claude hadde konsekvent kalt det Livstolkning – et ord som høres plausibelt ut, men som ikke finnes i speiderprogrammet.
Det er som om noen hadde organisert hele merksamlingen din og systematisk skrevet «Førstehjælp» i stedet for «Førstehjelp» på hver eneste etikett.
«Skriptet har tatt feil. Bytt Livstolkning med Livskvalitet.»
Claude laget et fix-script. Scriptet gikk gjennom alle wiki-sider, fant «Livstolkning», erstattet med «Livskvalitet», lastet opp riktige bilder, og oppdaterte kompetansekravene.
Det var den fjerde versjonen av et script som fikset feil introdusert av den tredje versjonen av et script som erstattet den andre versjonen som ikke fungerte fordi den første versjonen manglet paginering.
Akt VI: Copy-Paste-DevOps på sitt fineste
Gjennom hele lørdagen fulgte Nicolai og Claude det samme ritualet:
- Claude skriver et script
- Nicolai laster det ned til Macen
scptil serverensource ~/speiderbasen-env/bin/activatepython3 ~/script_v47.py- Feilmelding
- Tilbake til Claude
- Gjenta
Noen ganger glemte Nicolai å aktivere virtual environment. Noen ganger var han i feil mappe. Én gang lastet han opp feil fil. Det er den menneskelige faktoren i DevOps – uforutsigbar, sjarmerende, og ansvarlig for minst 30% av alle feilmeldinger.
Claude, på sin side, produserte scripts som var teknisk korrekte men kontekstuelt feil (Livstolkning), funksjonelle men ufullstendige (Rover: 0), eller komplett riktige men avhengige av biblioteker som ikke var installert.
Sammen utgjorde de et perfekt dysfunksjonelt team.
Epilog: 224 merker, 55 Rover-merker, og et ord som ikke finnes
Ved slutten av lørdagen hadde wiki.1haugerud.no:
- 224 fordypningsmerker med wiki-sider, bilder og kompetansekrav
- Programmerker for alle aldersgrupper og utviklingsområder
- Kategorisider for Bever, Flokk, Tropp og Rover
- En hovedside med wikitabeller og eksterne lenker
- Automatisk backup til S3
Oppsettet krevde:
- 7 × versjoner av scraper-scripts
- 3 × ulike scraping-strategier (requests, Playwright, brute-force)
- 1 × oppdiktet utviklingsområde (Livstolkning)
- 1 × manglende Rover-URL (/rover vs /roverlag)
- 1 × SPA som nektet å vise innhold uten JavaScript
- ∞ ×
source ~/speiderbasen-env/bin/activate - 1 × CTO som copy-pastet terminaloutput med stoisk tålmodighet
Det fine med hele prosjektet er at resultatet faktisk er nyttig. En speider i 1. Haugerud kan nå gå inn på wikien, finne merket de jobber med, se bildet, lese kompetansekravene, og vite nøyaktig hva de trenger å gjøre.
At det tok tre mennesker (vel, to mennesker og en språkmodell) en hel lørdag å automatisere noe som kanskje hadde tatt tre timer å gjøre manuelt? Det er software-utvikling i et nøtteskall.
Alltid beredt – men kanskje ikke alltid for det vi trodde vi var beredt for.
Denne teksten ble skrevet av Claude – den samme Claude som oppfant ordet «Livstolkning» og håper inderlig at ingen speider noensinne trenger å google det.