用PyQt4+Python寫一個(gè)簡(jiǎn)單的EPub閱讀器(1/3)

上一篇EPub格式電子書的制作介紹了EPub的基本概念,并用Python制作了一本簡(jiǎn)單的EPub電子書迂烁,這次猴贰,我們做一個(gè)EPub閱讀器。

既然主題已經(jīng)限定這是一個(gè)「簡(jiǎn)單」的EPub閱讀器乔夯,我們?cè)燧喿拥倪^(guò)程自然是以「掌握核心科技」為原則砖织,怎么簡(jiǎn)單怎么來(lái)(PS1:我說(shuō)的好有道理你竟然無(wú)言以對(duì)。PS2:「什么末荐,你有話說(shuō)侧纯?」,「哦甲脏!」)

所以呢眶熬,這個(gè)EPub閱讀器的構(gòu)想是這樣的,一個(gè)主界面上一共3個(gè)Widget块请,其中兩個(gè)一個(gè)用來(lái)查看章節(jié)娜氏,一個(gè)用來(lái)查看文字內(nèi)容,文字內(nèi)容一般用html墩新,xhtml展示贸弥,那我們就用webview來(lái)展示文字的內(nèi)容,還有一個(gè)作為圖書倉(cāng)庫(kù)(Library)海渊,里面可以看到已經(jīng)在倉(cāng)庫(kù)中的圖書绵疲。

上一篇提到,EPub電子書實(shí)際上是一個(gè)壓縮包文件臣疑,而且壓縮包內(nèi)的基本結(jié)構(gòu)我們也已經(jīng)了解了盔憨,要將這些數(shù)據(jù)展示在GUI上,需要一個(gè)抽象模型存放要顯示的內(nèi)容讯沈,所以郁岩,這個(gè)模塊就叫做Books吧,它存放的信息包括書名缺狠,作者驯用,章節(jié)名以及對(duì)應(yīng)的在文件目錄中的地址,這一篇呢儒老,我們就先寫這個(gè)模塊蝴乔。

解析xml用到的模塊是BeautifulSoup4和lxml,不會(huì)的童鞋也不要緊張驮樊,這兩個(gè)模塊非常容易用薇正,花一點(diǎn)時(shí)間學(xué)一下就行了。 你看囚衔,就像這樣:

howtodrawahorse

EPub格式電子書的制作中提到挖腰,META-INF/container.xml中包含了opf文件的路徑,而opf文件中有書籍的基本信息练湿,如書名猴仑,作者等等。所以,流程也很簡(jiǎn)單辽俗,先用zifile解壓讀取container.xml疾渣,再用bs4從opf文件中解析出需要的信息。首先放一本epub格式的書籍到工作目錄中崖飘,新建一個(gè)books.py榴捡,如:

epubandbookspy

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import os
import zipfile

from BeautifulSoup import BeautifulStoneSoup
LIBRARY_DIR = os.path.abspath('.') + os.sep

class Book(object):
    u"""
    """
    _FILE = LIBRARY_DIR + '%s.epub'

    def __init__(self, book_id=None):
        if book_id:
            self.open(book_id)

    def open(self, book_id=None):
        if book_id:
            self.book_id = book_id
        if not self.book_id:
            raise Exception('Book id not set')

        self.f = zipfile.ZipFile(self._FILE % self.book_id, 'r')
        soup = BeautifulStoneSoup(self.f.read('META-INF/container.xml'))

        oebps = soup.findAll('rootfile')[0]['full-path']
        print ("ops filename path:" + str(oebps))
        folder = oebps.rfind(os.sep)
        self.oebps_folder = '' if folder == -1 else oebps[:folder+1]   # 找到oebps的文件夾名稱

if __name__ == '__main__':
    book = Book('莎士比亞全集')
    print book.oebps_folder

獲得ops文件名,所在目錄: 如:

getopsfile

照這個(gè)思路寫下去朱浴,得到書名吊圾,作者信息,從ncx文件中獲得目錄信息翰蠢,代碼如下:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import os
import zipfile

from lxml import etree
from BeautifulSoup import BeautifulStoneSoup

LIBRARY_DIR = os.path.abspath('.') + os.sep

RECOVER_PARSER = etree.XMLParser(recover=True, no_network=True)
NAMESPACES = {
    'dc': 'http://purl.org/dc/elements/1.1/',
}


class Book(object):
    u"""
    需要主動(dòng)調(diào)用open方法才能獲得相應(yīng)的屬性
    """
    _FILE = LIBRARY_DIR + '%s.epub'

    def __init__(self, book_id=None):
        if book_id:
            self.open(book_id)

    def fromstring(self, raw, parser=RECOVER_PARSER):
        return etree.fromstring(raw, parser=parser)

    def read_doc_props(self, raw):
        u"""

        :param raw: raw string of xml
        :return:
        """
        root = self.fromstring(raw)
        self.title = root.xpath('//dc:title', namespaces={'dc': NAMESPACES['dc']})[0].text
        self.author = root.xpath('//dc:creator', namespaces={'dc': NAMESPACES['dc']})[0].text

    def open(self, book_id=None):
        if book_id:
            self.book_id = book_id
        if not self.book_id:
            raise Exception('Book id not set')

        self.f = zipfile.ZipFile(self._FILE % self.book_id, 'r')
        soup = BeautifulStoneSoup(self.f.read('META-INF/container.xml'))

        oebps = soup.findAll('rootfile')[0]['full-path']
        folder = oebps.rfind(os.sep)
        self.oebps_folder = '' if folder == -1 else oebps[:folder+1]   # 找到oebps的文件夾名稱

        oebps_content = self.f.read(oebps)
        self.read_doc_props(oebps_content)

        opf_bs = BeautifulStoneSoup(oebps_content)
        ncx = opf_bs.findAll('item', {'id': 'ncx'})[0]
        ncx = self.oebps_folder + ncx['href']     # 找到ncx的完整路徑

        ncx_bs = BeautifulStoneSoup(self.f.read(ncx))

        self.chapters = [(nav.navlabel.text, nav.content['src']) for
                         nav in ncx_bs.findAll('navmap')[0].findAll('navpoint')]

