はじめに
「小説家になろう」や「カクヨム」の素晴らしい小説を、ブラウザではなくKindleなどの縦書きでじっくりと読みたいと思ったことはありませんか?
私自身、これまで完成度の高い先行プロジェクトには大変お世話になっていたのですが、RubyやJavaといった実行環境の構築がハードルになることもありました。実際、自分のPCを機種更新した際に環境を再構築できず、動かせなくなってしまったのです。
そこで今回、Pythonだけで完結し、誰でも 「かんたんに使える縦書きEPUB変換ツール」 を目指して自作を始めました。
つまずきポイント1:スクレイピング編
「小説家になろう」の作品トップページ(目次)は、エピソード数が100を超えるとページネーションが発生します。単純に目次URLからリンクを抽出するだけだと、最初の100話で取得が止まってしまいます。また、単純なページ番号の加算だけでは、最終ページを判定できずに無限ループに陥るリスクもありました。
今回、以下のロジックを実装することで、全話を網羅するようにしました。
-
動的なURL解析: BeautifulSoupを用いて「次へ(Next)」ボタンの有無を確認。ボタンが存在する場合、そのリンク(
?p=2などのパラメータ付きURL)を再帰的に追いかけ続ける。 - 終了判定の厳格化: 「次のページへのリンクが見つからない」状態を確実にキャッチし、ループを安全に抜ける。
これにより、数百話におよぶ大作であっても一気にダウンロードすることが可能になりました。
つまずきポイント2:EbookLib
EPUBの生成には Python の定番ライブラリである EbookLib を使用しましたが、日本語の「縦書き書籍」を作成するにはいくつかのハードルがありました。
通常、特定のページ(例えば扉ページ)だけデザインを切り替えたい場合、<body class="hltr"> のように body タグにクラスを付与してCSSで制御するのが一般的です。
しかし、EbookLib は生成時に独自に <body> タグを再構築する仕様らしく、EpubHtml オブジェクトに渡した body タグのクラス属性が、書き出し時にことごとく消滅してしまうという現象に見舞われました。これでは、ページごとに縦書き・横書きを切り替えることができません。
解決策:コンテンツ全体を div で囲む「ラッパー作戦」
試行錯誤の結果、body 自体の操作を諦め、コンテンツ全体を1つの div で囲むことでこの問題を解決しました。
開発のTips:表示が崩れたら「解凍」して中を見る
EPUBは特別なバイナリファイルではなく、その実体は HTMLやCSSをZIP形式で圧縮したものです。
「CSSが当たらない」「意図しない余白ができる」といった問題にぶつかったとき、私が最も多用したデバッグ手法が 「EPUBを解凍して中身を直接解析する」 ことでした。
デバッグのワークフロー
- 生成された
.epubファイルの拡張子を.zipに変える。 - 解凍されたディレクトリ内にある
xhtmlファイルやcssファイルをブラウザやエディタで開く。 -
EbookLibによって書き出された最終的なHTML構造が、自分の意図通り(例:bodyタグにクラスがついているか等)になっているかを確認する。
今回の「bodyタグの属性が消える問題」も、この手法で書き出し後のHTMLを直接確認したことで原因がわかりました。
「実際に出力されたコードを信じる」 のが、EPUB開発の近道だと痛感しました。
まとめ
PCの機種更新をきっかけに始めた今回の自作プロジェクトですが、いざ蓋を開けてみるとライブラリの癖やWebの仕様に苦戦しました。そのぶん、完成したツールを使って小説をKindleで表示できた時はちょっと感動しました。
もし「なろう小説をKindleで読みたいけれど、環境構築でつまずいている」という方がいれば、ぜひこのPythonツールを試してみてください。
