# Återuppliva min gamla blogg med Archive.org och en hel del C#

<!--category-- Imported, .NET, Archive.org -->
<datetime class="hidden">2025-11-24T12:00</datetime>

Så du kanske har märkt hundratals av ["nya" blogginlägg](https://www.mostlylucid.net/blog/category/Imported) visas nyligen. Tja, de är inte nya alls - de är OLD. Som, 2004 gammal. Jag byggde äntligen ett verktyg för att rädda mitt innehåll från den digitala kyrkogården som var min gamla blogg på mestadels lucid.co.uk.

## Varför Archive.org är helt lysande

Innan jag dyker in i de tekniska grejerna, måste jag ge en massiv ropa ut till [Internetarkiv](https://archive.org/) och deras Wayback Machine. Denna ideella organisation har i tysthet arkiverat webben sedan 1996, bevara miljarder webbsidor som annars skulle gå förlorade för alltid.

Tänk på det för en sekund. Varje blogginlägg du skrev 2005, varje GeoCities sida, varje MySpace profil - det finns en anständig chans att det fortfarande är tillgänglig via Archive.org. De driver i huvudsak ett museum över hela internet, finansieras av donationer och bidrag.

När min gamla hosting leverantör försvann (tillsammans med mina säkerhetskopior eftersom jag var SMART som det), trodde jag att allt detta innehåll var borta för alltid. Visar sig Wayback Machine hade flitigt ögonblicksbilda min webbplats i år. Archive.org ganska bokstavligen sparat 6+ år av min blogg historia.

Om du aldrig har donerat till dem, överväga att göra det. De bevarar vår kollektiva digitala historia.

## Problemet: Min blogg var en röra

Så här är det med att köra en blogg från 2004 till 2010 - webbteknik förändrade en LOT under den tiden. Och tydligen, Jag ändrade min blogging setup minst tre gånger:

1. **Tidiga dagar (2004)**: Någon homebrew ASP.NET sak med innehåll inlindad i `<div class="post">` på insidan av en `<form>` element (eftersom allt var en form då)
2. **Medeltidsperiod**: Olika mallstruktur, datum på olika platser
3. **Senare år**: Ytterligare en omstrukturering med något olika valörer

Från minnet använde den något anpassat då [Undertext](http://beletsky.net/2010/09/subtext-open-source-blogging-engine.html) (Phil Haacks bloggande grej). Följt av Community Server (a) [Telligentt Ordförande](https://community.telligent.com/) sak ASP.NET brukade använda för att vara värd webbplatser, av ANother ex ASP,NET PM Rob Howard) . Alla hade olika sätt att uppdatera och olika sätt att visa innehåll.

Detta innebar att alla extraktionsverktyg behövde vara flexibla nog att hantera flera HTML-strukturer. En "en storlek passar alla" skrapmaskin skulle inte skära det.

## Skriv in arkivetOrgImporter@ info: whatsthis

Jag byggde [ArkivOrgImporterare](https://github.com/scottgal/mostlylucid.nugetpackages/tree/main/Mostlylucid.ArchiveOrg) för att lösa detta mycket specifika problem. Det är en .NET 9.0 konsol program som:

1. **Respekt Archive.orgs användningsgränser** - De är ideella med donationer, så det vore hemskt att hamra deras servrar.
2. **Nerladdningar arkiverade sidor mellan konfigurerbara datum**
3. **Extraherar blogginnehåll från flera HTML-strukturer**
4. **Genererar ren markering** i mitt nuvarande bloggformat
5. **Använder Ollama för att generera användbara taggar** - Varför inte kasta lite LLM-magi på den?

### Hur den fungerar

Verktyget följer en rörledningsarkitektur med tre huvudfaser:

```
Archive.org CDX API → Download HTML → Convert to Markdown → Generate Tags → Output Files
```

#### Fas 1: Fråga på arkivet

Verktyget använder Archive.org's [CDX- API](https://github.com/internetarchive/wayback/tree/master/wayback-cdx-server) för att hitta alla arkiverade ögonblicksbilder av min blogg. API:et returnerar en lista med fångade webbadresser med tidsstämplar, MIME- typer och HTTP- statuskoder.

```csharp
// The CDX query builds a URL like this:
// https://web.archive.org/cdx/search/cdx?url=mostlylucid.co.uk/posts/&output=json&collapse=urlkey
```

och `collapse=urlkey` parameter är smart - det returnerar bara den senaste ögonblicksbilden för varje unik URL, vilket dramatiskt minskar antalet dubbletter du behöver ta itu med.

Jag använder också regex mönster för att filtrera webbadresser. Mina gamla inlägg följde mönstret `/posts/[number].aspx`, så:

```json
{
  "IncludePatterns": ["/posts/\\d+\\.aspx$"]
}
```

På så sätt tar jag bara riktiga blogginlägg, inte arkivsidor, kategorisidor eller RSS-flöden.

#### Fas 2: Att vara en god medborgare med prisbegränsning

Archive.org är en offentlig tjänst. De har inte infrastruktur budgeten för Google eller Amazon. Så downloader är medvetet konservativ:

```csharp
// Default: 5 seconds between requests, single-threaded downloads
"RateLimitMs": 5000,
"MaxConcurrentDownloads": 1
```

Ja, detta innebär att ladda ner hundratals inlägg tar ett tag. Men det är det rätta att göra. Verktyget hanterar också 429 (frekvensgräns) svar graciöst med exponentiell backoff.

Det finns också en del städning som behövs för nerladdade filer. Archive.org lägger till verktygsradsskript och skriver om webbadresser i den fångade HTML. Downloader tar bort allt:

```csharp
private static string CleanWaybackArtifacts(string html)
{
    // Remove the interactive Wayback toolbar
    html = WaybackToolbarRegex().Replace(html, string.Empty);
    // Remove playback.archive.org script references
    html = WaybackScriptRegex().Replace(html, string.Empty);
    // Strip archival metadata comments
    html = WaybackCommentRegex().Replace(html, string.Empty);
    // Rewrite archived URLs back to original paths
    html = WaybackUrlRewriteRegex().Replace(html, "$1$2");
    return html;
}
```

Regex-mönstren hanterar:

- `<!-- BEGIN WAYBACK TOOLBAR INSERT -->...<!-- END WAYBACK TOOLBAR INSERT -->` - verktygsradens HTML
- `<script>` taggar hänvisning `playback.archive.org`
- Arkivmetadatakommentarer
- Webbadressprefix som `https://web.archive.org/web/20040527/` som blir förberedd på alla länkar

#### Fas 3: Mardrömmen för innehållsextraktion

Det är här det blir intressant. Kommer du ihåg att jag nämnde min blogg ändrade struktur tre gånger? Så här hanterade jag det.

Den primära extraktionen använder en CSS-väljare:

```json
{
  "ContentSelector": "div.post"
}
```

Men här är en rolig sak - i vissa versioner av min gamla webbplats, `div.post` Ingen känd frekvens: `<form>` Koden måste extrahera innehåll INNAN oönskade element tas bort, annars tar bort `<form>` Tags skulle nuke den faktiska bloggen innehåll:

```csharp
// In ConvertFileAsync - the order here is critical
var contentNode = ExtractMainContent(doc);
if (contentNode == null)
{
    _logger.LogWarning("Could not find main content in {File}", htmlFilePath);
    return articles;
}

// NOW we can safely remove unwanted elements from within the extracted content
RemoveUnwantedElementsFromNode(contentNode);
```

och `ExtractMainContent` metod använder en hierarkisk sökning för att hitta innehållet:

```csharp
// For selectors like "div.post", split and search by element + class
node = doc.DocumentNode.Descendants()
    .FirstOrDefault(n =>
        n.Name.Equals(elementName, StringComparison.OrdinalIgnoreCase) &&
        HasExactClass(n, className));
```

Verktyget har också reservväljare om den primära misslyckas:

1. `div.blogpost`, `div.singlepost`, `article`
2. `#content`, `#main-content`, `#PostBody`
3. `.post-content`, `.entry-content`, `.article-content`
4. Slutligen, bara `<body>` om allt annat misslyckas

Sedan finns det en lång lista med element att ta bort efter innehållsextraktion:

```json
{
  "RemoveSelectors": [
    "nav", "header", "footer", ".sidebar", ".advertisement",
    ".comments", ".social-share", ".related-posts", "script",
    "style", "noscript", "iframe", "#commentform", ".postNav"
  ]
}
```

#### Fas 4: Produktion av markeringar

När vi har rent HTML-innehåll, [Omvänd markering](https://github.com/mysticmind/reversemarkdown-net) hanterar den tunga lyft av konvertera den till GitHub-flavored Markdown.

Men utmatningen behövde en del efterbehandling. Gamla HTML hade ofta konstig indentering som skulle förvirra Markdown-tolkar (indenterade rader blir kodblock!). Så det finns upprensning:

```csharp
// Removes leading whitespace from non-code lines
// Preserves code block formatting (respects ``` fences)
// Removes excessive blank lines (max 2 consecutive)
```

Den slutliga utmatningen inkluderar min bloggs front mater format:

```markdown
# Article Title

<datetime class="hidden">2004-05-27T23:21</datetime>
<!--category-- mostlylucidcouk, Imported, SomeCategory -->

Article content here...
```

#### Fas 5: LLM-kraftig tagggenerering

Nu för den roliga delen. Gamla blogginlägg hade ofta inga taggar alls, eller taggar som inte gjorde vettigt för min nuvarande webbplats struktur. Så jag integrerade Ollama för att analysera innehåll och generera relevanta taggar.

Konfigurationen är enkel:

```json
{
  "Ollama": {
    "BaseUrl": "http://localhost:11434",
    "Model": "gemma3:4b",
    "Temperature": 0.3,
    "MaxTags": 5,
    "Enabled": true
  }
}
```

Jag använder `gemma3:4b` Eftersom den är snabb och liten nog att köra lokalt utan mycket väsen. Låg temperatur (0.3) håller resultatet konsekvent – vi vill inte ha kreativa hallucinationer i våra taggar. Observera; för min blogg fungerade detta som inläggen var korta, om din är längre se till att titta på bitning och summering tekniker för att passa i din modells sammanhangsfönster.

##### Hantering av längre inlägg

Här är en praktisk begränsning: LLMs har sammanhangsfönster, och att pumpa in ett helt blogginlägg i dem för tagggenerering är slöseri. Verktyget trunkerar innehåll till 3000 tecken:

```csharp
var truncatedContent = content.Length > 3000
    ? content[..3000] + "..."
    : content;
```

För tagggenerering, de första 3000 tecken innehåller vanligtvis tillräckligt med sammanhang för att förstå vad inlägget handlar om. Prompten instruerar modellen att fokusera på tech-specifika kategorier:

```
Generate up to 5 tags, short (1-3 words), focusing on:
.NET, C#, ASP.NET, JavaScript, Docker, Database, API, Security, DevOps, Cloud
```

Svarstolkningen är defensiv – om Ollama returnerar skräp eller tider ut, får vi bara en tom lista istället för att krascha hela rörledningen.

### Datumutdrag: En strategi för flera strategier

Att hitta det ursprungliga publiceringsdatumet är förvånansvärt knepigt. Min gamla blogg lagrade datum på olika platser under åren. Verktyget försöker flera strategier:

1. **Anpassad väljare** (t.ex. `.postfoot`)
2. **Metataggar**: `article:published_time`, `DC.date.issued`
3. **HTML5 Ordförande `<time>` grundämnen**
4. **Försäkringstekniska avsättningar – försäkringstekniska avsättningar beräknade som helhet (efter återförsäkring/specialföretag) – Bästa skattning och försäkringstekniska avsättningar beräknade som helhet (efter återförsäkring/specialföretag)**: `.date`, `.post-date`, `.entry-date`
5. **Regexmönster** på obehandlad HTML (ISO-format, slash-separerad, etc.)
6. **Tillbaka**: Själva arkivets ögonblicksbildsdatum

En särskilt irriterande format var min gamla blogg mall är "posted on torsdag 27 maj 2004 11:21" sträng. Det finns specifik tolkning för det.

### Pipelineorkestern

Den coolaste arkitektoniska biten är hur nedladdning och konvertering körs parallellt med .NET Kanaler:

```csharp
var channel = Channel.CreateBounded<string>(10);

// Producer: downloads and writes file paths to channel
// Consumer: reads file paths and converts to markdown
```

Det betyder att konverteringen börjar så fort den första filhämtningen, snarare än att vänta på att alla nedladdningar ska slutföras. Den begränsade kapaciteten (10 objekt) ger mottryck - om konverteringen hamnar efter, saktar nedladdningen ner för att matcha.

## Begränsningar och Gotchas

Låt oss vara ärliga om vad detta verktyg inte kan göra:

1. **Det är mycket specifikt för MIN blogg** – Selectors, mönster, och datum extraktion är alla trimmade för mestadelslucid.co.uk. Du skulle behöva anpassa allt för en annan webbplats.

2. **Archive.org har inte allt** – Vissa sidor arkiverades inte, eller arkiverades med trasiga CSS/bilder.

3. **Bilder är bäst-ansträngning** - Verktyget försöker ladda ner bilder från Wayback Machine, men många är helt enkelt borta för alltid.

4. **Döda länkar överallt** - Externa länkar från 2004 pekar på webbplatser som inte längre finns. Jag arbetar på en separat lösning för detta (automatisk Archive.org länk substitution i en middleware - blogginlägg kommer snart!).

5. **LLM-taggar är ofullständiga** – De Ollama-genererade taggarna är oftast förnuftiga, men ibland missa märket. Manuell granskning rekommenderas.

6. **CDX API- trunkering** – För webbplatser med tusentals sidor, CDX API kan returnera trunkerade resultat. Koden hanterar detta graciöst men du kan missa vissa sidor.

## Kör den

Om du vill anpassa detta för din egen webbplats (det kommer att behöva anpassning), kommandona är:

```bash
# Full pipeline (download + convert)
dotnet run -- full

# Just download HTML from Archive.org
dotnet run -- download

# Just convert existing HTML files to Markdown
dotnet run -- convert
```

Verktyget stöder graciös avstängning (Ctrl+C) och kan återupptas från där det slutade eftersom filer är cachad lokalt.

## Resultaten

Efter att ha kört detta på min gamla blogg, hittade jag inlägg som går tillbaka till [1 januari 2004](/blog/365) Och innan! Läsa igenom dem är en fascinerande resa genom tiden. Webbutveckling diskussioner från innan jQuery existerade. Inlägg om teknik som nu är helt föråldrade. Och några pinsamma åsikter jag höll som en yngre utvecklare.

Du kan hitta alla importerade inlägg med hjälp av [Importerad](/blog/category/Imported) Kategorimärke.

## Vad händer härnäst?

Det importerade innehållet har en LOT av döda länkar – det är bara arten av 20-åriga webbinnehåll. I [byggt en mellanutrustningslösning](/blog/the-war-on-404) där

1. Upptäck 404s för gamla webbadresser
2. Hitta automatiskt närmaste Archive.org ögonblicksbild
3. Omdirigera eller visa den arkiverade versionen

## Uppslagsverk

Att bygga detta verktyg var ett helgprojekt som förvandlades till något verkligt användbart. Om du har förlorat innehåll från en gammal blogg, det finns en anständig chans Archive.org har det. Och om du är bekväm med C#, teknikerna här (CDX API fråga, HTML innehåll utvinning, Markdown generation, LLM taggning) kan anpassas för din egen återhämtningsprojekt.

Koden är på [github.com/scottgal/mestlylucid.nugetpaket](https://github.com/scottgal/mostlylucid.nugetpackages/tree/main/Mostlylucid.ArchiveOrg). Det är inte ett polerat bibliotek – det är ett specialbyggt verktyg för min specifika situation – men det kan ge dig idéer för dina egna arkiväventyr.

Och allvarligt talat, gå och donera till Archive.org. De gör ett viktigt arbete.