1. 程式人生 > 其它 >EPUB檔案格式簡單解析

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檔案和小說正文檔案以及封面。

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 id="navPoint-1" playOrder="1">
  <navLabel>
    <text>插圖</text>
  </navLabel>
  <content src="chapter0001.xhtml"/>
</navPoint>

整書的目錄,每個navPoint代表目錄中的一項,包含標題和檔案路徑。

一個EPUB有以上這些檔案就能被識別,通過建立檔案然後壓縮就可以完成一個EPUB檔案的建立。

完成的專案

最後提一下已經完成的開頭的專案: linovel-downloader