EPUB文件格式简单解析
最近热衷于看轻小说,奈何某些网站样式排版属实糟糕,移动端体验极度不友好,实在无法忍受,于是希望能将网站内容爬取下来制作成EPUB格式的电子书。
抛开爬取网站内容不谈,通过解析EPUB文件后,大致掌握了EPUB文件的基本格式内容。
EPUB文件结构
EPUB文件本质是一个zip压缩文件。
将EPUB文件后缀改为zip解压即可一窥真相。
使用tree命令查看整个EPUB文件的目录结构和文件,其中部分文件被省略。
mimetype
│
├─META-INF
│ container.xml
│
└─OEBPS
│ chapter0001.xhtml
│ chapter0002.xhtml
│ chapter0003.xhtml
│ chapter0004.xhtml
│ chapter0005.xhtml
│ chapter0006.xhtml
| ...
│ content.opf
│ toc.ncx
│
└─images
39655.jpg
39656.jpg
39657.jpg
...
固有文件
- mimetype
- META-INF/container.xml
mimetype
mimetype是一个文本文件,内容固定为:application/epub+zip
META-INF/container.xml
其中rootfile的属性full-path指定了此书的OPF文件路径。
<?xml version="1.0" encoding="UTF-8"?>
<container xmlns="urn:oasis:names:tc:opendocument:xmlns:container" version="1.0">
<rootfiles>
<rootfile full-path="OEBPS/content.opf" media-type="application/oebps-package+xml"/>
</rootfiles>
</container>
OPF
Open Package Format(OPF),即包文件格式,其主要功能是用于组织 OPS 文档和提供相应的导航机制,并形成一个开放式的基于 XML 的打包文档,该文档的后缀名为 “.opf” 。
通过META-INF/container.xml
即可定位到OPF文件。
查看文件内容,可以比较容易猜测每部分的作用。
<?xml version="1.0" encoding="UTF-8"?>
<package xmlns="http://www.idpf.org/2007/opf" unique-identifier="bookId" version="2.0">
<metadata xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:opf="http://www.idpf.org/2007/opf">
<dc:identifier id="bookId">urn:uuid:9bfb698f-dfa3-45ca-bea4-d0fbc2ead4f3</dc:identifier>
<dc:language>en</dc:language>
<dc:title>第一卷 虚伪的王国</dc:title>
<meta content="cover-image" name="cover"/>
</metadata>
<manifest>
<item href="toc.ncx" id="ncx" media-type="application/x-dtbncx+xml"/>
<item href="chapter0001.xhtml" id="chapter0001.xhtml" media-type="application/xhtml+xml"/>
<item href="chapter0002.xhtml" id="chapter0002.xhtml" media-type="application/xhtml+xml"/>
<item href="chapter0003.xhtml" id="chapter0003.xhtml" media-type="application/xhtml+xml"/>
<item href="chapter0004.xhtml" id="chapter0004.xhtml" media-type="application/xhtml+xml"/>
<item href="chapter0005.xhtml" id="chapter0005.xhtml" media-type="application/xhtml+xml"/>
<item href="chapter0006.xhtml" id="chapter0006.xhtml" media-type="application/xhtml+xml"/>
...
<item href="images/39655.jpg" id="cover-image" media-type="image/jpeg"/>
</manifest>
<spine toc="ncx">
<itemref idref="chapter0001.xhtml"/>
<itemref idref="chapter0002.xhtml"/>
<itemref idref="chapter0003.xhtml"/>
<itemref idref="chapter0004.xhtml"/>
<itemref idref="chapter0005.xhtml"/>
<itemref idref="chapter0006.xhtml"/>
...
</spine>
</package>
metadata
EPUB文件元数据
dc:identifier
书本的唯一标识符,需要和ncx文件中的identifier一致,虽然不一致也没问题。
dc:language
书本使用的语言 不是很重要。
dc:title
整本书的书名,重要性不言而喻。
meta
通过对部分EPUB进行解压,目前只发现设置封面的meta
<meta content="cover-image" name="cover"/>
一般没有需求不更改,如何设置封面查看下文。
manifest
整本书的清单文件,一般会列出ncx文件和小说正文文件以及封面。
ncx文件是必须的,它定义了书籍的目录,具体格式查看下文。
封面是可选的,不过EPUB没有封面和插图就没有灵魂。
item
清单文件项目。
- href 文件的相对路径
- id 项目ID
- media-type 文件的MIME类型
正文网页文件
一般格式都为XHTML,可以使用样式图片音频各种各样的资源。
指定封面图片
- metadata中包含
name
为cover的meta
标签
<meta content="cover-image" name="cover"/>
- manifest中包含id为上述meta的content属性的item
- 通过设置item的
href
即可指定封面路径
<item href="images/39655.jpg" id="cover-image" media-type="image/jpeg"/>
spine
翻译成中文就是书脊,通过引用的顺序来指定阅读顺序。
例如上文文件依次列出了chapter0001、chapter0002等,阅读完chapter0001就会开始阅读chapter0002。
itemref
引用的manifest中的文件,只需要引入正文网页文件。
- idref 需要与manifest中itme的id对应 代表此文件
- linear 表明该项是作为线性阅读顺序中的一项,与先后顺序无关,默认为yes
NCX
NCX是Navigation Content eXtended的缩写,用于表示本书的目录。
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<ncx xmlns="http://www.daisy.org/z3986/2005/ncx/">
<head>
<meta content="urn:uuid:9bfb698f-dfa3-45ca-bea4-d0fbc2ead4f3" name="dtb:uid"/>
<meta content="1" name="dtb:depth"/>
<meta content="0" name="dtb:totalPageCount"/>
<meta content="0" name="dtb:maxPageNumber"/>
</head>
<docTitle>
<text>第一卷</text>
</docTitle>
<navMap>
<navPoint id="navPoint-1" playOrder="1">
<navLabel>
<text>插图</text>
</navLabel>
<content src="chapter0001.xhtml"/>
</navPoint>
<navPoint id="navPoint-2" playOrder="2">
<navLabel>
<text>序章</text>
</navLabel>
<content src="chapter0002.xhtml"/>
</navPoint>
<navPoint id="navPoint-3" playOrder="3">
<navLabel>
<text>第一章 前世</text>
</navLabel>
<content src="chapter0003.xhtml"/>
</navPoint>
<navPoint id="navPoint-4" playOrder="4">
<navLabel>
<text>第二章 异世界</text>
</navLabel>
<content src="chapter0004.xhtml"/>
</navPoint>
<navPoint id="navPoint-5" playOrder="5">
<navLabel>
<text>第三章 冤罪</text>
</navLabel>
<content src="chapter0005.xhtml"/>
</navPoint>
<navPoint id="navPoint-6" playOrder="6">
<navLabel>
<text>第四章 入学王立学院</text>
</navLabel>
<content src="chapter0006.xhtml"/>
</navPoint>
<navPoint id="navPoint-7" playOrder="7">
<navLabel>
<text>第五章 五年后</text>
</navLabel>
<content src="chapter0007.xhtml"/>
</navPoint>
<navPoint id="navPoint-8" playOrder="8">
<navLabel>
<text>第六章 野外演习</text>
</navLabel>
<content src="chapter0008.xhtml"/>
</navPoint>
<navPoint id="navPoint-9" playOrder="9">
<navLabel>
<text>第七章 虚伪的真相</text>
</navLabel>
<content src="chapter0009.xhtml"/>
</navPoint>
<navPoint id="navPoint-10" playOrder="10">
<navLabel>
<text>末章</text>
</navLabel>
<content src="chapter0010.xhtml"/>
</navPoint>
<navPoint id="navPoint-11" playOrder="11">
<navLabel>
<text>后记</text>
</navLabel>
<content src="chapter0011.xhtml"/>
</navPoint>
<navPoint id="navPoint-12" playOrder="12">
<navLabel>
<text>特典 淑女空腹状态</text>
</navLabel>
<content src="chapter0012.xhtml"/>
</navPoint>
<navPoint id="navPoint-13" playOrder="13">
<navLabel>
<text>特典 雾雨茫茫相思相爱伞</text>
</navLabel>
<content src="chapter0013.xhtml"/>
</navPoint>
<navPoint id="navPoint-14" playOrder="14">
<navLabel>
<text>特典 贵族千金们的茶会</text>
</navLabel>
<content src="chapter0014.xhtml"/>
</navPoint>
</navMap>
</ncx>
meta
dtb:uid
<meta content="urn:uuid:9bfb698f-dfa3-45ca-bea4-d0fbc2ead4f3" name="dtb:uid"/>
这个和opf中的dc:identifier应该保持一致,不一致倒也没什么问题。
depth、totalPageCount和maxPageNumber
<meta content="1" name="dtb:depth"/>
<meta content="0" name="dtb:totalPageCount"/>
<meta content="0" name="dtb:maxPageNumber"/>
对于电子书不需要进行修改,使用这几个值就OK。
docTitle
<docTitle>
<text>第一卷</text>
</docTitle>
姑且认为应该与opf中的dc:title一致,书名以opf中的为准。
navPoint
<navPoint id="navPoint-1" playOrder="1">
<navLabel>
<text>插图</text>
</navLabel>
<content src="chapter0001.xhtml"/>
</navPoint>
整书的目录,每个navPoint代表目录中的一项,包含标题和文件路径。
一个EPUB有以上这些文件就能被识别,通过创建文件然后压缩就可以完成一个EPUB文件的创建。
完成的项目
最后提一下已经完成的开头的项目: linovel-downloader
EPUB文件格式简单解析的更多相关文章
- MP4文件格式的解析
MP4文件格式的解析,以及MP4文件的分割算法 mp4应该算是一种比较复杂的媒体格式了,起源于QuickTime.以前研究的时候就花了一番的功夫,尤其是如何把它完美的融入到视频点播应用中,更是费尽了心 ...
- 【文件格式探究】EP.1 对ePub文件格式的初探
这是"文件格式探究"专题的第 1 期--初探 "ePub" 文件格式.这个专题将会给各位读者呈现笔者探索各种文件格式的过程,具体则是文件的内容是如何呈现出来的. ...
- 对 cloudwu 简单的 cstring 进行简单解析
题外话 以前也用C写过字符串,主要应用的领域是,大字符串,文件读取方面.写的很粗暴,用的凑合着.那时候看见云风前辈的一个开源的 cstring 串. 当时简单观摩了一下,觉得挺好的.也没细看.过了较长 ...
- 基于DOM的XSS注入漏洞简单解析
基于DOM的XSS注入漏洞简单解析http://automationqa.com/forum.php?mod=viewthread&tid=2956&fromuid=21
- PCM文件格式简单介绍
PCM文件格式简单介绍 PCM文件:模拟音频信号经模数转换(A/D变换)直接形成的二进制序列,该文件没有附加的文件头和文件结束标志.Windows的Convert工具能够把PCM音频格式的文件转换成M ...
- 15.5 自学Zabbix之路15.5 Zabbix数据库表结构简单解析-其他 表
点击返回:自学Zabbix之路 自学Zabbix之路15.5 Zabbix数据库表结构简单解析-其他 表 1. Actions表 actions表记录了当触发器触发时,需要采用的动作. 2.Aler ...
- 深度优先搜索DFS和广度优先搜索BFS简单解析(新手向)
深度优先搜索DFS和广度优先搜索BFS简单解析 与树的遍历类似,图的遍历要求从某一点出发,每个点仅被访问一次,这个过程就是图的遍历.图的遍历常用的有深度优先搜索和广度优先搜索,这两者对于有向图和无向图 ...
- List<T>集合的Sort自定义排序用法简单解析
List<T>集合的Sort自定义排序用法简单解析: 如下:一系列无序数字,如果想要他们倒序排列,则使用如下代码: 那么如何理解这段代码呢? (x,y)表示相邻的两个对象,如果满足条件:x ...
- Maven项目pom.xml文件简单解析
Maven项目pom.xml简单解析 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="h ...
随机推荐
- promise小案例
页面中有个板块,需要多张图片加载完之后才能进行显示 //页面中有个板块 需要多张图片加载完之后才能进行显示 const loadImg = (src) => { return new Promi ...
- AndroidJetpack数据处理之数据库Room和懒加载Paging
数据库工具:Room Room结构 导入依赖 app的build.gradle中开启kapt: apply plugin: 'kotlin-kapt' 并导入以下依赖: def room_versio ...
- Javascirpt 面向对象总结-继承
JS继承的实现方式 既然要实现继承,那么首先我们得有一个父类,代码如下: // 定义一个动物类 function Animal (name) { // 公有属性 this.name = name || ...
- 痞子衡嵌入式:MCUXpresso IDE下将应用程序RW段分散链接的几种方法
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是MCUXpresso IDE下将应用程序RW段分散链接的几种方法. 早期的 MCU 芯片,一般都会嵌入内部 Flash 和 RAM,并且 ...
- Appium问题解决方案(10)- Original error: Swipe did not complete successfully
背景 从搜索页面返回首页之后,执行 swipe 滑动操作,但是报错了,如上图 解决方法 只需要在第一次 swipe 之前加个 sleep,强制等待即可 备注 这种解决方案其实不好,强制等待能少用就少 ...
- Linu常用日志分析实战
日志结构分析 分析日志状态码所在位置为第九个 遍历取出第一行日志的每个字段 //取出第一行日志 awk 'NR==1{for(i=1;i<=NF;i++)print i"= " ...
- Nginx+Tomcat 负载均衡、动静分离集群
目录: 一.Nginx负载均衡实现原理 二.Nginx动静分离实现原理 三.Nginx+Tomcat 负载均衡.动静分离集群部署 一.Nginx负载均衡实现原理 1.Nginx实现负载均衡是通过反向代 ...
- go相关
mac 上build go 如果想要在centos上面执行 必须使用下面的方式 CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -o hello ...
- Android学习记录(三)——安装SQLite
这次学习安装SQLite. 一.SQLite简介 重要特性:零配置,即不需要复杂的配置即可使用 详细:https://www.runoob.com/sqlite/sqlite-intro.html 二 ...
- 记一次docker compose的低级错误
记一次docker compose的低级错误 问题 今天在学习dockercompose的时候,启动docker compose up,结果却出现异常 Error response from da ...