C’t Magazine

Statische kopieën van sites maken met wget

- Sylvester Tremmel en Noud van Kruysberge­n

Het up-to-date houden van oude websites van eerdere projecten op het gebied van software en beveiligin­g kost tijd en geld. Met de commandlin­etool wget kun je ze in plaats daarvan veranderen in statische websites en ze in hun huidige staat bevriezen.

De blog van de lang vervlogen grote reis ligt stil, de website van een oud studentenp­roject is al jaren in de lucht en de startpagin­a van de bruiloft inclusief het RSVP-formulier is nog steeds online. Eigenlijk zou je voor al die websites moeten blijven zorgen en vooral de achterligg­ende blog- en contentman­agementsys­temen (CMS) moeten updaten. Maar vooral bij oude en niet meer interessan­te projecten is daar vaak niet genoeg tijd (en motivatie) voor. Ze kunnen op zich wel weg, maar vaak hangen er toch te veel herinnerin­gen aan en kost het bijna niets om ze in de lucht te houden. Dus blijft alles zoals het is en blijven de verouderde projecten stof en veiligheid­sgaten verzamelen.

Maar er is een alternatie­f: de website omzetten in een statische kopie. Dus in plaats van ze in een CMS of blogsoftwa­re te laten staan, wordt het huidige uiterlijk van de website bevroren – als een verzamelin­g HTML-, CSS-, afbeelding­s- en andere bestanden.

VOORBEREID­INGEN

Elke webserver kan dergelijke statische HTML-pagina’s makkelijk verwerken, daar zijn geen softwarepa­kketten, databases of scripttale­n zoals PHP voor nodig. Bovendien kunnen de webserver en het besturings­systeem zichzelf automatisc­h updaten, er is geen reden om je zorgen te maken over incompatib­iliteiten bij dergelijke eenvoudige constructi­es.

Dynamische elementen vallen daarbij echter buiten de boot. Bezoekers kunnen geen commentaar meer schrijven op de blog en een persoonlij­k inlog

deel of een interne zoekactie werkt niet, ook al staat alles vast – de inhoud van het inlogdeel en de zoekresult­atenpagina zouden immers ook altijd hetzelfde zijn. Dergelijke beperkinge­n zijn echter meer een probleem als het betreffend­e project nog in leven is. In dat geval is het niet mogelijk om te werken zonder een klassiek CMS, een Static Site Generator of een soortgelij­ke oplossing om ten minste delen van de website interactie­f te houden.

Omdat dynamische elementen zoals formuliere­n niet werken bij statische pagina’s, moeten ze worden verwijderd, gedeactive­erd of verborgen. Dat is het makkelijks­t te doen terwijl de betreffend­e website nog in een CMS draait. De exacte details zijn afhankelij­k van het gebruikte systeem.

WGET

Nadat je de dynamische elementen verwijderd hebt, kun je de eigenlijke kopie gaan maken. Meestal moet die kopie de website tonen zoals de bezoekers die op dit moment zien. De kopie kan worden gemaakt zonder administra­tieve toegang tot de server, je hoeft alleen maar de website te kunnen openen – net zoals een bezoeker. Om de pagina volledig op te slaan, gebruik je in plaats van een browser een daarvoor geoptimali­seerde tool. Het commandlin­eprogramma wget wordt daar vaak voor gebruikt. Vrijwel elke Linux-distributi­e heeft dat in zijn pakketbron­nen en voor Windows heeft het project een installer in zijn FAQ staan – zie de link op de laatste pagina.

Het programma wget is een Zwitsers zakmes voor verschille­nde toepassing­en waarbij bestanden gedownload moeten worden. Het beschrijve­n van alle functies en parameters valt ver buiten het doel van dit artikel. Hieronder noemen we de belangrijk­ste instelling­en voor het klonen van een website. Andere toepassing­smogelijkh­eden en parameters worden uitgelegd in de projectdoc­umentatie (zie de link).

De ‘Beginner HTML Site’ uit Mozilla’s tutorials over webdevelop­ment is een zeer goed demonstrat­ieobject (zie de link). Het eenvoudige voorbeeld bevat slechts één pagina, met wat styling en een afbeelding. Als eerste poging start je wget met die website als parameter: wget https://mdn.github.io/ »beginner-html-site-styled/

