Daily Build

我是怎么从国标电子书库抓取 PDF 并整理书签的

国标电子书库(ebook.chinabuilding.com.cn)仅提供在线阅读 PDF 文档部分页面,未开放全文下载。std.py 通过爬取网站获取 PDF 文件,本质上是一个 WebCrawler。

抓取的 PDF 自带网站提供的书签,但格式不够规整,也没有章节分组层级。std.py bookmark 使用格式化规则处理书签,是常规工作流中的必要步骤。扫描版 PDF 需借助 std-ocr.py 半自动创建书签。std.py copy-bookmarkstd-copy-bookmark.ps1 针对另一类场景:当用户已完成书签整理,但需通过 Acrobat 等 PDF 编辑软件进行删除隐藏信息、统一图片分辨率等清理(Clean Up)操作时,原有书签可能会一并丢失,这两个工具用于将书签从备份恢复至处理后的文件。

三个脚本相互独立,按场景选用。

准备

需要 Python ≥ 3.13,建议使用 uv。两个 Python 脚本均通过文件头部的 PEP 723 元信息声明依赖,uv run 会自动建立临时环境完成安装,无需配置 pip 或 venv。

uv run std.py <command> [args]
uv run std-ocr.py

如不使用 uv,亦可手动执行 pip install httpx parsel pymupdf keyboard pyperclip 安装相应依赖。

ps1 脚本需要 PowerShell 7+。

选择指引

场景 工具
下载书籍/整理书签 std.py download / std.py bookmark
为扫描版 PDF 半自动创建书签 std-ocr.py
Acrobat 清理操作后恢复已整理的书签(单文件) std.py copy-bookmark
Acrobat 清理操作后恢复已整理的书签(批量) std-copy-bookmark.ps1("发送到"菜单)

下文按脚本逐一展开。

std.py

提供三个子命令:downloadbookmarkcopy-bookmark

download 负责抓取 PDF 文件;bookmark 实现抓取国标电子书库网站对应目录经格式化处理后覆盖 PDF 已有书签;copy-bookmark 在分页一致的两个 PDF 之间迁移书签。

Book ID 的获取

打开任意书籍详情页,URL 中 bookID= 参数对应的数字即为 Book ID:

https://ebook.chinabuilding.com.cn/zbooklib/book/detail/show?SiteID=1&bookID=12345

下文命令中的 --book-id 均指该值。

用法

# 抓取 PDF(保存为 12345.pdf)
uv run std.py download --book-id 12345

# 将当前目录下 12345.pdf 自带的书签覆盖为国标电子书库网站对应目录经格式化处理后的版本
uv run std.py bookmark --book-id 12345

# 在两个 PDF 之间迁移书签
uv run std.py copy-bookmark --source 12345.pdf --target 12345-cleaned.pdf

bookmark 子命令按约定处理当前目录下的 {book_id}.pdf,因此无需 --input 参数——download 完成后可直接接续执行 bookmark。

实现要点

std-ocr.py

国标电子书库中部分文档为扫描版,详情页缺少结构化目录,std.py bookmark 对此类书籍无效。本脚本提供半自动方案:用户对照 PDF 目录页逐条操作,按 F11 触发截屏 OCR 并自动建立书签。

该办法可广泛应用到国标电子书库外用户可收集到的各种 PDF 文档。

前置条件

用法

uv run std-ocr.py

启动后常驻后台监听以下热键:

热键 作用
F11 截屏 OCR → 自动新建书签
F12 切换文本格式化开关
Ctrl + C 退出

工作流程:

  1. 在 Acrobat 中翻至目录条目对应的实际页面(非目录页本身——书签的目标位置即为按下 F11 时当前显示的页)。
  2. 按 F11 进入 Umi-OCR 截图模式。
  3. 框选目录页中对应条目的文字,松开鼠标。
  4. 脚本依次发送 Ctrl+B 新建书签 → 将 OCR 结果粘贴至标题栏 → 回车确认。
  5. 翻至下一条对应页面,重复上述步骤。

每次建立书签均需同时满足两个条件:Acrobat 当前页停留于书签目标位置屏幕上可见对应的目录条目文字。常用的操作姿势是 Acrobat 双窗口或分屏,一侧显示目录页,另一侧翻至目标页。

关于格式化

OCR 结果常包含多余空格与换行(同一行文字识别后字与字之间常被插入空格)。默认开启的格式化逻辑包括:

  1. 删除全部空白字符;
  2. 在 "第 X 章/节/条/款/项"、"附录/附件/附表/附图/表/图 + 编号"、1.2.3 形式的数字编号、A.1.2 形式的字母编号后补一个空格;
  3. 当识别结果为单独的"条文说明"或"起草说明"时,替换为"附:条文说明""附:起草说明"——此为国标中作为附件标题的常见写法。

如需对某条目录跳过格式化(例如较长的说明性文字),可按 F12 临时关闭,处理完毕后再次按 F12 恢复。

实现要点

std-copy-bookmark.ps1

std.py copy-bookmark 单次仅处理一对文件。当需要对一批已整理书签的 PDF 统一执行 Acrobat 清理操作时,逐一调用命令的方式效率较低。本 ps1 脚本配合 Windows "发送到"菜单,可在一次操作中处理多个文件。

用法

将 ps1 置于固定位置(例如 D:\tools\std\std-copy-bookmark.ps1),修改文件顶部的 $StdScript 常量使其指向 std.py 的绝对路径,然后注册至"发送到"菜单(步骤见下节)。

