概述
读取json配置文件,然后把几个xhtml文件合并为epub的python库。配置文件里包含了书名、作者、封面图像路径、各个章节的路径和章节名称。本文用到的库:
from ebooklib import epub
内容包括:
- 书脊 spine
- 封面 set_cover
要点
书脊的概念 spine
书脊这个词用的真的好,确实和实体书脊是一样的。但是应该把书横放在桌子上,书脊对着自己,这样观察就特别容易理解。如果把书立起来,顺序就会变成从右往左,这样很不舒服。一本书,从上往下(和写代码的顺序一样,看起来像一个列表)依次是:
- 封面
- 简介
- 目录页(你把它当成一个名字为“目录页”的章节即可,以免和后面的目录专用概念混淆)
- 第一章
- 第二章(略)
- 结束语
- 引用
- 感谢
- 封底
以上这些并不都是必须的,就算只有一章也没关系,仿佛一页A4纸打印好了扔在那里。
以下的函数,动态地创建了一个前言页面intro.xhtml。然后把’nav’和这个前言页面,加入到书脊。具体解释详见程序的注释
def add_intro_page(self):
# title是页面的<title></title
intro_page = epub.EpubHtml(title='-前言-', file_name='intro.xhtml', lang='zh')
intro_page.content = '<p><h2>不可商用</h2></p><p>自学自用, 请勿传播</p>'
self.book.add_item(intro_page)
# spine 是 EPUB 书籍的主要内容部分, 它是一个列表, 包含了书籍的各个部分。这里我们先把前言部分添加到 spine 中
# 每个spine的元素都是一个 EpubHtml 对象, 它代表了一个 HTML 页面,包含了页面的标题、内置文件名和内容等信息
# 当 nav 出现在 spine 列表中时,通常表示导航文档(Navigation Document)。在 EPUB 3 规范中,导航文档是 nav.xhtml,
# 它为读者提供了一种在电子书中进行导航的方式,类似于目录。
self.spine = ['nav', intro_page]
封面 set_cover
就是一本书的封面的图像
def set_book_cover(self, cover_image_path):
# 如果封面图像路径为空, 使用默认封面图像
if not cover_image_path:
cover_image_path = "bg.png"
# set_cover 函数用于设置书籍的封面图像。它接受三个参数:
# 第一个参数是封面图像的文件路径,第二个参数是封面图像的二进制内容,
# 第三个参数 False 是 create_thumbnail 参数。它是一个布尔值,
# 用于指示是否要为封面图片创建缩略图。缩略图可以用于在app的书架里使用
self.book.set_cover(cover_image_path, open(cover_image_path, 'rb').read(), False)
目录 toc
这个目录 toc,不是nav.xhtml那个页面,而是整个epub文档的内部逻辑。
主要靠epub.link来实现。
举个例子:
你家住在“长安街8号院8号楼808室”这是个内部逻辑,是派出所登记这个房子的一个编码。
而你家房门上有个牌子,上面写着8-808, 这只是一个牌子.即便它掉下来了,没有了,也不影响派出所里的逻辑
def add_toc(self): # toc 目录
# 先连接上前言部分, 然后再连接上各个章节
toc = [epub.Link(href='intro.xhtml', title='++前言++', uid='intro***')]
for chapter_filename, chap_title in self.book_info['chapters_filelist']:
chapter_link = epub.Link(href=chapter_filename, title=f'++{chap_title}++')
toc.append(chapter_link)
self.book.toc = tuple(toc)
ncx / nav
ncx只限于epub2.0标准, 其他的我也不知道了. 请自行搜索.
def add_nav(self):
# self.book.add_item(epub.EpubNcx())
self.book.add_item(epub.EpubNav(file_name='mynav.xhtml', title='~~目录~~'))
反正得加上这么一句话.
#类和json配置文件
"""
读取json配置文件,然后把几个xhtml文件合并为epub的python库。配置文件里包含了书名、作者、封面图像路径、各个章节的路径和章节名称。
"""
from ebooklib import epub
import json
class EpubBookCreator:
def __init__(self, book_info_json):
self.book_info = book_info_json
self.book = epub.EpubBook()
self.book.set_identifier('id123456')
self.book.set_language('zh')
self.book.set_title(book_info_json['book_name'])
self.book.add_author(book_info_json['book_auth'])
self.set_book_cover(book_info_json.get("book_cover", "bg.png"))
self.add_css()
self.add_intro_page()
self.add_chapters()
self.add_toc()
self.add_nav()
def set_book_cover(self, cover_image_path):
# 如果封面图像路径为空, 使用默认封面图像
if not cover_image_path:
cover_image_path = "bg.png"
# set_cover 函数用于设置书籍的封面图像。它接受三个参数:
# 第一个参数是封面图像的文件路径,第二个参数是封面图像的二进制内容,第三个参数 False 是 create_thumbnail 参数。
# 它是一个布尔值,用于指示是否要为封面图片创建缩略图。缩略图可以用于在app的书架里使用
self.book.set_cover(cover_image_path, open(cover_image_path, 'rb').read(), False)
def add_css(self):
css_text = '''
@namespace epub "http://www.idpf.org/2007/ops";
body { font-family: "Times New Roman", Times, serif;}
p {text-indent: 2em; /* 设置段落首行缩进 */ margin-top: 0; margin-bottom: 0.5em;}
'''
# 创建一个 CSS 文件对象
# epub.EpubItem 用于创建一个 EPUB 项目, 这里是一个 CSS 文件。它接受四个参数:
# uid: 项目的唯一标识符 # file_name: 项目的文件名内置于epub里 # media_type: 项目的媒体类型, 这里是 "text/css"
# content: 项目的内容, 这里是 CSS 样式文本
style = epub.EpubItem(uid="style", file_name="style/mystyle.css", media_type="text/css", content=css_text)
self.book.add_item(style)
def add_intro_page(self):
# title是页面的<title></title
intro_page = epub.EpubHtml(title='-前言-', file_name='intro.xhtml', lang='zh')
intro_page.content = '<p><h2>不可商用</h2></p><p>自学自用, 请勿传播</p>'
self.book.add_item(intro_page)
# spine 是 EPUB 书籍的主要内容部分, 它是一个列表, 包含了书籍的各个部分。这里我们先把前言部分添加到 spine 中
# 每个spine的元素都是一个 EpubHtml 对象, 它代表了一个 HTML 页面,包含了页面的标题、内置文件名和内容等信息
# 当 nav 出现在 spine 列表中时,通常表示导航文档(Navigation Document)。在 EPUB 3 规范中,导航文档是 nav.xhtml,
# 它为读者提供了一种在电子书中进行导航的方式,类似于目录。
self.spine = ['nav', intro_page]
def add_chapters(self):
for chapter_filename, chapter_title in self.book_info['chapters_filelist']: # 按列表顺序取得各个章节的文件名和标题
content = open(chapter_filename, 'r', encoding='utf-8').read()
epub_chapter = epub.EpubHtml(title=chapter_title, file_name=chapter_filename, lang='zh')
epub_chapter.content = f'{content}'
self.book.add_item(epub_chapter)
self.spine.append(epub_chapter)
self.book.spine = self.spine
def add_toc(self): # toc 目录
# 先连接上前言部分, 然后再连接上各个章节
toc = [epub.Link(href='intro.xhtml', title='++前言++', uid='intro***')]
for chapter_filename, chap_title in self.book_info['chapters_filelist']:
chapter_link = epub.Link(href=chapter_filename, title=f'++{chap_title}++')
toc.append(chapter_link)
self.book.toc = tuple(toc)
def add_nav(self):
# self.book.add_item(epub.EpubNcx())
self.book.add_item(epub.EpubNav(file_name='mynav.xhtml', title='~~目录~~'))
def save(self):
epub_path = f'{self.book_info["book_name"]}.epub'
epub.write_epub(epub_path, self.book, {})
print(f"EPUB 文件已创建: {epub_path}")
if __name__ == '__main__':
with open('book_info.json', 'r', encoding='utf-8') as f:
json_book_info = json.load(f)
epub_creator = EpubBookCreator(json_book_info)
epub_creator.save()
有几个字段是爬虫用的,本程序用不到. chapter_*.xhtml 是本地文件
{
"menu_file": "listbs.txt",
"book_name": "书的名字",
"book_auth": "作者",
"txt_content_id": "acontent",
"book_cover": "cover.jpg",
"chapters_filelist": [
[
"chapter_0.xhtml",
"第一章"
],
[
"chapter_1.xhtml",
"第二章"
],
[
"chapter_2.xhtml",
"第三章"
]
]
}