オープンソースの電子書籍管理ソフト「Calibre」を使いこなそう!

第3回 Calibreに新しいニュースサイトを追加する

この記事を読むのに必要な時間:およそ 3 分

自分でニュースソースを追加する(その2)

今回は前回の続きで,Pythonのコードを使って新しいニュースサイト用のレシピを作り,Calibreに追加してみましょう。CalibreのマニュアルにもAdding your favorite news websiteと言うチュートリアルがあり,これも非常に参考になりますが,ここでは実際にgihyo.jpを例にして,最新の記事数本を電子書籍に変換するまでを実際に作ってみます。

新しいレシピを作成するには,前回と同様,⁠ニュース取り込み」から「独自ニュース源を追加」のダイアログを開き,そこで(今回は)右上にある「アドバンスモードに切り替え」のボタンを押すとPythonスクリプトのレシピを入力できるようになります。

アドバンストモード

アドバンストモード

前回も少し言及しましたが,Calibreのニュース・レシピはPythonで書き,スクリーン・スクレイピング用のライブラリ,Mechanize ⁠Cookieの処理や,ログイン等のフォームの操作等を行う)BeautifulSoup ⁠HTMLを解析しそれを操作する)を使ってニュースを取得します。レシピのスーパークラスBasicNewsRecipeにすでに色々な機能が含まれているので,ポイントを押さえてゆけばニュースソースの対応処理部分だけに集中して作成でき,シンプルに作成できるでしょう。

レシピの処理全体の流れを大まかに説明すると,次のようになります。

  1. ログイン等を行う
  2. 記事のインデックスを取得する
  3. 各記事を取得する
  4. 記事HTMLを修正する

順を追って説明していきましょう。

1:(必要な場合)ログイン等を行う

get_browserメソッドでMechanizeの機能を使いログイン等を行います。多くのニュースサイトではログインしないと記事が見れない,一部の機能が使えないなどの制限があります。特に電子書籍に向いた印刷用ヴァージョンを見るためには,ログインが必要なことがよくあります。MechanizeはCookieの処理や,フォームの操作等ができるので,これを使って後の操作のためにログインします。今回のgihyo.jpレシピではログイン等は必要ないのでこのメソッドは使いません。

2:記事のインデックス(一覧)を取得する

parse_indexメソッド等で記事のインデックスを取得・作成してどの記事をダウンロードするかを決定します。一覧ページをBeautiful Soupを使ってスクレイピングしても良いのですが,多くの場合,最新の記事は(全文でない)RSSフィードが出ている場合が多いため,それを使うことでBasicNewsRecipe側で勝手に記事一覧を作ってくれます(もちろん前回紹介したように,全文RSSがあればPythonでレシピを書く必要はありません)⁠

    #links to RSS feeds
    feeds = [ ('gihyo.jp', u'http://gihyo.jp/feed/atom') ]

そのため今回は,gihyo.jpのRSSフィードをfeeds変数に設定するのみで,parse_indexメソッドも使いません。

3:各記事を取得する

各記事の取得もBasicNewsRecipeクラスが自動でやってくれるのですが,今回のgihyo.jpでは記事が複数ページに分かれている場合があるため,preprocess_htmlと言うフック・メソッドをオーバーライドして,自作のメソッド append_page()にて再帰的に複数ページに対応します。その他(今回は使いませんが)⁠プリント用ページ等に対応する時にはprint_versionと言うフックも使えます。

    #load second and subsequent page content
    # in: soup - full page with 'next' button
    # out: appendtag - tag to which new page is to be added
    def append_page(self, soup, appendtag):
        # find the 'Next' button
        nextButton = soup.find(attrs={'rel':'next'})

        if nextButton:
            nexturl = nextButton['href']
            soup2 = self.index_to_soup(nexturl)
            print " fetching next url : " + nexturl

            contents = soup2.find('div', attrs={'class':'readingContent01 autopagerize_page_element'})

            pos = len(appendtag.contents)
            appendtag.insert(pos, contents)

            self.append_page(soup2, appendtag)

    def preprocess_html(self, soup):
        contents = soup.find('div', attrs={'class':'readingContent01 autopagerize_page_element'})
        self.append_page(soup, contents)

        return soup

4:記事HTMLを修正する

取得した記事には広告や,Twitter等へのリンク,パンくずリンク等の電子書籍として読むには必要ないものが数多く入っているので,それを修正します。これにはBasicNewsRecipeが勝手に行ってくれる便利な変数,remove_tagsremove_tags_beforeremove_tags_after等があるので,これらに条件を設定するだけでOKです。今回は使いませんが,この他にも色々な修正処理を行う物があります。たとえばCSSを追加するextra_cssリンクを有効・無効化するmatch_regexpsfilter_regexpsそしてHTMLを強制的に正規表現で書き換えるpreprocess_regexpsなども使用可能です。

    remove_tags_before = dict(name='div', attrs={'id':['content']})

    remove_tags = [
                      dict(name='div', attrs={'class':['pageSwitch01']}),
                      dict(name='div', attrs={'id':['socialBookmark']}),
                      dict(name='div', attrs={'class':['pageSwitch01 autopagerize_insert_before']})
                  ]

    remove_tags_after = [
                      dict(name='div', attrs={'id':['relArticle']})
                  ]

著者プロフィール

西村亜土(にしむらあど)

さまよえるプログラマー?

フリーランスで,iPhone開発,Android開発,Webアプリ開発などのプログラム開発を行っている。最近は住所不定でよく変わる。現在は鎌倉でボーっとしている。仕事探しの一環としてJICAのシニアボランティアを眺めていたら,MySQLのスキルが必要なボランティアを発見(少し前だが)。パプアニューギニアへ行くのも一興かな。calibreの翻訳は,もう少しで一通り終わりそう!がんばろう!

Twitter:@adonishi
Web: http://www.sig.or.jp/~ado/

コメント

コメントの記入