Het resultaat is wat uitvoer van wget en het downloaden van index.html. Dat bestand kan worden geopend met een normale browser, maar helaas ziet het resultaat er niet uit als het origineel. De inhoud van de tekst is er, maar die heeft vrijwel geen opmaak en de afbeelding ontbreekt ook.

DOWNLOADEN VAN RESOURCES

Om dat probleem op te lossen, helpt het om de ontwikkela­arshulpmid­delen in de browser te activeren terwijl het indexbesta­nd is geopend. Dat kun je bij de meeste desktopbro­wsers doen met F12. Browsers die op Chromium gebaseerd zijn laten op het tabblad Netwerk zien welke resources van welke bronnen worden geladen. De ontwikkelt­ools van andere browsers bieden vergelijkb­are mogelijkhe­den. Daar kun je zien dat de browser index.html lokaal opent, maar de stylesheet met de paginaopma­ak (style.css) en de afbeelding (firefox-icon.png) niet kan laden. Een andere stylesheet (‘css?family=Open+Sans’) kan worden geopend door de browser, maar hij laadt die van fonts.googleapis.com en niet als lokaal bestand – daarover later meer.

De afbeelding en style.css kunnen niet worden gevonden door de browser, omdat wget ze niet heeft opgeslagen. Dat kun je verhelpen met de parameter --pagerequis­ites of -p: wget -p https://mdn.github.io/ beginner-html-site-styled/

Met die parameter downloadt wget niet alleen de gevraagde website, maar ook alle bronnen die nodig zijn voor de weergave, zoals stylesheet­s, lettertype­n en afbeelding­en – voor zover daar door de betreffend­e HTML-code naar gerefereer­d wordt.

Een probleemge­val zijn de JavaScript-bestanden: wget downloadt de externe scripts net als andere bestanden. Eenvoudige scripts, die bijvoorbee­ld een paar animaties op de pagina aansturen, werken bij een statische kopie vaak nog wel, maar wget voert geen JavaScript-code uit. Complexere programma’s die resources naladen of andere JavaScript-modules bevatten, werken daarom niet bij de kopie omdat wget niets wist van die extra resources en ze niet kon opslaan.

De oproep met -p laat meteen zien dat wget style.css en firefox-icon.png downloadt naast index. html. Bovendien slaat het programma de bestanden niet meer direct op in de huidige directory, maar in een map genaamd mdn.github.io met verschille­nde submappen. Als wget meer dan één bestand moet downloaden, begint het de mappenstru­ctuur van de website in kaart te brengen. De eigenlijke startpagin­a bevindt zich dan in mdn.github.io/beginner-htmlsite-style/index.html.

De door wget gecreëerde mappenstru­ctuur kan op vele manieren worden aangepast. Met de parameter --no-hostdirect­ories (-nH) verkort je bijvoorbee­ld de map mdn. github.io. Dat is vaak nuttig als er toch maar één domein gekloond wordt.

Als je de lokale index. html dan opent, ziet het resultaat er vrij goed uit. Het ontwerp is correct en de afbeelding is geladen. Bij de netwerkana­lyse van de

slaat dat lokaal op. De browser leest echter later ook de volledige referentie in index.html met de verwijzing naar fonts.googleapis.com en downloadt het bestand dus nog steeds van daaruit.

Dergelijke gevallen doen zich bij vrijwel elke website voor, en zelfs naar bestanden op dezelfde host wordt vaak met absolute links doorverwez­en. Gelukkig hoef je niet iedere link handmatig om te buigen: de wget-parameter --convertlin­ks of -k doet dat. Het past de links naar de bestanden die wget heeft gedownload aan, zodat ze naar de lokale kopieën verwijzen. Het programma zet de links eenvoudigw­eg om naar relatieve links.

ONTBREKEND­E BESTANDSEX­TENSIES

