硬盘里那个叫 tech-archive 的目录,是我这几年陆陆续续攒下来的技术资料库,里面躺着八百多个 PDF。最早的几份是几年前从 CSDN 博客上存下来的单片机配置笔记,去年我想回头查其中一个寄存器地址,点开原链接——文章已经被作者删了,评论区只剩一句"内容已迁移"。从那天起,把 CSDN 文章转成 PDF 归档就成了我的固定动作:找到一篇值得留下的技术文章,把它变成一份不依赖网络、不怕删改、能随时翻、能直接打印做标注的 PDF 文件。这篇内容就是把这套流程完整拆开讲清楚,包括什么时候该转、页面里有哪些坑、浏览器打印的参数怎么填、批量导出用什么脚本、转完怎么验收质量。不管你是刚开始收集资料的新手,还是已经存了几百份文件想升级工作流的人,都能直接照着做。
1. 先把"值不值得转"这件事想明白
我见过太多人一上来就研究工具,结果存了三百个 PDF 再也没打开过。转 PDF 这个动作本身不贵,但管理和检索的成本会随着数量线性增长,所以第一步不是动手,是筛选。
1.1 三类真正值得落成本地 PDF 的文章
我自己的判断标准很粗暴,只有满足下面任意一条才会转:
- 含可复现的操作步骤。比如某个环境的完整安装流程、某个报错的处理链路、某个参数的调优过程。这类内容一旦原文改动或者配图挂掉,价值直接归零,必须本地留一份。
- 含配置清单、参数表、命令集合。这类内容我经常要在没有外网的机器上对照着敲,PDF 是最省事的形式,不用来回切窗口。
- 成系列的教程。单篇可以靠收藏夹,但一个十几篇的系列教程如果分散在各个收藏里,半年后你根本找不到第三篇在哪。合成一份 PDF 反而形成了天然的目录。
反过来,纯资讯类、观点评论类、以及那些每年都会被新版本推翻的"某版本新特性速览",我基本不存。这类内容生命周期太短,存下来只会污染你的资料库。
1.2 一个筛选清单,三十秒决定去留
为了不在这件事上纠结,我给自己定了一张表,看完文章扫一眼就能定:
| 判断维度 | 值得转 | 不值得转 |
|---|---|---|
| 内容类型 | 教程、排查记录、参数手册 | 资讯、活动公告、观点随笔 |
| 时效性 | 原理类、通用方法 | 版本强相关且更新频繁 |
| 是否含代码 | 有可运行片段 | 只有概念描述 |
| 阅读场景 | 需要离线/反复查阅 | 一次看完即弃 |
| 图文依赖 | 大量截图和流程图 | 纯文字 |
提示:如果一篇文章你犹豫超过十秒,那基本就是不需要。真正有用的文章,你看到一半就会想"这个得存下来"。
1.3 转 PDF 之外的第一个备选方案
顺便说一句,不是所有情况都要转 PDF。如果文章只有几百字、纯粹是个命令备忘,直接复制到本地笔记里比转 PDF 快十倍。PDF 的优势在于保留原始排版、图文位置和代码高亮,当你需要"看到作者原本长什么样"的时候,它才不可替代。我一般是这样分工的:短备忘进笔记,长教程和图文混排的进 PDF。
2. 转换之前,得先摸清页面到底是怎么渲染的
很多人打印出来发现缺图、缺代码、排版错乱,八成不是工具的问题,是没搞清楚页面结构就下手了。这一步花五分钟,能省掉后面反复重来的时间。
2.1 服务端直出和前端动态渲染的区别
技术博客的正文渲染大致分两类。一类是打开页面时 HTML 里就已经带着完整正文,浏览器右键"查看网页源代码"就能看到全部文字;另一类是先给个空壳,正文靠脚本在浏览器里动态拼出来。这两类在处理手法上完全不同:
- 前者简单,浏览器打印、命令行工具、简单脚本都能拿到完整内容。
- 后者麻烦,如果你用不带浏览器内核的工具直接抓,拿到的往往是个空白页或者只有标题。
判断方法很直接:打开开发者工具,禁用 JavaScript 刷新一次页面。如果正文还在,就是第一类;如果正文消失只剩导航,就是第二类,必须用带渲染引擎的方案。
2.2 懒加载图片和折叠代码块
这是最容易吃亏的两个地方。图片懒加载意味着你停留在页面顶部时,下面的图还没加载出来,这时候直接按打印,下半部分的插图会是空框。解决办法是先手动滚到页面底部,等所有图都渲染完,再回到顶部打印。
折叠代码块更隐蔽。有些文章的代码默认只显示几行,要点击"展开"才显示全部。打印前必须把所有折叠项点开,否则你存下来的 PDF 里,最关键的那段代码刚好被省略号截掉了。批量处理时这一步尤其要注意,脚本里必须加一步"点击所有展开按钮"。
2.3 关于需要登录才能查看的内容
有些文章或专栏需要登录后、甚至是订阅后才能看全文。这里的态度要明确:正常登录自己的账号,把你有权访问的内容导出来自用,这是合理的个人归档行为;但如果内容本身需要付费授权,那就老老实实付费,不要试图绕过任何访问控制。另外,导出后只在个人设备上阅读使用,不要二次分发或者上传到公开渠道,这是基本的分寸。
3. 浏览器打印这条路,参数怎么填才不出废页
浏览器自带的打印成 PDF 是所有方案里门槛最低的,Windows 上一般对应"Microsoft Print to PDF"这个虚拟打印机,Mac 和 Linux 上就是系统自带的"存储为 PDF"。但默认参数打出来的东西基本没法看:左右各一条侧边栏,底部一堆推荐阅读,代码块被拦腰砍断。下面是我摸索出来的一套固定流程。
3.1 打印预览打开后先做三项清理
按 Ctrl+P 或者 Cmd+P 之后,别急着点保存,先处理这三件事:
- 砍掉非正文区域。最省事的办法是开启浏览器的"阅读模式"(地址栏右侧那个像书本的图标),它会把导航、侧栏、评论区、广告全部剥掉,只留正文。如果阅读模式识别失败,就退回手动方案:在开发者工具里选中要隐藏的区块,按 Delete 键临时删掉,注意这个操作只在当前页面会话有效,刷新就恢复,所以删完立刻打印。
- 展开全部折叠内容。回到页面上把所有"展开全文""显示更多"的按钮点一遍。
- 触发所有懒加载图片。从顶部匀速滚到底部再滚回来,或者在开发者工具的 Console 里执行一次滚动脚本,确保图片全部加载。
3.2 页边距、缩放和背景图形这三个参数
打印对话框里那几个不起眼的选项,直接决定了成品质量。我用下来最稳的一组配置是:
| 参数 | 推荐值 | 理由 |
|---|---|---|
| 纸张 | A4 | 通用性最好,打印和屏幕阅读都合适 |
| 边距 | 默认或"最小" | 自定义边距容易让代码块超宽被裁 |
| 缩放 | 80% 到 90% | 技术文章常有宽表格和长代码行,缩一点能避免横向截断 |
| 背景图形 | 必须勾选 | 不勾的话代码高亮底色全丢,只剩黑白文字 |
| 页眉页脚 | 取消勾选 | 否则每页顶部带 URL、底部带页码和日期 |
| 双面打印 | 视情况 | 只是电子存档的话无所谓 |
注意:缩放低于 75% 之后正文会明显变小,屏幕上读起来很累。如果 90% 仍然有横向截断,问题不在缩放,而在代码块本身不支持换行,得用下一节的 CSS 方案解决。
3.3 代码块被拦腰截断的修复手法
这是最让人抓狂的问题:一段五十行的代码,打印出来第一页尾巴断在第十二行,第二页开头接着第十三行,中间还会插进一个页眉。修复思路是往页面里注入一段打印专用样式,告诉浏览器"代码块和图片不要跨页断开"。
具体做法是打开开发者工具的 Console,粘贴执行下面这段:
const style = document.createElement('style'); style.textContent = ` @media print { pre, code, blockquote, table, figure, img { break-inside: avoid !important; page-break-inside: avoid !important; } pre { white-space: pre-wrap !important; word-break: break-all !important; font-size: 11px !important; line-height: 1.4 !important; } table { font-size: 11px !important; } h1, h2, h3 { break-after: avoid !important; } body { -webkit-print-color-adjust: exact !important; print-color-adjust: exact !important; } } `; document.head.appendChild(style);其中break-inside: avoid是核心,它让代码块、图片、表格尽量保持在同一页内;white-space: pre-wrap让超长代码行自动折行,避免横向被裁;最后一行print-color-adjust: exact是强制保留背景色,某些浏览器里光勾选"背景图形"还不够,得靠它兜底。执行完这段再按 Ctrl+P,会发现断裂问题基本消失,代价只是页数多一点,这对电子存档完全值得。
3.4 关于页码,浏览器原生确实没有
浏览器打印出来的 PDF 默认不带页码,长文档翻起来不方便。两个补救办法:一是装一个能生成页码的打印辅助扩展,在保存时自动在页脚叠加;二是先用浏览器导出 PDF,再用任意一款 PDF 编辑器批量添加页码。我一般用第二种,因为可以顺手在封面加个标题和归档日期,做成一份像样的文档。这一步不算刚需,但如果你打算长期归档,加上页码和标题页会让检索体验好很多。
4. 从单篇到整栏目:批量导出的实现路径
单篇靠浏览器打印够了,但当你想把一个系列、一个专栏甚至一个作者的全部教程一次性存下来时,手动操作就完全不现实了。这时候就得上自动化。
4.1 三种批量方案的实际取舍
我把能想到的路子都试了一遍,结论如下:
| 方案 | 上手难度 | 批量能力 | 适用场景 |
|---|---|---|---|
| 浏览器扩展 | 极低 | 中等 | 一次导十几篇,偶尔用 |
| 命令行工具 | 中等 | 强 | 需要稳定复现、定期跑 |
| 自写脚本 | 较高 | 最强 | 有定制需求,比如加封面、合并目录 |
我的建议是:如果你只是偶尔存几篇,装个支持"批量打印当前标签页"的扩展就够了,把所有要存的文章在标签页里打开,一次性导出。如果你要定期归档,或者需要处理上百篇,那就直接上脚本,一次投入换来长期省事。
4.2 用无头浏览器跑批量导出
下面这份脚本是我自己一直在用的,基于 Python 加 Playwright,核心逻辑是:逐个打开文章链接,等页面渲染完成,展开所有折叠块,滚到底部触发懒加载,最后调用浏览器的原生打印接口输出 PDF。
import asyncio from pathlib import Path from playwright.async_api import async_playwright URLS_FILE = "urls.txt" OUT_DIR = Path("pdf_out") OUT_DIR.mkdir(exist_ok=True) PRINT_CSS = """ @media print { pre, code, table, figure, img { break-inside: avoid !important; } pre { white-space: pre-wrap !important; word-break: break-all !important; } body { -webkit-print-color-adjust: exact !important; } } """ async def save_one(page, url, idx): await page.goto(url, wait_until="networkidle", timeout=60000) # 展开所有折叠代码块,选择器需按实际页面结构调整 for sel in [".show-more", ".read-more", ".code-expand"]: for btn in await page.query_selector_all(sel): try: await btn.click() except Exception: pass # 滚到底部触发懒加载 await page.evaluate(""" async () => { for (let y = 0; y < document.body.scrollHeight; y += 600) { window.scrollTo(0, y); await new Promise(r => setTimeout(r, 150)); } window.scrollTo(0, 0); } """) await page.add_style_tag(content=PRINT_CSS) title = (await page.title())[:60].replace("/", "_").replace("\\", "_") out = OUT_DIR / f"{idx:03d}_{title}.pdf" await page.pdf( path=str(out), format="A4", print_background=True, margin={"top": "12mm", "bottom": "14mm", "left": "10mm", "right": "10mm"}, scale=0.9, ) print(f"done -> {out}") async def main(): urls = [u.strip() for u in Path(URLS_FILE).read_text(encoding="utf-8").splitlines() if u.strip()] async with async_playwright() as p: browser = await p.chromium.launch() page = await browser.new_page(viewport={"width": 1280, "height": 900}) for i, url in enumerate(urls, 1): try: await save_one(page, url, i) except Exception as e: print(f"fail {url}: {e}") await asyncio.sleep(2) await browser.close() asyncio.run(main())几个关键参数值得单独说。wait_until="networkidle"是等网络请求静默下来,这一步比单纯等几秒可靠得多,因为不同文章的图片数量差别很大。print_background=True对应打印对话框里的"背景图形",少了它代码高亮就没了。scale=0.9是全局缩放,和前面手动打印时的建议一致。两个sleep是我踩坑之后加的:连续快速请求同一站点很容易被限流,间隔两秒能显著降低失败率。至于那几个折叠按钮的选择器,我写的是常见命名,实际用之前你必须打开开发者工具确认一遍,因为这类类名会不定期调整。
4.3 文件命名和目录分层,别等到五百个文件才后悔
文件名混乱是归档最大的敌人。我的规则是"序号_标题关键词_日期",比如012_环境配置与依赖安装_20240411.pdf。序号保证目录里的顺序稳定,标题关键词保证肉眼可见,日期保证你以后能看出这份资料的新旧。
目录按"主题/子主题"两层分就够了,超过三层你会懒得点进去。比如:
tech-archive/ embedded/ mcu-config/ peripheral-driver/ backend/ database/ deployment/ tooling/ build-system/提示:别用中文特殊符号做文件名,跨设备同步和某些命令行工具会出问题。空格也尽量换成下划线。
5. 导出之后的验收:六个必须过一遍的检查点
很多人转完就直接扔进文件夹了,等到真正需要用的那天才发现缺图或者文字选不中。我现在的习惯是每转一批,抽几份过一遍验收清单。
5.1 六个检查项的具体标准
| 检查项 | 合格标准 | 常见不合格表现 |
|---|---|---|
| 图片完整性 | 全部插图正常显示 | 大面积空框、灰色占位 |
| 代码高亮 | 底色和语法着色保留 | 全黑白,或底色变纯黑 |
| 代码完整性 | 无省略号截断 | 中间出现"展开更多"或断行 |
| 横向内容 | 无右侧裁切 | 表格右边一列消失 |
| 文字可选中 | 光标能选中正文 | 整页是图片,选不中 |
| 文件体积 | 单篇 1MB 到 5MB | 超过 30MB 或者只有几十 KB |
最后一项特别值得说。"只有几十 KB"往往意味着图全丢了,"超过 30MB"则通常是某张未压缩的大图被原样嵌入。我遇到过一篇带四十多张截图的教程,导出后 68MB,翻页卡顿,后来用 PDF 编辑器的图片压缩功能降到 4MB,屏幕上完全看不出差别。
5.2 文字图层:为什么有的 PDF 搜不了
如果 PDF 是用浏览器原生打印生成的,正文一定是矢量文字,可以选中、可以搜索、可以复制。但如果你走的是一些"截图拼接成 PDF"的野路子,整份文件就是一堆位图,搜索功能直接废掉,体积还会暴涨。这也是我一直推荐浏览器原生打印而不是截图方案的原因——同样是存档,能不能搜索是质变。
顺带说一个细节:代码里的连字符和引号有时会被排版规则换成全角字符,导致你复制出来粘贴运行会报错。验收时随手复制两行代码到编辑器里跑一下,能提前发现这个问题。
5.3 公式、图表和宽表格的还原度
技术文章里的数学公式和架构图是最容易被破坏的部分。公式如果原本是用脚本渲染的,打印时可能变成一堆乱码或者位置错位;宽表格和横向流程图在 A4 宽度下几乎必然被裁。
对付宽表格,除了前面提到的缩放和pre-wrap,还有一个办法:把纸张方向临时改成横向,只对这一页生效。浏览器打印支持按页设置,虽然操作稍麻烦,但对那几张确实很宽的表,是唯一不丢内容的选择。至于架构图,如果导出后线条丢失或者文字重叠,我的做法是单独把那张图另存为 PNG,和 PDF 放在同一个目录里,文件名保持一致。看起来不够优雅,但实用。
6. 存下来之后:让这些 PDF 真正能被用起来
归档不是终点,如果五百份 PDF 躺在硬盘里从来打不开,那前面的工作全是白费。这几年我摸索出几个让资料库保持"活着"的习惯,分享给你。
6.1 给资料库建一份索引,比什么都重要
我用的是一份 Markdown 索引文件,每次新增 PDF 就补一行,记录文件名、主题、来源和一句话备注。听起来很笨,但它解决了最关键的问题:三个月后你根本不记得自己存过什么。有了索引,用编辑器全局搜索就能找到,比在文件管理器里翻快得多。索引格式大概是这样:
- [012] 环境配置与依赖安装 | embedded/mcu-config | 2024-04-11 | 记录了交叉编译工具链的坑 - [013] 串口通信调试记录 | embedded/peripheral-driver | 2024-04-13 | 含示波器波形图6.2 和笔记工具联动的两种做法
第一种是把 PDF 当成附件挂进笔记,笔记里只写"这篇解决了什么问题",正文留在 PDF 里。第二种是把 PDF 里最关键的几段代码和结论摘抄到笔记,PDF 作为原始出处备查。我两种都在用:原理性的内容走第一种,操作性内容走第二种,因为操作步骤我迟早要复制出来用,提前摘一遍省事。
如果你用的是支持 PDF 批注的阅读器,还有个额外收益:读的时候顺手高亮和写批注,几个月后回看,那些标记就是你自己写的第二版笔记,比原文章有用得多。
6.3 自用归档的边界感
最后必须提一句。把公开的技术文章转成 PDF 放在自己电脑上阅读、做笔记、打印,这是正常的学习行为。但如果要转发给别人、发到群里、或者传到公开网盘,就涉及作者的权利了,尤其是有明确版权声明或者付费专栏的内容。我的原则很简单:只存自己看得,不在任何公开渠道二次分发,引用的时候注明出处和原文链接。这个分寸守住了,归档这件事才能做得长久。
对了,还有一个我用了很久的小技巧:每份 PDF 存下来之后,我会在文件的元数据里补上原文标题和链接。浏览器导出的 PDF 元数据基本是空白的,用任意 PDF 编辑器填一下,以后就算文件名被改乱了,点开属性还能顺藤摸瓜找回原文。这一步只花十秒钟,但在我身上至少救回过七八份"不知道从哪来的"文件。