Beancount 旧版文档自动化转换工具链:从 Google Docs 批量导出 PDF、Markdown 与 RST 的完整实践

发布时间:2026/9/17 21:11:06
Beancount 旧版文档自动化转换工具链:从 Google Docs 批量导出 PDF、Markdown 与 RST 的完整实践 Beancount 旧版文档自动化转换工具链从 Google Docs 批量导出 PDF、Markdown 与 RST 的完整实践【免费下载链接】beancountBeancount: Double-Entry Accounting from Text Files.项目地址: https://gitcode.com/GitHub_Trending/be/beancount本文基于 Beancount 仓库中experiments/docs_rst/old/目录下的实验性与遗留脚本系统讲解这套以 Google Docs 为唯一事实来源、自动下载并转换为离线文档的工具链。读者将掌握其整体工作流索引发现 → 批量下载 → 格式转换 → PDF 合并、核心工具库docs.py中认证、缓存、链接枚举等关键实现以及单个文档经 pandoc 转换到 Markdown 的细节与格式选型经验并了解如何通过 Makefile 将转换结果集成进静态文档站构建流程。这套工具要解决什么问题Beancount 的早期文档体系以 Google Docs 为源但发布时需要产出 PDF、Markdown、reStructuredTextRST等离线格式以便生成静态站点文档或离线手册。手动逐份导出显然不可行于是就有了本目录下的自动化脚本。其核心诉求记录在 experiments/docs_rst/README 中原始文档始终保留在 Google Docs每次发布前自动完成转换转换产物再集成回 Beancount 的静态文档站。整套工具链围绕三个核心概念展开Google Drive API 集成通过apiclientGoogle API Python 客户端检索、列出并导出文档认证采用服务账户service account方式基于索引的文档发现先从 Drive 中定位名为 Beancount - Index 的索引文档解析其中的链接得到全部相关文档章节多格式转换管线支持 DOCX、PDF、ODT、HTML、TXT、RTF 等导出格式并借助pandoc、pdftk做进一步加工如 DOCX → Markdown、多个 PDF 合并。目录结构与整体工作流experiments/docs_rst/old/目录下共有 5 个文件职责划分清晰文件角色docs.py共享工具库认证、缓存、索引发现、下载、PDF 合并download_docs.py批量下载索引中全部关联文档可按需合并 PDFconvert_doc.py下载并转换单个 Google Doc经 pandoc 产出 Markdownconvert_filter_docx.pypandoc 过滤器用于定制 DOCX 转换行为docs_test.py工具库的单元测试端到端流程可以概括为四步认证用服务账户凭据换取授权的 HTTP 客户端发现在 Drive 中检索Beancount - Index文档导出其 HTML 并解析出全部docs.google.com/document/d/...链接下载对每个文档 id 导出为目标 MIME 类型的文件写入本地目录后处理若目标为 PDF则用pdftk将所有 PDF 合并为一个文件若目标为 Markdown则用 pandoc 加自定义过滤器转换。核心工具库 docs.py 源码剖析docs.py 是整套工具链的基石其模块头注释明确写着Utility functions to download and convert Google Docs下载并转换 Google Docs 的工具函数版权与许可证信息显示其为 GNU GPLv2维护周期跨越 2014 至 2025 年。Cache 类远程调用的持久化缓存远程工作场景下同一文档可能被反复下载Cache 类 专门解决这一问题。它的设计很有借鉴价值构造时接收缓存文件名与delegate_factory工厂内部用shelve打开持久化存储通过__getattr__将任意属性访问如files.list包装为Cache.MethodMethod.__call__把(方法名, 位置参数, 排序后的关键字参数)整体 pickle 后取 MD5 摘要作为缓存键命中则直接返回缓存值未命中才真正调用 Google API 并将结果写回 shelve返回的ExecuteWrapper模拟 Google API 客户端的.execute()语义使得调用方无需感知缓存层存在。从实现看这是一种透明方法级缓存模式调用方照常写files.list(q...).execute()缓存逻辑全部隐藏在代理之后且日志会输出Cache miss for digest便于排查。服务账户认证get_auth_via_service_account 从环境变量HOME下的.google-apis-service-account.json读取服务账户 JSON 密钥通过oauth2client.service_account.ServiceAccountCredentials.from_json_keyfile_name构造凭据再用httplib2.Http()授权。它返回(credentials, http)二元组供discovery.build构建 Drive v3 服务。注意源码第 18 行留有 TODO 注释oauth2client已被官方弃用这是一处典型的遗留代码标志。索引文档的定位与链接枚举find_index_document 通过files.list(qname Beancount - Index)精确检索索引文档若匹配数量不等于 1 会抛出ValueError这是对数据一致性的强校验。enumerate_linked_documents 先将索引文档导出为text/html再用正则https?://docs.google.com/document/d/([^/;])扫描全部文档链接去重后返回文档 id 列表索引自身也包含在内。批量下载与 CONVERSION_MAPdownload_docs 接收文档 id 列表与输出目录为每个文档执行files.get取元数据用于命名与files.export取内容。文件名经过清洗re.sub([^A-Za-z0-9-], _, name)将非法字符替换为下划线再依次规整连续下划线与_-_序列。下载后校验文件大小空文件会被判为下载失败并跳过同时记录 error 日志。格式与 MIME 类型、后处理函数的映射关系集中在 CONVERSION_MAP扩展名MIME 类型后处理htmltext/html无txttext/plain无rtfapplication/rtf无pdfapplication/pdfconvert_pdf合并odtapplication/vnd.oasis.opendocument.text无docxapplication/vnd.openxmlformats-officedocument.wordprocessingml.document无pdftk 合并多个 PDFcollate_pdf_filenames 构造pdftk file1 file2 ... cat output out命令并用subprocess.Popen执行捕获FileNotFoundError/PermissionError并给出pdftk is probably not installed的友好提示若pdftk返回码非零则抛出IOError。批量下载脚本 download_docs.pydownload_docs.py 的模块 docstring 描述了其目标把 Google Drive 上所有 Beancount 文档下载下来并烘焙成一个漂亮的 PDF同时留下 TODO后续计划用 Pandoc 将全部文档转换为原生格式并编写自定义过滤器以更好地识别代码块再输出为 Markdown 等格式。命令行用法脚本通过argparse接收三个参数./download_docs.py [extension] [output] [--cache CACHE]extension必填位置参数可选值即CONVERSION_MAP的键html、txt、rtf、pdf、odt、docx默认pdfoutput必填位置参数输出文件/目录路径默认值虽为None但下方os.makedirs(args.output)会实际使用--cache可选指定服务缓存文件路径用于离线工作。执行流程main()download_docs.py的核心逻辑如下配置日志级别为 INFO定义get_service()请求https://www.googleapis.com/auth/drive作用域经服务账户认证后discovery.build(drive, v3, httphttp)返回service.files()若传了--cache用docs.Cache包装服务对象否则直接用原始服务调用find_index_document与enumerate_linked_documents得到全部文档 id从CONVERSION_MAP取出后处理函数创建输出目录download_docs完成下载若后处理函数存在即 PDF 场景则调用之合并文件最后打印输出位置。单文档转换 convert_doc.py 与 pandoc 过滤器convert_doc.py 面向只处理一个文档的场景模块注释点明了动机Google 自带的 Markdown 导出质量不足因此需要下载多种导出格式再经 Pandoc 转换以得到最忠实的 Markdown。其pandoc()辅助函数convert_doc.py构造命令pandoc -f informat -t markdown --filter convert_filter_docx.py filename其中--filter指向同目录下的 convert_filter_docx.py。该过滤器基于pandocfilters.toJSONFilter实现目前只关注BlockQuote节点并打印到 stderr——从实现看这是一个最小骨架用于后续定制多余引用块等转换细节对应notes-about-formats.txt中docx 转换会带出多余 blockquote的调研结论。main()convert_doc.py接收docid、output与--cache参数对同一文档分别以docx、odt、txt、pdf、html、rtf六种格式下载到临时目录其中下载 DOCX 后调用 pandoc 转换的代码被注释保留# native pandoc(filenames[0], docx)说明多格式并行下载是广撒网、按需取策略不同格式各自携带不同信息如 DOCX 结构最好但缺标题HTML 有标题却混入大量样式最终拼接出完整结果。格式选型notes-about-formats 的调研结论notes-about-formats.txt 记录了作者对 Google Drive 导出格式的系统性评估是理解本工具链设计取舍的第一手材料可下载格式html、txt、rtf、odt、pdf、docx、epubpandoc 可读取的格式html、odt、docx、epub实测观察HTML 与 epub 输出很糟糕混入大量样式元素ODT 解析出的结构信息很少章节标题甚至不被识别为标题而只是锚点标记DOCX 是质量最好的选择——但它不产出标题因此需要下载多种格式各取所长含有多余的 blockquote且代码块无法被识别、账户名前的空白会丢失输出到 HTML时结果需要被拼接进带 UTF-8 编码的 HTML 包装器中。这些发现直接对应了代码中的设计convert_doc.py为什么要同时下载六种格式、pandoc 过滤器为什么要处理BlockQuote。单元测试与跳过机制docs_test.py 使用unittest.mock.MagicMock模拟 Google API 服务对象验证find_index_document能从files().list().execute()的返回中正确提取文档 id。值得注意的工程实践是整个测试类用unittest.skipIf(apiclient is None, ...)装饰——若环境未安装google-api-python-client则自动跳过保证在无 Google 依赖的 CI 环境中测试套件依然能通过。与构建流程的集成Makefile 三阶段目录级的 Makefile 把工具链串成了三个可复现的阶段download: # ./download_docs.py $(CONVERT_DOCS) —— 下载全部文档 convert: # ./convert_docs.py $(CONVERT_DOCS) —— 转换为 Markdown copy: # ./copy_docs.py $(CONVERT_DOCS) $(RST_DOCS) —— 拷贝到静态文档源其中CONVERT_DOCS$(HOME)/docs是下载产物目录RST_DOCS$(HOME)/p/beancount-docs是静态文档生成器源码目录拷贝后即可用 Sphinx 构建并检查效果。这印证了 README 的定位转换的最终目的是把产物集成进 Beancount 的静态文档站其对应生成源即aumayr.github.io/beancount-docs-static而 Google Docs 始终保持为pristine source原始权威来源。适用前提与遗留限制依赖外部工具PDF 合并依赖pdftk缺失时脚本会明确报错退出Markdown 转换依赖pandoc与pandocfilters认证文件必须在$HOME/.google-apis-service-account.json提供服务账户密钥并授予 Drive 作用域oauth2client已弃用源码 TODO 已注明实验性定位本目录属于experiments/docs_rst/old/脚本自带experimental and legacy定位与同目录下更新的 convert_docs.py、copy_docs.py 等并存README 中列出的静态站点链接是 2016 年前后的历史产物如今 Beancount 文档已主要内置于仓库本体如 docs.md 及各子模块的docs.md。总体而言这套旧工具链的价值在于它以不足 300 行的代码完整示范了Google Docs 权威源 Drive API 自动化导出 pandoc 二次加工 静态站构建的文档发布流水线其 Cache 缓存模式、索引发现机制与格式选型方法论对任何以云文档为源、需要自动发布离线文档的项目都具有直接的参考意义。【免费下载链接】beancountBeancount: Double-Entry Accounting from Text Files.项目地址: https://gitcode.com/GitHub_Trending/be/beancount创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考