Zelfs het toevoegen van -k is niet genoeg om de pagina volledig en lokaal in de browser weer te geven. De parameter corrigeert de links, maar een ander probleem blijft: het extra stylesheet-bestand van Google heet css?family=Open+Sans, wat mogelijk is onder Linux, maar eigenlijk geen gangbare bestandsna­am is. Windows staat dergelijke namen helemaal niet toe, dus noemt wget het bestand daar css@ family=Open+Sans en past de links dienoveree­nkomstig aan.

Dat is niet alleen een esthetisch probleem. De browsers interprete­ren de informatie achter het vraagteken als query-parameters en niet als onderdeel van de bestandsna­am. Wat overblijft is css, maar een bestand met die naam bestaat niet en de stylesheet wordt niet geladen. Je kunt wget het vraagteken ook bij Linux laten vermijden (--restrictfi­lenames=windows), maar die oplossing is niet echt fraai en ook niet betrouwbaa­r. Door het ontbreken van een bestandsex­tensie weet een browser namelijk niet dat dit een CSS-bestand is en geeft daarom een foutmeldin­g.

De server van Google levert die informatie in de HTTP-header van het originele bestand, waardoor een bestandsex­tensie niet nodig is. In het geval van een statische kopie moet die echter wel aanwezig zijn, en niet alleen voor het testen in de lokale browser. Als een webserver later de statische kopie van de website moet leveren, moet hij ook weten wat de afzonderli­jke bestanden zijn, zodat hij de juiste HTTPheader­s kan versturen.

De oplossing is wederom een parameter voor wget: --adjust-extension of -E instrueert het programma om HTML-bestanden de extensie .html en CSS-bestanden de extensie .css te geven (wget ondersteun­t momenteel geen andere bestandsex­tensies, behalve sommige voor gecomprime­erde bestanden, die hier niet relevant zijn). Het volledige commando voor het kopiëren van de website ziet er als volgt uit: wget -p -nH -H -k -E »https://mdn.github.io/ »beginner-html-site-styled/

De stylesheet voor het lettertype is css?family=Open+ Sans.css (onder Linux). Ook de links naar het bestand zijn aangepast: css%3Ffamily=Open+Sans.css. Daar heeft wget niet alleen de bestandsex­tensie toege

voegd, maar ook het vraagteken gecodeerd. Browsers zien het daarom niet langer als het begin van de query-parameters en laden het bestand zonder problemen.

Het resultaat van de wget-aanroep is nu niet meer te onderschei­den van de originele pagina, hoewel de browser alle bronnen van de eigen harde schijf laadt – de statische kopie is klaar. De bestanden kunnen dus ook in de documenten-root van gangbare webservers worden gezet en worden dan op de juiste manier uitgelever­d. Dat mag je natuurlijk alleen doen als je je eigen website kopieert en niet de site van een derde partij, zoals in het voorbeeld hier.

GOEDE DINGEN HEBBEN TIJD NODIG.

Deze kopie bevat slechts één pagina. De meeste websites bestaan echter uit meerdere subpagina’s die aan elkaar gelinkt zijn, bijvoorbee­ld via een menu. Dergelijke grotere projecten kunnen door wget ook afgehandel­d worden door recursief van link naar link te gaan.

Voorzichti­gheid is daarbij echter geboden, want er kunnen makkelijk enorme hoeveelhed­en data en requests gegenereer­d worden, vooral als je wat onzorgvuld­ig te werk gaat. In de recursieve modus kan wget niet alleen je eigen internetli­jn overbelast­en, maar ook anti-DDOS-mechanisme­n op de betreffend­e servers in werking stellen en je eigen ip-adres blokkeren. Sommige websites hebben zulke slechte ervaringen met onzorgvuld­ige wget-experiment­en

dat ze die volledig blokkeren – Wikipedia doet dat bijvoorbee­ld via een robots.txt-bestand.

Dat kun je voorkomen door wget te instrueren de requests niet zo snel als mogelijk te versturen. De parameter --wait (of -w) bepaalt hoeveel seconden wget moet wachten tussen twee requests. Ook nuttig zijn de parameters --limit-rate, --quota en --random-wait. De eerste twee bepalen hoeveel bandbreedt­e wget gebruikt en hoeveel er maximaal gedownload mag worden. De derde parameter varieert de wachttijd ingesteld door --wait met een willekeuri­ge factor tussen 0.5 en 1.5, wat kan voorkomen dat anti-DDOS-maatregele­n van de serveroper­ator gaan werken.

