Så bygger du en Python-scraper som överlever att sidan görs om
- En selektor på `div.price-tag` slutar fungera i tysthet
- Sex steg från rå HTML till strukturerad data
- Läs robots.txt innan du skriver första raden
- AI-fallback på två procent av sidorna är knappt märkbart
- Fem procent fel är normalt, planera för det
- FAQ
- Behöver jag Playwright eller räcker requests?
- Är det lagligt att skrapa svenska webbplatser?
- Hur mycket kostar AI-fallbacken i praktiken?
- Kan jag använda en lokal modell i stället?
En scraper går sönder när HTML-strukturen ändras. Lösningen är att sluta lita på CSS-selektorer som enda strategi och i stället låta en språkmodell tolka innehållet när selektorerna missar. Grundmönstret: hämta sidan med `requests`, försök med `BeautifulSoup` först och skicka bara vidare till en modell när det snabba spåret misslyckas. Då kostar det nästan ingenting i normalfallet och du slipper skriva om koden varje gång någon byter CSS-klass.
En selektor på `div.price-tag` slutar fungera i tysthet
Det klassiska problemet med `soup.select_one(”div.price-tag”)` är inte att den kraschar. Den returnerar `None` och om du inte hanterar det får du en tom sträng i databasen som ser ut som ett giltigt värde. Sidan har gjorts om, klassen heter numera `div.product-price__value` och din pipeline har samlat tomma rader i tre veckor.
Samma sak händer med formuleringar. En sida skriver ”Leveranstid: 2-4 dagar”, en annan ”Skickas inom 2 till 4 arbetsdagar”. Ska du täcka båda med reguljära uttryck får du snabbt ett regex ingen vill underhålla.
Här gör en språkmodell något som regex inte kan: den läser texten och förstår att båda meningarna beskriver samma sak. Skickar du in rå text och ber om strukturerad JSON tillbaka spelar det mindre roll hur meningen är formulerad.
Sex steg från rå HTML till strukturerad data
Ordningen spelar roll. Varje steg minskar mängden data som behöver skickas vidare och det billigaste steget kommer först.
- Hämta sidan och sätt en vettig User-Agent. `requests.get(url, headers={”User-Agent”: ”…”}, timeout=10)`. Utan timeout hänger ditt skript för evigt på en långsam server. Sätt också en paus mellan anropen, en sekund räcker oftast.
- Kontrollera att du får HTML och inte JavaScript. Innehåller svaret bara en tom `
` renderas sidan i webbläsaren. Då behöver du Playwright i stället för `requests` och det kostar sekunder per sida i stället för millisekunder.
- Försök med selektorer först. Skriv dina `BeautifulSoup`-anrop som vanligt men kolla returvärdet. Får du `None` på ett fält som borde finnas, markera raden som osäker i stället för att spara tomt.
- Rensa bort allt som inte är innehåll. `for tag in soup([”script”, ”style”, ”nav”, ”footer”, ”svg”]): tag.decompose()` tar bort en stor del av volymen. Sedan `soup.get_text(separator=”\n”, strip=True)`. En produktsida på 400 kB HTML krymper ofta till några kilobyte text. Det här steget är det som gör AI-spåret ekonomiskt försvarbart, eftersom du betalar per token.
- Skicka texten till modellen med ett schema. Be inte om ”informationen på sidan”. Be om exakt fält: `{”produktnamn”: str, ”pris_sek”: float eller null, ”i_lager”: bool}`. Både OpenAI och Anthropic stödjer strukturerad output som garanterar giltig JSON tillbaka. Instruera explicit att fältet ska vara `null` när uppgiften saknas, annars gissar modellen.
- Validera resultatet innan du sparar. Använd Pydantic. Ett pris på 4 500 000 kronor för en t-shirt betyder att modellen läst fel fält och den kontrollen kostar dig tre rader kod. Loggar du dessutom vilka sidor som gick via AI-spåret ser du direkt när en webbplats har gjorts om.
Läs robots.txt innan du skriver första raden
Att en sida är publik betyder inte att du får skrapa den systematiskt. Kolla `robots.txt`, läs användarvillkoren och håll nere frekvensen så att du inte belastar någon annans server. Python har `urllib.robotparser` i standardbiblioteket, så det är inget merarbete. Skrapar du personuppgifter gäller GDPR fullt ut, oavsett att uppgifterna låg öppet på webben.
Att bygga en databas över namn och kontaktuppgifter från svenska sajter är en personuppgiftsbehandling som kräver rättslig grund. Vissa myndigheter erbjuder API:er i stället, PTS nummertjänster är ett exempel där du kan slå upp operatörsinformation utan att skrapa något alls. Leta alltid efter API:et först.
AI-fallback på två procent av sidorna är knappt märkbart
Ett anrop till en språkmodell tar mellan en och fem sekunder. En `BeautifulSoup`-selektor tar mikrosekunder. Skillnaden är sex tiopotenser och den avgör hur du bör tänka.
Kör du AI på varje sida i en lista med 10 000 URL:er får du timmar av väntetid och en räkning du inte hade budgeterat för. Kör du det som fallback på de två procent som failar blir det knappt märkbart. Ett annat sätt att komma runt kostnaden: låt modellen generera selektorn i stället för att extrahera datan. Skicka in ett HTML-utdrag en gång, be om ett CSS-uttryck tillbaka, cacha det per domän och kör vanlig `BeautifulSoup` på resten av sidorna. Går selektorn sönder genererar du en ny.
Vilken modell du väljer spelar mindre roll än man tror för den här typen av uppgift. Extraktion från text är inte särskilt krävande. En liten och billig modell klarar det oftast lika bra som en stor och skillnaden i latens märks direkt när du kör tusentals anrop. Tester av olika modellers kodningsförmåga säger heller inte så mycket om hur bra de är på att plocka ut ett pris ur en textmassa.
Håll också isär två saker som lätt blandas ihop: en scraper med AI-fallback är fortfarande deterministisk kod med ett undantagsspår. Den är inte en agent som planerar och agerar i en loop. Skillnaden är att du vet exakt vad din scraper kommer att göra och det är en egenskap värd att behålla.
Fem procent fel är normalt, planera för det
Modellen kommer att hitta på saker. Den läser ”ord. pris 899 kr” och rapporterar 899 som aktuellt pris trots att det står överstruket. Den tolkar ”från 1 295 kr” som ett exakt pris. Den missar att sidan visar priser exklusive moms.
Bygg därför in stickprov. Plocka ut trettio slumpade rader ur varje körning och jämför mot sidan manuellt. Hittar du fel i mer än ett par av dem behöver prompten skärpas eller fältet definieras tydligare. Att lägga in `”pris_inkl_moms”: bool` i schemat löser förvånansvärt många tolkningsproblem, helt enkelt för att modellen tvingas ta ställning.
Spara alltid den råa HTML:en du skrapade, komprimerad. När du upptäcker ett systematiskt fel om två månader kan du köra om extraktionen på befintlig data i stället för att skrapa allt igen.
FAQ
Behöver jag Playwright eller räcker requests?
Kolla om datan finns i HTML-svaret genom att söka efter ett känt värde i `response.text`. Finns det där räcker `requests`. Saknas det renderas sidan med JavaScript och du behöver Playwright eller så letar du efter det underliggande API-anropet i webbläsarens nätverksflik, vilket ofta ger renare data direkt.
Är det lagligt att skrapa svenska webbplatser?
Det beror på vad du hämtar och hur. Publik faktainformation i rimlig takt är sällan ett problem men personuppgifter omfattas av GDPR även när de ligger öppet och webbplatsens användarvillkor kan förbjuda automatiserad insamling. Kolla robots.txt, läs villkoren och fråga dig om det finns ett API i stället.
Hur mycket kostar AI-fallbacken i praktiken?
Efter att du rensat bort script, style och navigation landar en typisk produktsida på några tusen tokens. Med fallback på ett par procent av sidorna handlar det om ören per tusen skrapade sidor med en mindre modell. Kör du AI på varenda sida blir det däremot en faktura du märker av.
Kan jag använda en lokal modell i stället?
Ja och för ren textextraktion fungerar det ofta bra. En modell i storleksordningen 7-8 miljarder parametrar klarar strukturerad JSON-output om du är tydlig med schemat. Fördelen är att ingen data lämnar din maskin, nackdelen är att du behöver hårdvaran och att svarstiden sällan blir bättre än ett API-anrop.
Källor
- PTS nummertjänster nummer.pts.se
