只要你的 PDF 是文字型(内嵌可选中文本,而非纯扫描图片),就能把它变成 一个可选中、可高亮、可写批注的网页——前后端全本地、零第三方服务、零 CDN。
把教材 / 论文 / 文档丢进去,网页里像在 PDF 里一样选中文字,一键高亮、加下划线、 写笔记;刷新不丢,还能导出一份自包含 HTML(单文件,发给别人也能继续批注)。
| 传统做法 | 本工具 |
|---|---|
| 截图 OCR、满屏 PNG,文件数爆炸 | 只抽文字 + 坐标,一本书 ≈ 2 个 JSON,磁盘几乎零负担 |
| 批注锁死在 PDF 阅读器里 | 批注存网页,可导出、可分享、可继续编辑 |
| 依赖网盘 / 在线 SaaS,隐私外泄 | 全程本地,PDF 抽取完即删源文件 |
| 文字不可选中、复制麻烦 | 文字原生可选中、可复制 |
💡 设计哲学:不往你电脑塞垃圾、不让文件数疯涨。PDF 源文件上传后立即抽取并丢弃, 磁盘上只留极小的结构化数据。
# 1) 装依赖(只需一个)
pip install -r requirements.txt
# 2) 启动(纯标准库,无需 Flask / 数据库)
python app.py
# 默认 http://127.0.0.1:8000
# 想让同局域网访问:python app.py --host 0.0.0.0 --port 9000
# 3) 打开浏览器,上传一个文字型 PDF,开始批注需要 Python 3.8+。除了 pymupdf 没有别的运行依赖。
- 上传:首页拖入 / 选择任意文字型 PDF。
- 阅读 + 批注:
- 直接用鼠标选中一段文字,浮出工具条 → 选「高亮 / 下划线 / 批注」。
- 「批注」会弹出输入框,写下你的笔记;批注会落到右侧边栏,可随时编辑、删除。
- 顶部滑块缩放页面(0.5×–3×),长文档自动懒渲染,不卡。
- 标注持久化:在线版的批注存于服务端
data/,刷新、重开浏览器都不丢。 - 导出:点「导出 HTML」→ 得到单个
.html文件,自带全部文字、版式与批注; 双击即用,离线可批注,可直接发给同学 / 同事继续标注。
⚠️ 仅支持文字型 PDF。纯扫描版(无内嵌文字)会提示「无可抽取文本」, 这类请用 OCR 工具先转成文字 PDF 再上传。
.
├── app.py # 后端:纯标准库 HTTP 服务(上传 / 读取 / 批注 / 导出)
├── pdftext.py # PDF 文本+版式抽取(PyMuPDF),输出紧凑 JSON
├── static/
│ ├── index.html # 上传页 + 阅读批注页(双视图,同一套 JS)
│ ├── style.css # 样式
│ └── app.js # 前端逻辑:渲染 / 选区→批注映射 / 侧栏 / 导出
├── requirements.txt # 仅 pymupdf
├── poster.pdf # 一张小样张(演示用,已跟踪)
└── data/ # 运行时生成:各文档的抽取结果 + 批注(gitignore,不进仓库)
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /api/info |
服务信息 |
| GET | / 或 /index.html |
前端页面 |
| POST | /api/upload |
原始 PDF 字节 + 头 X-Filename,抽取后返回 {id, title, page_count} |
| GET | /api/doc/<id> |
文档抽取结果(文字 span / 图片 / 元信息) |
| GET | /api/docs |
已上传文档列表 |
| GET/POST | /api/annotations/<id> |
读取 / 覆盖保存批注(JSON 数组) |
| GET | /api/export/<id> |
导出自包含可批注 HTML(单文件) |
| DELETE | /api/doc/<id> |
删除文档及其批注 |
导出的独立 HTML 用
localStorage存批注,无需后端即可使用。
- 后端:Python 标准库
http.server(线程安全),无框架、无数据库。 - 抽取:PyMuPDF 1.24+(
fitz),逐 span 抽取文字、字号、字重、颜色、坐标。 - 前端:原生 HTML / CSS / JS,无构建步骤、无 npm 依赖。
- 存储:每个文档一个目录
data/<id>/,含doc.json与annotations.json。
MIT License。