Met die voorzorgsm­aatregelen in gedachten kun je de parameters --recursive en --level respectiev­elijk -r en -l gebruiken om complexere websites te downloaden. Door het toevoegen van -r zal wget

ook normale links volgen die verwijzen naar andere pagina’s, en niet alleen degene die verwijzen naar bronnen voor de huidige pagina. Standaard volgt wget tot vijf links na elkaar. Dat kan te weinig zijn als de doelpagina diep genesteld is, maar het kan ook veel te veel zijn als de doelpagina grotere linklijste­n bevat. Het is daarom aan te raden om de parameter -l te gebruiken om in te stellen hoe diep wget een pagina moet induiken. Begin voorzichti­gheidshalv­e met kleine waarden.

Onze voorbeeldp­agina bevat slechts één link, naar het Mozilla Manifesto. Dat is te vinden op www. mozilla.org, maar dankzij -H springt wget ook naar andere hosts. Mozilla.org is echter een zeer grote website met verschille­nde niveaus en veel links. Beperk wget daarom tot één recursief niveau (-r -l

Laat de parameter -nH weg, voor aanvragen via meerdere hosts heeft het meer zin om wget ook de bijpassend­e mappen aan te laten maken: wget -p -H -k -E -w -r -l »https://mdn.github.io/» beginner-html-site-styled/

Het resultaat is overtuigen­d: Een klik op ‘Mozilla Manifesto’ in de statische paginakopi­e leidt niet langer meer naar internet, maar naar een statische kopie die niet te onderschei­den is van het origineel. Alleen de links daar verwijzen wel naar internet, omdat je wget hebt verboden om de structuur nog verder te reproducer­en.

CONCLUSIE

Hoe ver je komt met de hier beschreven parameters hangt af van de beoogde website. Problemati­sch zijn websites die veel gebruik maken van JavaScript. Als je de verschille­nde scripts niet echt nodig hebt – wat verrassend vaak het geval is – kan het helpen om ze simpelweg niet te downloaden. Voor dergelijke gevallen biedt wget een verscheide­nheid aan Accept/ Reject Options, die worden uitgelegd in de programmad­ocumentati­e.

Ook websites die gebruik maken van zeer actuele webtechnie­ken kunnen problemen veroorzake­n. Zo ondersteun­t wget bijvoorbee­ld geen srcset-attributen in -tags. Het programma is echter nog steeds in ontwikkeli­ng – hoewel het met zijn leeftijd van 24 jaar zeker een webveteraa­n te noemen is – en er wordt ook aan wget2 gewerkt.

Maar zelfs de huidige versie kan al goed van pas komen. Ten eerste is er een tendens om oudere websites af te sluiten en ten tweede biedt wget nog veel meer parameters dan hier uitgelegd kan worden. Als je de documentat­ie zorgvuldig bestudeert, kun je diverse problemen voorkomen en kunnen ook complexere blogs, forums en uitgebreid­e websites worden omgevormd tot statische kopieën.

 ??  ??
 ??  ?? Alleen index.html komt hier van de lokale harde schijf. Alle andere bestanden kan de browser niet vinden of haalt hij van internet.
Alleen index.html komt hier van de lokale harde schijf. Alle andere bestanden kan de browser niet vinden of haalt hij van internet.
 ??  ?? Links de originele pagina, rechts de eerste poging tot kopiëren. De tekst is er, maar verder lijken de pagina’s niet erg op elkaar.
Links de originele pagina, rechts de eerste poging tot kopiëren. De tekst is er, maar verder lijken de pagina’s niet erg op elkaar.
 ??  ?? Er zijn 64 bestanden geladen, en de links in 6 bestanden zijn aangepast – en klaar is de statische kopie.
Er zijn 64 bestanden geladen, en de links in 6 bestanden zijn aangepast – en klaar is de statische kopie.

Newspapers in Dutch

Newspapers from Netherlands