注册完成后的日常工作流:

  1. 复制原 PDF:在资源管理器中执行 Ctrl+C / Ctrl+V,Windows 默认将副本命名为 xxx - 副本.pdf。该副本作为书签源文件保留备用,不应做任何修改。
  2. 在 Acrobat 中清理原文件(不带"- 副本"后缀的文件),执行删除隐藏信息、降低图片分辨率等操作并保存。此步骤将导致原文件已整理的书签丢失。
  3. 选中一个或多个清理过的 PDF(不带"- 副本"后缀的),右键 → 发送到 → ps1 快捷方式。
  4. 脚本对每个目标文件自动定位对应的 xxx - 副本.pdf 作为书签源,调用 std.py copy-bookmark,成功后删除副本

最终结果:原文件名保持不变,书签从副本迁移过来,副本被清理。

注册至"发送到"菜单

  1. std-copy-bookmark.ps1 置于固定位置,例如 D:\tools\std\std-copy-bookmark.ps1

  2. 编辑 ps1 顶部的 $StdScript 常量,使其指向实际的 std.py 绝对路径。

  3. 在 ps1 文件上右键 → 发送到 → 桌面快捷方式。

  4. 右键新建的快捷方式 → 属性 → "目标"栏改为:

    pwsh.exe -NoProfile -ExecutionPolicy Bypass -File "D:\tools\std\std-copy-bookmark.ps1"
    
  5. 重命名为合适的名称,例如"复制 PDF 书签"。

  6. Win+R 打开运行对话框,输入 shell:sendto 回车,将该快捷方式剪切至打开的文件夹中。

完成后右键任意 PDF 文件即可在"发送到"菜单中看到该项。

实现要点

配合使用

下文列出几种典型工作流的具体步骤。

工作流一:抓取 PDF 和整理书签(详情页有目录)

最常见的情况,两条命令完成:

uv run std.py download --book-id 12345
uv run std.py bookmark --book-id 12345

完成后当前目录下的 12345.pdf 即包含格式化处理后的书签。如需进一步进行章/节分组等人工调整,可直接在 Acrobat 中操作。

工作流二:扫描版 PDF

详情页缺少结构化目录,bookmark 子命令对此类书籍无效,改用 OCR 流程:

# 1. 抓取 PDF
uv run std.py download --book-id 67890

# 2. 启动 OCR 工具(常驻后台)
uv run std-ocr.py

随后在 Acrobat 中打开 67890.pdf,按 std-ocr.py 章节描述的流程逐条建立书签。完成后在 Acrobat 中按 Ctrl+S 保存。

工作流三:批量清理与书签恢复

当一批已整理书签的 PDF 需要在 Acrobat 中执行清理操作时:

  1. 在资源管理器中全选这批 PDF,Ctrl+C / Ctrl+V,得到一组 xxx - 副本.pdf
  2. 在 Acrobat 中依次打开原文件(非副本),执行清理操作并保存。此步骤将导致原文件的书签丢失。
  3. 全部清理完成后,全选所有原文件(不要选中副本),右键 → 发送到 → 复制 PDF 书签。
  4. 等待脚本执行完毕,副本自动删除,原文件书签恢复。

期间任何文件清理失败或书签复制失败,对应的副本将被保留,脚本结束时会列出,可手动处理。

故障排查

std.py download 失败或抓不到 PDF 链接。 通常是网站改版所致。检查 get_pdf_url 中的 CSS 选择器是否仍能匹配——打开试读页源码,搜索 link rel="stylesheet",对比路径结构是否变化。

std.py bookmark 抓取的目录为空或错乱。 同样可能是网站改版,应检查 get_tocdiv.m-t-md.font14 div.clearfix div::text 选择器。如仅为部分条目错位或编号识别异常,则可能是 TOC_FORMAT_RULES 覆盖不全,应补充相应正则。

std-ocr.py 按 F11 无反应。 三种可能原因:(1) Umi-OCR 未启动;(2) HTTP 服务未启用;(3) 端口非默认 1224——应修改 UMI_OCR_SERVICE 常量。控制台日志中出现 "OCR request failed" 对应 (2),出现 httpx 连接错误对应 (1) 或 (3)。

std-ocr.py 建立的书签标题正确,但目标页错误。 按下 F11 时 Acrobat 当前显示的页面即为书签指向的页面——此为 Acrobat Ctrl+B 的行为,非脚本可控。每次按 F11 前应先翻至目标页。

std-copy-bookmark.ps1 报 "std.py not found"。 修改 ps1 顶部的 $StdScript 常量为正确的路径。

std-copy-bookmark.ps1 报 "Source not found"。 检查目标文件所在目录是否存在对应的 xxx - 副本.pdf。如系统语言非简体中文,副本可能采用其他命名(例如 xxx - Copy.pdf),应修改 ps1 中构造 $sourceFile 的字符串。

下载

三个脚本可通过以下链接获取:

百度网盘:https://pan.baidu.com/s/13nvO_EvPq83FUauo96fINg(提取码 uy8v

使用前请参照"准备"一节安装 uv,并按各脚本"前置条件"小节确认 Umi-OCR、Adobe Acrobat 等依赖项已就位。


本文采用 CC BY-NC-SA 4.0 协议发布,可自由转载、修改,但需保留作者署名、不可用于商业用途、衍生作品需以相同协议发布。