Watch at Ease看见世界,读懂生活。

科技 · 实用指南

EPUB 报“no item named”?改书前先追查缺失的 ZIP 成员

缺脚本、缺章节和大小写不符,都可能触发同一种 KeyError。四份受控样本说明:ZIP 检查通过,不代表 EPUB 内容完整。

原创示意图:四份原创 EPUB 均通过 ZIP CRC 检查,但只有对照样本能被 EbookLib 0.20.0 加载;其余分别在脚本、spine 章节或大小写不符路径上失败。
原创示意图:四份原创 EPUB 均通过 ZIP CRC 检查,但只有对照样本能被 EbookLib 0.20.0 加载;其余分别在脚本、spine 章节或大小写不符路径上失败。 Watch at Ease

EPUB 报错称某个路径没有对应条目,说明一次压缩包成员查找失败,并不能说明缺的是章节、脚本,还是引用拼写有误。修改前,先保留原文件与报错路径全文。

我们在 Python 3.12.14、EbookLib 0.20.0、lxml 6.1.3 中测试四份原创本地 EPUB 3。对照样本能加载;移除清单声明的脚本、移除书脊中的第二章,或把章节引用改一个大写字母,均触发 KeyError。四份压缩包的 ZipFile.testzip() 全部通过,审计期间输入文件哈希均未改变。

这是包内查找测试,不能证明对照样本完全符合 EPUB 标准,也不能证明设备会正确显示这些文件。我们没有运行 EPUBCheck、Calibre、EpubSplit 或图形阅读器。本文提供的实际补充,是把同一异常分流到不同排查方向的对照。

从包文档沿引用追到压缩包

先列出压缩包成员,不解压覆盖文件。Python 命令为 python -m zipfile -l book.epub。读取 META-INF/container.xml,确定包文档位置。样本中是 OEBPS/package.opf,因此 manifest 的 Text/chapter2.xhtml 指向 OEBPS/Text/chapter2.xhtml。

记录 manifest ID、原始 href、媒体类型、解析后的成员名称、是否精确存在,以及 spine 位置。W3C 规定包文档是其中 URL 的基准,容器名称区分大小写。测试仅使用简单本地路径;远程资源、编码名称、片段、多呈现版本或错误 XML,应遵循相应 URL 与包规则,不能凭猜测拼接文件系统路径。

区分正文缺失与引用不匹配

缺章节样本中,c2 指向不存在的 OEBPS/Text/chapter2.xhtml,位于 spine 第 2 位。不要补一个空章节,或跳过异常后把结果标为完整。应取得更正后的源文件,或由获授权的制作者恢复真实正文及相关链接。

大小写不符样本中,manifest 请求 Text/Chapter1.xhtml,压缩包实际包含 Text/chapter1.xhtml。审计列出大小写不同的候选项,没有自动选取或重命名。定向修正前,须核对全部引用及制作者原意;近似匹配是线索,不是等价证明。

不在 spine 中的脚本,也不能自动丢弃

移除 OEBPS/js/unused.js 同样让 EbookLib 停止,尽管两份 spine 章节仍在压缩包内。在合成样本里,我们知道脚本未被使用,因为每个文件都是我们创建的;他人书籍中不在 spine 的脚本,仍可能被正文引用或支撑某项功能。

追查依赖关系,请制作者恢复资源,或明确移除过时声明及其引用。不要把缺失的本地文件归为允许的远程资源,不要下载同名脚本补进去,也不要捕获所有 KeyError 后继续。上游问题 281 已经说明此类 manifest 加载失败,这不是本文新发现的机制。

分别验收 ZIP、出版物结构与最终交付

testzip() 检查已存成员的 CRC 与文件头,不知道出版物原本应包含哪些成员。四份样本均返回 None,包括缺章节样本。对照样本被 EbookLib 加载,只说明该解析器在测试选项下接受了它,不代表完全符合 EPUB 标准。

Calibre 文档中的 Tools → Check book 已能报告断链和 OPF 问题,W3C 也建议使用 EPUBCheck 等符合性检查器。对工作副本使用这些既有方法,并保留报告。获授权修正后,重跑最初失败的操作,核对预期章节顺序与正文,再测试所需阅读流程。保留原件并记录未解决资源;重试变绿,不能单独证明文字和功能都没有丢失。

原创示意图:沿 container.xml、包文档、manifest ID 与 href,追到精确的包内成员和 spine 位置;成员缺失或近似候选都需要记录决定,不能自动跳过。
原创示意图:沿 container.xml、包文档、manifest ID 与 href,追到精确的包内成员和 spine 位置;成员缺失或近似候选都需要记录决定,不能自动跳过。 Watch at Ease