
简介这是一个CSDN博客搬家与博文下载工具面向需要批量备份自己或他人CSDN文章的博主、爬虫爱好者及有一定Java基础的二次开发者。包内含可运行的class文件、Java源码DoBackup.java、Eclipse工程配置.project/.classpath/.prefs及核心依赖htmlparser.jar共7个文件压缩后仅272KB。作者基于原版调试修复后已成功下载30多篇长文、单篇容量达1G的博客说明工具在长文与大附件场景下有较好的稳定性。需注意源码中写死了CSDN域名若想抓取其他平台博客需全局替换相关域名同时原版爬虫解析可能受htmlparser.jar版本更新影响属于常见踩坑点。目前该资源已有469人学习下载适合想了解HTML解析、批量下载实现逻辑或需要快速备份CSDN文章的读者参考。 大概两年前我收藏夹里躺着一个特别喜欢的独立博客作者写了五六年全是Linux运维和自建服务的实操心得。某天我突然想翻一篇老文章发现域名过期没续费整个站连同几百篇文章一起消失了。当时我找了一下午数据恢复的办法最终只找回三分之一。从那以后我养成一个习惯任何有价值的博客读完后顺手就下载一份归档。这个习惯慢慢变成了一套完整的工作流也就是你看到的这个“博客下载工具”。这篇文章不是单纯给你推荐一个软件而是把我从零搭建博客下载归档工具的完整思路、工具选型、踩坑记录全部摊开。内容包括用什么方式下载最省心现成工具和自写脚本各自解决什么问题遇到动态网页怎么处理以及下载完之后怎么把这些文章变成真正能检索、能长期使用的知识库。适合所有想把网上内容真正“存下来”的人不管你会不会写代码都能找到自己能用的那一层方案。1. 先把问题拆清楚博客下载到底在解决什么1.1 内容丢失的风险远比你想的更常见大多数人对博客的依赖是“在线阅读就好”但内容消失这件事发生的频率比我预期的高得多。除了域名过期还有平台改版把旧文章下线、博主清空服务器、平台整顿删除敏感分类、甚至第三方存储失效导致整个图床的图片全部挂掉。我做备份工具的初衷就是应对这些场景。不要抱着“我喜欢的博客一定会一直存在”的侥幸心理。越是好内容越值得落地到本地。一个完整、可自包含的本地副本是任何在线服务都给不了的安全感。1.2 “读过”不等于“拥有”离线阅读只是起点很多人觉得博客下载工具不就是把网页存下来吗其实离线阅读只解决了“能不能在没有网络的时候看”这一层问题。我更看重的是后面的知识管理价值把分散在几十个博客里的文章统一格式、统一命名、放进同一个库之后能全文搜索、能建立主题关联、能在写技术方案时快速引用。这和使用笔记软件的道理一样。你收藏1000篇文章如果只是堆在收藏夹里它们还是死的真正把它们下载、清洗、归入知识库才变成自己的东西。博客下载工具就是这套知识管理流程的入口。1.3 归档工具不等于爬虫别一上来就做重很多人一听“博客下载工具”第一反应是“写爬虫”。实际上做定向归档比写通用爬虫简单得多也安全得多目标网站固定、页面结构固定、更新频率也不高。你需要的不是一套复杂的分布式抓取系统而是一个能反复运行、增量更新的轻量归档器。想明白这个定位下面所有选型和设计思路就都顺了。2. 现成工具怎么选三类方案各有各的生态位2.1 整站镜像类要的是“原封不动”如果你只想要某个博客的完整快照保留原站排版、图片路径、跳转关系整站镜像工具是最快的。命令行里的wget是这个领域的常青树一条命令就能把整个站点拉下来wget --mirror \ --convert-links \ --adjust-extension \ --page-requisites \ --no-parent \ https://example.com/这里每个参数都有它的用意--mirror是镜像模式--convert-links把页面里的绝对链接改成可本地访问的相对链接--adjust-extension给没有扩展名的页面补上.html--page-requisites会把图片、CSS、JS 这些资源一并下载--no-parent防止往上爬出网站根目录。实测下来对于传统服务端渲染的博客这一条命令基本够用。除了 wget图形化的 HTTrack 也能做类似的事适合不想碰命令行的人。这类方案的优点是省事、还原度高缺点是整站体积大、后期不好检索而且如果博客有动态加载的内容工具可能拿不到完整正文。2.2 单篇转存类目标是干净的 Markdown如果你只是看中某几篇文章希望保存成干净的 Markdown 放进笔记库单篇转存工具更合适。浏览器扩展 MarkDownload 可以在网页上一键把文章主体转成 Markdown支持复制到剪贴板或直接保存成文件。类似思路的自托管方案还有简悦可以在服务端批量转换文章为 Markdown 并保留图片。我在整理专题类文章时几乎只用单篇转存的方式。它最大的价值不在于“下载”而在于“提纯”——自动过滤侧边栏、广告、相关推荐这些干扰区块只留下正文。对于需要进入知识库的内容这个步骤非常重要后面我会专门讲原理。2.3 基于RSS的批量同步最优雅的增量方案大多数独立博客都会提供 RSS 或 Atom 订阅地址。这个接口是批量下载最靠谱、最友好的入口。RSS 里通常包含文章的标题、链接、发布时间有些博客还会在摘要里给你全文。我最早的自动备份脚本就是从 RSS 入手解析 feed拿到文章链接列表再逐篇提取正文。后续每次运行都只处理新增的文章天然就是增量更新。这种方式对博客的负载很小对网站管理员来说也比较友好不会像疯狂抓取那样给对方服务器造成压力。import feedparser feed feedparser.parse(https://example.com/feed.xml) for entry in feed.entries: title entry.get(title) link entry.get(link) published entry.get(published) print(title, link, published)2.4 我的选型思路按用途决定别迷信单一工具三类工具不是互斥的实际上它们解决的是三个不同层面的需求整站镜像负责“保底存档”单篇转存负责“提取精华”RSS批量下载负责“长期增量同步”。我在实际使用中会这样组合场景推荐手段原因博客即将关闭紧急做全站备份wget整站镜像速度快还原度最高看到一篇好文章想放进知识库MarkDownload/简悦转Markdown便于后续编辑长期跟踪某几个常更新的博客基于RSS的同步脚本低负载自动增量需要全文搜索大量历史文章统一转为Markdown后入库检索效率最高如果你只要一个方案我建议从“RSS解析单篇转存”入手这是性价比最高、对网站最友好、后期整理最方便的路径。整站镜像适合应急但不适合作为长期知识库的底座。3. 自己动手做一个下载工具核心流程拆解3.1 技术栈其实很轻Python就够如果决定自写一个博客下载工具Python 是最舒服的选择生态里有现成的库帮你处理80%的脏活累活。我的工具核心依赖只有四个requests负责请求网页BeautifulSoup负责解析HTMLreadability-lxml负责从杂乱页面里提取正文markdownify负责把HTML转成Markdown。额外还会用feedparser解析RSS。不要一上来就想上 Scrapy 之类的重型框架。博客归档的目标是精确、温和、可靠几行脚本加上良好的工程结构比复杂框架更容易维护。等到你发现自己需要管理几百个站点、处理复杂的抓取调度时再考虑升级也不迟。3.2 文章列表获取优先走sitemap或RSS别直接翻页下载工具的第一个关键步骤是拿到博客所有文章的真实链接列表。这一步如果走弯路后面全都会很痛苦。我最推荐的两个入口sitemap.xml通常位于/sitemap.xml或/sitemap_index.xml里面按层次列出所有文章URL解析简单信息完整。RSS/Atom适合增量同步但有些博客的feed只包含最近10~20篇拿不到全量历史。如果这两条路都走不通才去解析首页和归档页的分页结构。实际写代码时可以先用 requests 请求 sitemap再用 BeautifulSoup 把里面所有loc标签解析出来import requests from bs4 import BeautifulSoup sitemap_url https://example.com/sitemap.xml resp requests.get(sitemap_url, timeout10) soup BeautifulSoup(resp.text, html.parser) urls [loc.get_text() for loc in soup.find_all(loc)] print(f共发现 {len(urls)} 个URL)拿到URL列表后建议先按域名过滤一遍避免下载到外链图片所在的其他站点。之后对每个URL做去重再交给下载模块。3.3 正文提取与清洗这一步决定文章以后好不好用下载网页本身很容易难的是从一堆HTML标签、导航栏、评论区块、侧边栏里把真正的正文干净地抽出来。我用的是readability-lxml它是 Firefox 的 Reader View 算法移植到 Python 的版本。用起来非常简洁import requests from readability import Document import markdownify url https://example.com/archives/2024/05/hello-world.html html requests.get(url, headers{User-Agent: Mozilla/5.0}, timeout10).text doc Document(html) title doc.title() content_html doc.summary(html_partialTrue) markdown_text markdownify.markdownify(content_html, heading_styleATX)Document(html)会分析页面结构doc.summary()返回的是它认为的正文区块HTML然后markdownify再把这段HTML转成 Markdown。整个提取过程基本不需要自己写正则。不过我要提醒一句readability 的识别不是100%准确特别是一些排版混乱的博客提取出来的段落顺序可能错乱。我的做法是每篇文章保留一份原始 HTML 快照再生成一份清洗后的 Markdown两者同时存档。原始快照是保底方案Markdown 是日常使用的主格式。3.4 增量更新与去重让工具能长期跑下去归档工具最关键的要求是“能反复跑而不会重复下载”。我维护了一个index.json文件记录每篇文章的URL、标题、下载时间和内容哈希值。每次运行工具时先读取索引再和新拿到的URL列表对比只下载新增的或哈希值变化的文章。import json import hashlib def compute_hash(text): return hashlib.sha256(text.encode(utf-8)).hexdigest() # 加载已有索引 with open(index.json, r, encodingutf-8) as f: index json.load(f) # 对每篇文章做去重判断 for url in urls: if url not in index: # 下载并加入索引 index[url] {title: title, hash: compute_hash(content)} else: # 如果内容哈希发生变化说明文章更新过重新下载 old_hash index[url].get(hash) if old_hash ! compute_hash(content): pass # 重新下载增量更新的意义在于它能让你放心地把它挂在定时任务里。我每天凌晨跑一次对所有订阅的博客自动同步新文章完全不需要人工干预。4. 实操阶段绕不开的几个坑逐个说清楚4.1 请求频率失控被网站临时拦截刚开始写下载工具时我犯过最典型的错误拿到一个博客的2000篇文章URL后开足马力循环请求大约跑到第300篇对方服务器直接返回一堆403。这件事不难理解就是请求太密集被对方限流了跟恶意攻击一个模式。解决方案很朴素在每次请求之间加随机延时而不是固定延时。固定延时很容易被识别成脚本行为随机延时更接近真人浏览的节奏import time import random def fetch_with_politeness(url): time.sleep(random.uniform(2, 5)) resp requests.get(url, headers{User-Agent: Mozilla/5.0}, timeout10) return resp一般个人博客控制在每篇间隔3秒左右就足够温和了。实际耗时算下来抓一个500篇的博客大约需要30到40分钟完全可以接受。另外加一个退避机制也很有必要如果连续出现三次非200状态码就暂停5分钟再继续。这个机制救过我很多次。4.2 乱码问题几乎都是编码表没对上博客的编码问题比想象中常见尤其是有些老博客用了非UTF-8编码。请求响应里的charset和页面meta标签里的声明可能不一致如果 requests 用了错误的编码去解析文本后面全部是乱码。解决思路是不要盲目相信 response 的编码声明在拿到响应后先看原始字节尝试用可能的编码解码resp requests.get(url, timeout10) if resp.encoding is None or resp.encoding.lower() ! utf-8: # 尝试用utf-8解码失败则回退到gbk try: resp.encoding utf-8 text resp.text except UnicodeDecodeError: resp.encoding gbk text resp.text实测下来国内一些更新频率低的老博客使用GBK/GB2312的概率不低。这一步处理好了后面提取正文就不会因为编码问题前功尽弃。4.3 图片懒加载与本地化存储现在很多博客的图片地址并不是直接写在img src里的而是放在>from bs4 import BeautifulSoup for img in soup.find_all(img): src img.get(src) or img.get(data-src) or img.get(data-original) if not src or not src.startswith(http): continue # 下载图片保存到 images 目录 filename src.split(/)[-1] # 将 src 替换为本地相对路径 img[src] fimages/{filename}这是把“可读”变成“可长久保存”的关键一步。如果不做图片本地化一旦原站的图床挂掉下载下来的文章就缺胳膊少腿归档的意义就大打折扣了。4.4 动态渲染的博客用无头浏览器兜底现在有些博客用前端框架渲染页面服务端返回的HTML里基本没有正文内容。对这种站点requests BeautifulSoup 这套组合拳完全失效。我的应对方式是引入 Playwright启动无头浏览器等页面JavaScript执行完再抓取渲染后的HTMLfrom playwright.sync_api import sync_playwright with sync_playwright() as p: browser p.chromium.launch() page browser.new_page() page.goto(url, wait_untilnetworkidle) html page.content() browser.close()这里networkidle是等网络请求基本结束再返回页面内容。对于一些特别重的页面可以额外加一个page.wait_for_selector(article)确保正文节点已经渲染出来。无头浏览器的缺点是耗时更长、内存占用更大所以我的策略是先用普通方式请求发现正文为空时才切换到无头浏览器兜底这样大部分静态博客还是能快速完成下载。4.5 使用伦理边界尊重robots和版权做博客下载工具必须给自己划一条清晰的边界。我个人遵循三条原则只下载允许公开访问的内容尊重robots.txt里明确禁止抓取的目录不把下载的内容用于再发布或商业用途。归档是为了个人学习和备份这种使用方式绝大多数内容创作者是可以接受的。不要用工具去突破登录墙、付费墙或者任何形式的访问控制。这不仅是技术问题也是基本的尊重问题。下载工具应该服务于“保存公开知识”这个目的而不是成为内容窃取的工具。5. 下载不是终点把归档变成可检索的知识库5.1 文件命名和目录结构是地基下载下来的文章如果文件名乱起再好的内容也会被埋没。我的目录结构是按域名、日期、标题三级组织backup/ └── example.com/ ├── 2024-05-12-hello-world.md ├── 2024-06-03-nginx-tuning.md └── images/ ├── 1.jpg └── 2.png文件名里的日期取自文章发布时间的RFC 3339格式而不是下载日期。这样排序时能按时间线自然浏览。Markdown 文件开头我会写入YAML front matter保留标题、原文链接、发布时间、标签这些元数据方便后续用各种工具检索--- title: Hello World url: https://example.com/archives/2024/05/hello-world.html date: 2024-05-12 tags: [教程, 入门] ---5.2 全文搜索本地知识库的刚需归档文章数量超过两三百篇后按目录翻文件就完全不现实了。全文检索是知识库的刚需。这里我推荐几个由浅入深的选择。最简单的方案是安装 ripgrep在备份目录里直接按关键词搜索rg -l nginx backup/如果想要图形化界面把备份目录挂进 Obsidian配合内置搜索就能在Markdown文件里做全文检索。如果你有轻微折腾精神也可以用 SQLite 的 FTS5 扩展建一个本地索引用 Python 把每篇文章的标题和正文塞进去查询速度飞快CREATE VIRTUAL TABLE posts USING fts5(title, content, url);实测一个约2000篇文章的本地库全文搜索基本在毫秒级返回。这种离线可检索的体验是在线收藏夹永远给不了的。5.3 双链笔记让下载的内容与你的思考连接起来文章归档入库后还有一个更进阶的玩法把下载的文章和自己的笔记打通。在 Obsidian 这类双链笔记工具里你可以直接归档的Markdown文件里新建笔记、添加批注、链接到另一篇归档文章甚至建立主题索引。我的做法是对每个感兴趣的专题建一个MOC内容地图笔记比如“Linux性能优化”这个MOC下面通过双链关联所有从不同博客下载的相关文章。这样一来原本分散在不同站点、不同作者的知识被重新组织成你自己的知识网络。从“收藏文章”到“建立连接”这才是下载归档这个动作真正的增值所在。最后分享一点个人体会博客下载工具做得再好也比不上持续运行的纪律。工具本身可以很简单三五个脚本就能跑起来真正难的是养成定期整理的习惯。我现在的节奏是每周日看一下这周的自动归档结果随手补充标签、修正提取错误的标题顺便把值得精读的文章转成带自己批注的笔记。这个动作花不了半小时但长期积累下来你会发现自己的“第二大脑”越来越厚实。如果你还没有开始做博客归档今天就是个不错的时机——先保存一篇你最喜欢的文章试试看剩下的问题等你真正遇到再回来翻这篇文章。本文还有配套的精品资源点击获取