This is a viewer only at the moment see the article on how this works.
To update the preview hit Ctrl-Alt-R (or ⌘-Alt-R on Mac) or Enter to refresh. The Save icon lets you save the markdown file to disk
This is a preview from the server running through my markdig pipeline
Monday, 24 November 2025
Ви, можливо, помітили сотні. " Новий " блог Останнім часом вони зовсім не нові, вони старі, як, наприклад, 2004 р. я нарешті зробив інструмент, щоб врятувати свій контент з цифрового кладовища, який був моїм старим блогом у centalluciad.co.uk.
Перед тим, як я занурюся в технічні речі, я повинен дати величезний крик для Інтернет- архів Ця некомерційна організація тихо ацтекує веб- сайт з 1996 року, зберігаючи мільярди веб- сторінок, які в іншому випадку були б назавжди втрачені.
Подумайте про це на секунду. кожен допис блогу, який ви написали 2005 року, кожні сторінки GeoCities, кожен профіль MySpace - існує пристойний шанс, що він все ще доступний за допомогою Archive.org.
Після того, як мій старий постачальник послуг- господар зник (майже з моїми резервними копіями через те, що я була SMART ось так), я подумав, що весь цей вміст зник назавжди. Виявилося, що комп' ютер Вейбард вже роками ретельно фотографував мій сайт. Архів.org досить буквально зберіг 6+ років мого блогу.
Якщо ви ніколи не жертвували їм, подумайте про це, вони зберігають нашу колективну цифрову історію.
Ось що можна сказати про запуск блогу у період з 2004 по 2010 рік - веб-технології змінили LETS протягом того часу, і, очевидно, я змінив налаштування блогу щонайменше тричі:
<div class="post"> всередині a <form> елемент (оскільки все було формою в той час)З пам' яті він використовував якусь нетипову річ тоді Підтекст (Щодо блогу у Філа Хака). Послідовно на сервері громад (а) Телігент ASP.NET використовувався для сайтів, автором яких був ASP, NET PM Rob Говард). Всі вони мали різні способи оновлення та різні способи відображення змісту.
Це означало, що будь-який інструмент для видобування достатньо гнучкий, щоб працювати з декількома структурами HTML. "один розмір відповідає всім" скребкам не збирався обрізати його.
Я побудований. Архіватор OrgImporter щоб розв' язати цю дуже специфічну проблему. Це консольна програма .NET 9. 0, яка:
Інструмент слідує за архітектурою трубопроводу з трьома основними фазами:
Archive.org CDX API → Download HTML → Convert to Markdown → Generate Tags → Output Files
Інструмент використовує Archive.org CDX API Щоб знайти всі архівовані знімки мого блогу. Цей API поверне список отриманих адрес URL з часовими штампами, типами MIME і кодами стану HTTP.
// The CDX query builds a URL like this:
// https://web.archive.org/cdx/search/cdx?url=mostlylucid.co.uk/posts/&output=json&collapse=urlkey
The collapse=urlkey Параметр є кмітливим - він повертає лише найсвіжіший знімок для кожної унікальної адреси URL, що значно зменшує кількість дублікатів, з якими вам слід працювати.
Крім того, я використовую шаблони regex для фільтрування адрес URL. Мої старі дописи слідували за шаблоном /posts/[number].aspxТак.
{
"IncludePatterns": ["/posts/\\d+\\.aspx$"]
}
Таким чином, я перехоплюю лише справжні дописи блогів, а не сторінки архівів, сторінки категорій або подачі RSS.
Archive.org - це державна служба, у них немає бюджету інфраструктури на Google або Amazon.
// Default: 5 seconds between requests, single-threaded downloads
"RateLimitMs": 5000,
"MaxConcurrentDownloads": 1
Так, це означає, що звантаження сотень дописів триває деякий час, але це правильно. Інструмент також керує 429 (рівне обмеження) відповідьми з експоненціальним зворотним зв' язком.
Крім того, потрібне деяке спорожнення звантажених файлів. Archive.org додає скрипти панелі інструментів і перезаписує адреси URL у отриманому HTML. Вилучувачі все це надсилають:
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;
}
Керування шаблонами формального виразу:
<!-- BEGIN WAYBACK TOOLBAR INSERT -->...<!-- END WAYBACK TOOLBAR INSERT --> - пенал HTML<script> посилання на мітки playback.archive.orghttps://web.archive.org/web/20040527/ те, що підготовлятися до всіх посиланьТут все стає цікаво, пам'ятаєте, я згадував, що мій блог тричі змінював структуру?
Основне видобування використовує засіб вибору CSS:
{
"ContentSelector": "div.post"
}
Але ось весела викрутка в деяких версіях мого старого сайту div.post був ДУЖЕ ВАЖЛИВИЙ <form> element. Код має видобути вміст B перш ніж вилучати небажані елементи, у іншому випадку вилучити <form> tags буде nuke поточний вміст блогу:
// 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);
The ExtractMainContent метод використовує ієрархічний пошук для пошуку вмісту:
// 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));
Крім того, у інструменті передбачено інструмент вибору зворотного повернення, якщо перший з цих інструментів зазнає невдачі:
div.blogpost, div.singlepost, article#content, #main-content, #PostBody.post-content, .entry-content, .article-content<body> якщо всі інші зазнають невдачіКрім того, існує довгий список елементів, які вилучаються після видобування матеріалу:
{
"RemoveSelectors": [
"nav", "header", "footer", ".sidebar", ".advertisement",
".comments", ".social-share", ".related-posts", "script",
"style", "noscript", "iframe", "#commentform", ".postNav"
]
}
Після того, як у нас буде чистий зміст HTML, BackMarkdown керує важким підйомом на GitHub-flavored Markdown.
Але на виході потрібні були кінцеві обробки. Старий HTML часто мав дивні відступи, які могли б спантеличити аналізаторів Markdown (встановлені рядки стають блоками коду!) Отже, існує чистка:
// Removes leading whitespace from non-code lines
// Preserves code block formatting (respects ``` fences)
// Removes excessive blank lines (max 2 consecutive)
Остаточний вивід містить передній формат даних мого блогу:
# Article Title
Article content here...
Тепер весела частина: дописи старих блогів часто взагалі не мали міток, або міток, які не мали сенсу для моєї поточної структури сайта, тому я інтегрував Олламу з аналізу вмісту і створення відповідних міток.
Налаштування прості:
{
"Ollama": {
"BaseUrl": "http://localhost:11434",
"Model": "gemma3:4b",
"Temperature": 0.3,
"MaxTags": 5,
"Enabled": true
}
}
Я користуюся gemma3:4b Низька температура (0,3) зберігає виведені дані послідовними, ми не хочемо творчих галюцинацій у наших тегах. Примітка; для мого блогу це працювало, як пости є короткими, якщо ваша більш довша, щоб дивитися на прийоми розбиття і узагальнення, що вміщуються у контекстному вікні вашої моделі.
Це практичне обмеження: LLM мають контекстні вікна і перекачує до них весь допис блог для створення міток. Інструмент truncatecates вміст до 3000 символів:
var truncatedContent = content.Length > 3000
? content[..3000] + "..."
: content;
Для створення теґів перші 3000 символів, зазвичай, містять достатньо контексту, щоб зрозуміти суть повідомлення. За допомогою запиту можна вказати моделі, що слід зосередитися на категоріях, специфічних для технічного типу:
Generate up to 5 tags, short (1-3 words), focusing on:
.NET, C#, ASP.NET, JavaScript, Docker, Database, API, Security, DevOps, Cloud
Опрацювання полягає в тому, що якщо Ольма поверне сміття або відключиться, ми отримаємо порожній список теґів, замість того, щоб розбити весь трубопровод.
Знайти початкову дату публікації на диво складно. Мій старий блог зберіг дати у різних місцях протягом років. Інструмент виконає декілька стратегій:
.postfoot)article:published_time, DC.date.issued<time> елементи.date, .post-date, .entry-dateОсобливо дратує те, що мій старий шаблон блогу " поклав у четвер 27 травня 2004 року.
Найхолоднішим архітектурним бітом є робота з звантаження і перетворення паралельно за допомогою каналів. NET:
var channel = Channel.CreateBounded<string>(10);
// Producer: downloads and writes file paths to channel
// Consumer: reads file paths and converts to markdown
Це означає, що перетворення починатиметься одразу після першого звантаження файлів, а не очікування на завершення всіх звантажень. Обмежена місткість (10 елементів) забезпечує зворотний тиск, - якщо перетворення відступає, звантаження звантажується так, щоб збігався.
Давайте будемо чесними щодо того, що цей інструмент не може зробити:
Вона дуже специфічна для мого блогу. Все эти часы, сделаны для qualcid.co.uk.Тебе нужно объединить все для разного места.
Archive.org не має всього ♫ Деякі сторінки не були архівовані, або були архівовані зі зламаними CSS/images.
Зображення найкращі для зображеньName - Інструмент намагається завантажити зображення з Машини Вейвера, але багато з них просто зникають назавжди.
Повсюди мертві посилання - Зовнішні посилання з 2004 року вказують на сайти, яких вже немає. Я працюю над окремим розв' язком для цього (автоматично Archive.org пов' язує заміну за допомогою поля посередині блогу, що наближається найближчим часом!).
Мітки LLM недосконалі ▸ Створені теґи зазвичай є розсудливими, але іноді їх не помічають. Рекомендуємо переглянути їх вручну.
truncation CDX API ♫ За сайтами з тисячами сторінок, API CDX може повернути обрізані результати. Код використовує це граціозно, але ви можете пропустити деякі сторінки.
Якщо ви бажаєте пристосувати цей параметр до вашого власного сайта (потрібна його налаштування), цими командами будуть:
# 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
Інструмент підтримує граційне завершення роботи (Ctrl+C) і може поновлюватися з того місця, де його не було позначено, оскільки файли зберігаються локально у кеші.
Після того, як я запустив це у своєму старому блозі, я відновив дописи, що датуються до 1 січня 2004 року і раніше! читання крізь них є захопливою подорожжю у часі. обговорення веб-розробки ще до появи Джоурі. а також деякі незручні погляди, які я вважаю молодшими розробниками.
Ви можете знайти всі імпортовані дописи за допомогою Імпортовано мітка категорії.
В імпортованому контенті є код мертвих зв'язків, це просто природа 20-річного веб- контенту. побудова розв' язання середньої програми те:
Побудова цього інструменту була проектом на вихідні, який перетворився на щось справді корисне. Якщо ви втратили вміст зі старого блогу, його можна було б використати у архіві.org. І, якщо вам зручно використовувати C#, методи (перемотування CCDX API, видобування вмісту HTML, створення Markdown, створення LLM taging) можна адаптувати до вашого власного проекту відновлення.
Код в gitub.com/scottgal/ methlylucid. nuget packagesЭто не библиотека, что создала цель для моей личной ситуации, но это может дать тебе идеи по твоим собственным приключениям.
І серйозно, ідіть з пожертвами на Archive.org, вони виконують важливу роботу.
© 2026 Scott Galloway — Unlicense — All content and source code on this site is free to use, copy, modify, and sell.