# Resurrectioning My Old Blog with Archive.org and a Lot of C#

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

Quindi potresti aver notato centinaia di ["nuovi" post sul blog](https://www.mostlylucid.net/blog/category/Imported) Beh, non sono affatto nuovi - sono vecchi. Come, 2004 vecchio. Ho finalmente costruito uno strumento per salvare i miei contenuti dal cimitero digitale che era il mio vecchio blog a per lo piùlucid.co.uk.

## Perché Archive.org è assolutamente brillante

Prima di immergermi nella roba tecnica, devo dare un enorme grido al [Archivio Internet](https://archive.org/) Questa organizzazione no-profit archivia tranquillamente il web dal 1996, conservando miliardi di pagine web che altrimenti andrebbero perse per sempre.

Pensaci per un secondo. Ogni post del blog che hai scritto nel 2005, ogni pagina di GeoCities, ogni profilo di MySpace - c'è una buona possibilità che sia ancora accessibile tramite Archive.org. Stanno fondamentalmente dirigendo un museo di tutto Internet, finanziato da donazioni e sovvenzioni.

Quando il mio vecchio provider di hosting è scomparso (insieme ai miei backup perché ero SMART così), ho pensato che tutto quel contenuto era andato per sempre. A quanto pare la Wayback Machine era stata diligentemente istantanea il mio sito per anni. Archive.org abbastanza letteralmente salvato 6+ anni della mia storia blogging.

Se non hai mai donato loro, considera di farlo. Stanno preservando la nostra storia digitale collettiva.

## Il problema: il mio blog era un casino

Ecco come funziona un blog dal 2004 al 2010 - le tecnologie web hanno cambiato molto durante quel periodo. E, a quanto pare, ho cambiato il mio setup blogging almeno tre volte:

1. **Primi giorni (2004)**: Qualche cosa homebrew ASP.NET con contenuto avvolto in `<div class="post">` all'interno di un `<form>` elemento (perché tutto era una forma allora)
2. **Periodo medio**: Struttura del modello diversa, date in luoghi diversi
3. **Anni successivi**: Ancora un'altra ristrutturazione con selettori leggermente diversi

Dalla memoria ha usato Qualche cosa personalizzata allora [SubText](http://beletsky.net/2010/09/subtext-open-source-blogging-engine.html) (La cosa blogging di Phil Haack). Seguito da Community Server (a [TelligentCity name (optional, probably does not need a translation)](https://community.telligent.com/) cosa ASP.NET utilizzato per ospitare i siti, da ANTHER ex ASP,NET PM Rob Howard) . Tutti i quali avevano diversi modi di aggiornare e diversi modi di visualizzare i contenuti.

Questo significava che qualsiasi strumento di estrazione doveva essere abbastanza flessibile da gestire strutture HTML multiple. Un raschietto "one size si adatta a tutti" non lo avrebbe tagliato.

## Entra nell'archivioOrgImporter

L'ho costruito io. [ArchivioOrgImportatore](https://github.com/scottgal/mostlylucid.nugetpackages/tree/main/Mostlylucid.ArchiveOrg) per risolvere questo problema molto specifico. Si tratta di un .NET 9.0 applicazione console che:

1. **Rispetta i limiti d'uso di Archive.org** - Sono senza scopo di lucro in donazioni, quindi martellare i loro server sarebbe una cosa terribile da fare.
2. **Scarica le pagine archiviate tra le date configurabili**
3. **Estrae il contenuto del blog da strutture HTML multiple**
4. **Genera la pulizia di Markdown** nel mio attuale formato di blog
5. **Usa Ollama per generare tag utili** - perche' non lanciarci un po' di magia?

### Come funziona

Lo strumento segue un'architettura pipeline con tre fasi principali:

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

#### Fase 1: Interrogazione all'Archivio

Lo strumento utilizza quello di Archive.org [API CDX](https://github.com/internetarchive/wayback/tree/master/wayback-cdx-server) per trovare tutte le istantanee archiviate del mio blog. Questa API restituisce un elenco di URL catturati con timestamp, tipi MIME e codici di stato HTTP.

```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
```

La `collapse=urlkey` parametro è intelligente - restituisce solo l'ultima istantanea per ogni URL unico, che riduce notevolmente il numero di duplicati che è necessario affrontare.

Uso anche i modelli regex per filtrare gli URL. I miei vecchi post hanno seguito il modello `/posts/[number].aspx`, quindi:

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

In questo modo ho solo afferrare post sul blog reale, non le pagine di archivio, pagine di categoria, o feed RSS.

#### Fase 2: Essere un buon cittadino con limitazione della velocità

Archive.org è un servizio pubblico. Non hanno il budget infrastrutturale di Google o Amazon. Quindi il downloader è deliberatamente conservatore:

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

Sì, questo significa scaricare centinaia di messaggi richiede un po '. Ma è la cosa giusta da fare. Lo strumento gestisce anche 429 (limite di tasso) risposte con grazia con backoff esponenziale.

C'è anche qualche pulizia necessaria per i file scaricati. Archive.org aggiunge script sulla barra degli strumenti e riscrive gli URL nell'HTML catturato. Il downloader rimuove tutto ciò:

```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;
}
```

Il manico dei modelli regex:

- `<!-- BEGIN WAYBACK TOOLBAR INSERT -->...<!-- END WAYBACK TOOLBAR INSERT -->` - la barra degli strumenti HTML
- `<script>` riferimenti ai tag `playback.archive.org`
- Archivia i commenti dei metadati
- Prefissi URL come `https://web.archive.org/web/20040527/` che vengono preparati a tutti i link

#### Fase 3: L'Incubo di estrazione dei contenuti

Questo è dove le cose diventano interessanti. Ricordate che ho menzionato il mio blog cambiato struttura tre volte? Ecco come ho gestito.

L'estrazione primaria utilizza un selettore CSS:

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

Ma ecco una divertente stranezza - in alcune versioni del mio vecchio sito, il `div.post` era ALL'INTERNO di un `<form>` elemento. Il codice deve estrarre il contenuto PRIMA di rimuovere gli elementi indesiderati, altrimenti rimuovendo `<form>` tags nuke il contenuto effettivo del blog:

```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);
```

La `ExtractMainContent` metodo utilizza una ricerca gerarchica per trovare il contenuto:

```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));
```

Lo strumento dispone anche di selettori di ripiego se quello primario fallisce:

1. `div.blogpost`, `div.singlepost`, `article`
2. `#content`, `#main-content`, `#PostBody`
3. `.post-content`, `.entry-content`, `.article-content`
4. Finalmente, solo il `<body>` se tutto il resto fallisce

Poi c'è una lunga lista di elementi da rimuovere dopo l'estrazione del contenuto:

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

#### Fase 4: Generazione di marcatori

Una volta che abbiamo pulito il contenuto HTML, [ReverseMarkdown](https://github.com/mysticmind/reversemarkdown-net) gestisce il sollevamento pesante di converterlo in GitHub-saporato Markdown.

Ma l'output aveva bisogno di un po' di post-elaborazione. Il vecchio HTML spesso aveva un indentazione strana che confondeva i parser Markdown (le linee indentate diventano blocchi di codice!). Quindi c'è pulizia:

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

L'output finale include il formato front matter del mio blog:

```markdown
# Article Title

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

Article content here...
```

#### Fase 5: generazione del tag LLM-Powered

Ora per la parte divertente. I vecchi post del blog spesso non avevano tag a tutti, o tag che non hanno senso per la mia struttura attuale del sito. Così ho integrato Ollama per analizzare i contenuti e generare tag rilevanti.

La configurazione è semplice:

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

Uso `gemma3:4b` come è veloce e abbastanza piccolo per funzionare localmente senza molto trambusto. La bassa temperatura (0,3) mantiene l'uscita coerente • non vogliamo allucinazioni creative nei nostri tag. Nota: per il mio blog questo ha funzionato come i post erano brevi, se il vostro è più sicuro di guardare chunking e tecniche di summarizzazione per adattarsi alla finestra di contesto del vostro modello.

##### Gestione di posti più lunghi

Ecco una limitazione pratica: LLM hanno finestre di contesto, e pompare un intero post del blog in loro per la generazione di tag è inutile. Lo strumento tronca contenuti a 3000 caratteri:

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

Per la generazione di tag, i primi 3000 caratteri di solito contengono abbastanza contesto per capire che cosa il post è circa. Il prompt istruisce il modello per concentrarsi sulle categorie tech-specific:

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

L'analisi della risposta è difensiva se Ollama restituisce spazzatura o tempi fuori, ci basta ottenere una lista di tag vuoti piuttosto che schiantare l'intero gasdotto.

### Estrazione della data: un approccio multi-strategia

Trovare la data di pubblicazione originale è sorprendentemente difficile. Il mio vecchio blog memorizzato date in luoghi diversi nel corso degli anni. Lo strumento prova strategie multiple:

1. **Selettore configurato** (ad es. `.postfoot`)
2. **Etichette meta**: `article:published_time`, `DC.date.issued`
3. **HTML5 `<time>` elementi**
4. **Classi di date comuni**: `.date`, `.post-date`, `.entry-date`
5. **Modelli Regex** su HTML grezzo (formato ISO, slash-separato, ecc.)
6. **Ripiegamento**: L'istantanea dell'archivio data stessa

Un formato particolarmente fastidioso era il mio vecchio modello di blog "pubblicato giovedì 27 maggio 2004 11:21 PM" stringa. C'è specifica analisi per questo.

### L'Orchestrazione del Pipeline

Il bit architettonico più cool è come il download e la conversione eseguire in parallelo utilizzando .NET Canali:

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

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

Ciò significa che la conversione inizia appena il primo download di file, piuttosto che aspettare che tutti i download per completare. La capacità limitata (10 elementi) fornisce contropressione - se la conversione cade indietro, il download rallenta per abbinare.

## Limitazioni e Gotcha

Siamo onesti su ciò che questo strumento non può fare:

1. **E 'molto specifico per il mio blog** I selettori, i modelli e l'estrazione della data sono tutti sintonizzati per la maggior partelucid.co.uk. Dovresti personalizzare tutto per un sito diverso.

2. **Archive.org non ha tutto** Alcune pagine non sono state archiviate, o sono state archiviate con immagini/CSS rotte.

3. **Le immagini sono best-effort** - Lo strumento cerca di scaricare le immagini dalla Wayback Machine, ma molti sono semplicemente andati per sempre.

4. **Collegamenti morti ovunque** - Collegamenti esterni dal 2004 punto a siti che non esistono più. Sto lavorando su una soluzione separata per questo (sostituzione automatica link Archive.org in un middleware - blog post in arrivo presto!).

5. **I tag LLM sono imperfetti** I tag generati da Ollama sono di solito sensibili, ma a volte mancano il marchio. Si raccomanda una recensione manuale.

6. **Troncatura API CDX** Per i siti con migliaia di pagine, l'API CDX può restituire risultati troncati. Il codice gestisce questo con grazia, ma si potrebbe perdere alcune pagine.

## Eseguirlo

Se si desidera adattare questo per il proprio sito (è necessario personalizzare), i comandi sono:

```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
```

Lo strumento supporta lo spegnimento grazioso (Ctrl+C) e può riprendere da dove ha lasciato i file dal momento che sono cache localmente.

## Risultati

Dopo aver eseguito questo sul mio vecchio blog, ho recuperato post risalenti a [1 gennaio 2004](/blog/365) E prima! Leggere attraverso di loro è un viaggio affascinante attraverso il tempo. Lo sviluppo Web discussioni da prima jQuery esisteva. Posts su tecnologie che ora sono completamente obsolete. E alcune opinioni imbarazzanti che ho tenuto come uno sviluppatore più giovane.

È possibile trovare tutti i messaggi importati utilizzando il [Importato](/blog/category/Imported) categoria tag.

## Cosa c'e' dopo?

Il contenuto importato ha un sacco di link morti che è solo la natura del 20-year-old contenuto web. I [costruito una soluzione middleware](/blog/the-war-on-404) che:

1. Rileva 404 per vecchi URL
2. Trova automaticamente l'istantanea Archive.org più vicina
3. Reindirizzare o visualizzare la versione archiviata

## Avvolgibili

Costruire questo strumento è stato un progetto del fine settimana che si è trasformato in qualcosa di veramente utile. Se hai perso il contenuto da un vecchio blog, c'è una buona probabilità che Archive.org ce l'abbia. E se ti senti a tuo agio con C#, le tecniche qui (chiesa API CDX, estrazione di contenuti HTML, generazione Markdown, tag LLM) potrebbero essere adattate per il tuo progetto di recupero.

Il codice è a [github.com/scottgal/mostlylucid.nugetpackages](https://github.com/scottgal/mostlylucid.nugetpackages/tree/main/Mostlylucid.ArchiveOrg). Non è una libreria levigata è uno strumento appositamente costruito per la mia situazione specifica - ma potrebbe darvi idee per le vostre avventure d'archivio.

E sul serio, vai a donare ad Archive.org. Stanno facendo un lavoro importante.