羊をめぐるブログ

趣味の色々について書きます

青空文庫内の小説を全ダウンロードして解析用にきれいにする

はじめに

青空文庫のWebページはありがたいことに小説を含む全ページのソースがgithub上に公開されています. しかしそのままデータを用いようとすると,ルビがあったりエンコーディングがshift-jisだったりで少し使いづらいです. そこで青空文庫のレポジトリ内部のデータをパースして以下のような形式で保存することを行なったのでその手順について備忘録として書こうと思います.

novels
├── 芥川龍之介
│   ├── 河童
│   ├── 蜘蛛の糸
├── 坂口安吾
│   ├── 白痴

使ったもの

小説データの保存手順

まず青空文庫のレポジトリをクローンしてきます.

github.com

git clone git@github.com:aozorabunko/aozorabunko.git

クローンしてきたレポジトリに移動すると色々入っていますが,小説データなどは./aozorabunko/cards の中に入っています.

cards内のファイルをパースする前にエンコーディングを全てshift-jisからutf-8に変更します.

find cards -name '*.html' -exec nkf -w --overwrite {} \;

自分は全て上書きしてしまいましたが,文字化けで見れなくなるので別のところに保存した方がいいかもしれません.

次にcards内の小説データを全てパースします.自分はpythonとbeautiful soupを用いました. 主に小説のhtmlデータから著者,タイトル,メインテキストを取り出し,ルビを取り除いて保存するということを行なっています. 自分以外の環境で動くかはわかりませんが使用したコードは以下です.

from bs4 import BeautifulSoup as bs
import numpy as np

import re, sys, os

def make_dir(dir_name):
    if not os.path.exists(dir_name):
        os.mkdir(dir_name)

def save_novel(file_path, text):
    if not os.path.exists(file_path):
        print('saved', file_path)
        with open(file_path, 'w') as f:
            f.write(text)

if __name__ == '__main__':
    pass

    cards = os.listdir('./cards')

    for card in cards:
        if card.isdecimal() and os.path.exists('./cards/' + card + '/files'):
            novels = os.listdir('./cards/' + card + '/files')
            for novel in novels:

                if novel[-4:] == 'html':
                    with open('./cards/' + card + '/files/' + novel, 'r') as f:
                        novel_page_html = f.read()
                        novel_parsed = bs(novel_page_html, 'html.parser')
                        try:
                            for rt in novel_parsed('rt'):
                                rt.decompose()
                            for rp in novel_parsed('rp'):
                                rp.decompose()
                        except AttributeError as err:
                            print(err)
                        novel_title = novel_parsed.find('h1', class_='title')
                        novel_author = novel_parsed.find('h2', class_='author')
                        novel_content = novel_parsed.find('div', class_='main_text')
                        if novel_author is not None and novel_author.string is not None:
                            make_dir('./novels/' + novel_author.string)
                            save_novel('./novels/' + novel_author.string + '/' + novel_title.string, novel_content.text)

これでおおよそ14000の小説データがnovels以下に保存されました.全部でおよそ500MB程度です. 校正を行なってくださっている方たちに頭があがらねぇ...