最近熱衷於看輕小說,奈何某些網站樣式排版屬實糟糕,移動端體驗極度不友好,實在無法忍受,於是希望能將網站內容爬取下來制作成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