if __name__ == '__main__':
    book = Book('莎士比亞全集')
    print book.oebps_folder

    print book.title
    print book.author

    print str(book.chapters).decode("unicode-escape").encode("utf-8")
    

結(jié)果如圖:


book_result

說(shuō)明:測(cè)試過(guò)程中發(fā)現(xiàn)有的epub圖書不規(guī)范项乒,目錄信息中沒(méi)有章節(jié)描述和對(duì)應(yīng)的路徑,對(duì)于這些書籍可能會(huì)報(bào)錯(cuò)(OS:管它呢梁沧,反正不是我報(bào)錯(cuò)(OS:WTF))檀何。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市趁尼,隨后出現(xiàn)的幾起案子埃碱,更是在濱河造成了極大的恐慌猖辫,老刑警劉巖酥泞,帶你破解...
    沈念sama閱讀 222,183評(píng)論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異啃憎,居然都是意外死亡芝囤,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,850評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門辛萍,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)悯姊,“玉大人,你說(shuō)我怎么就攤上這事贩毕∶跣恚” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 168,766評(píng)論 0 361
  • 文/不壞的土叔 我叫張陵辉阶,是天一觀的道長(zhǎng)先壕。 經(jīng)常有香客問(wèn)我,道長(zhǎng)谆甜,這世上最難降的妖魔是什么垃僚? 我笑而不...
    開(kāi)封第一講書人閱讀 59,854評(píng)論 1 299
  • 正文 為了忘掉前任,我火速辦了婚禮规辱,結(jié)果婚禮上谆棺,老公的妹妹穿的比我還像新娘。我一直安慰自己罕袋,他們只是感情好改淑,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,871評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布碍岔。 她就那樣靜靜地躺著,像睡著了一般溅固。 火紅的嫁衣襯著肌膚如雪付秕。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 52,457評(píng)論 1 311
  • 那天侍郭,我揣著相機(jī)與錄音询吴,去河邊找鬼。 笑死亮元,一個(gè)胖子當(dāng)著我的面吹牛猛计,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播爆捞,決...
    沈念sama閱讀 40,999評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼奉瘤,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了煮甥?” 一聲冷哼從身側(cè)響起盗温,我...
    開(kāi)封第一講書人閱讀 39,914評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎成肘,沒(méi)想到半個(gè)月后卖局,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,465評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡双霍,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,543評(píng)論 3 342
  • 正文 我和宋清朗相戀三年砚偶,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片洒闸。...
    茶點(diǎn)故事閱讀 40,675評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡染坯,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出丘逸,到底是詐尸還是另有隱情单鹿,我是刑警寧澤,帶...
    沈念sama閱讀 36,354評(píng)論 5 351
  • 正文 年R本政府宣布深纲,位于F島的核電站仲锄,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏囤萤。R本人自食惡果不足惜昼窗,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,029評(píng)論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望涛舍。 院中可真熱鬧澄惊,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 32,514評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至毕贼,卻和暖如春温赔,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背鬼癣。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,616評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工陶贼, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人待秃。 一個(gè)月前我還...
    沈念sama閱讀 49,091評(píng)論 3 378
  • 正文 我出身青樓拜秧,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親章郁。 傳聞我的和親對(duì)象是個(gè)殘疾皇子枉氮,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,685評(píng)論 2 360

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)暖庄,斷路器聊替,智...
    卡卡羅2017閱讀 134,707評(píng)論 18 139
  • 最后一篇,這次我們加上幾個(gè)函數(shù)培廓,使得這個(gè)閱讀器能夠按照章節(jié)閱讀電子書惹悄,前兩篇我們將完成了Book模塊,實(shí)現(xiàn)了電子書...
    knarfeh閱讀 2,460評(píng)論 0 4
  • 接上一篇医舆,這一篇我們寫GUI俘侠。 上一篇提出了圖書倉(cāng)庫(kù)的概念象缀,更具體的想法是:這個(gè)倉(cāng)庫(kù)是一個(gè)文件夾蔬将,所有打開(kāi)的書都往...
    knarfeh閱讀 2,727評(píng)論 0 3
  • “老司機(jī)”為什么要加上引號(hào)呢?是因?yàn)樽现窆媚镏皇墙佑|投資理財(cái)產(chǎn)品的時(shí)間較長(zhǎng)央星,但是并達(dá)不到老司機(jī)的資格霞怀! ...
    紫竹姑娘閱讀 422評(píng)論 12 5
  • 阮郎歸:愿君早回鄉(xiāng) 原創(chuàng):籬菊傲霜 黎明簾幕卷寒霜, 披衣獨(dú)倚窗莉给。 臘梅仙子舞霓裳毙石, 陣陣散幽香。 風(fēng)瑟瑟颓遏,雨茫茫...
    籬菊傲霜閱讀 135評(píng)論 0 0