PythonスクリプトでHTMLの見出しタグ情報から目次を生成

ちょっとした小ネタです。

ブログを書くとき、書きたい事が溢れてしまい結果、見出しレベルの数が多くなってくると「目次」をちゃんと用意しておきたくなりますよね。(私はそうです) 目次を用意する事で文章全般を構造化する事が出来、ユーザビリティ的にも今どこを読んでいるのか、構成を確認出来るなどのメリットがあるかと思います。(ちなみにSEO的にはどうなんだろう...?)

ただ、見出しの数が多くなってくると対応する目次を準備するのも一苦労。

ブログに拠ってはプラグイン等で対応しているものもあるようですが、現時点では当ブログ(Developers.IO/WordPress)にはその様なものは導入されていないようです。

個人的には、ブログを書く時の記法は基本的にはHTMLをそのまま使っています。(※箇所に拠ってMarkdownを使います) ちなみに現環境では下記の「HTMLの入力補助」が使えますので、存分に活用してHTMLコード入力の手間を大幅に効率化しています。

という感じで個人的には「ブログ執筆には主にHTML記法を使うよ」派な私なので、見出し(良く使うのはh1〜h4あたりまで)もHTMLタグで記載する事が大半です。

「HTMLの見出し情報から良い感じで目次を生成してくれる仕組みは無いものかしら」と幾つか情報を漁って居たのですが、しっくりハマるものが見つからなかったので「ならば自分でこしらえてしまおう」と思い、シンプルなものではありますがPythonスクリプトを作成したのでその内容と実践方法を共有したいと思います。

目次

エントリ執筆のきっかけ

執筆を思い立った経緯は冒頭に書いた通りですが、これまでは当ブログで自分が書いてきたエントリに付与していた「目次」情報は全て自分の手で1つずつ編集・コピペして作っていました。ざっくり以下の様な手順です。

  • エントリ本文を書く
    • 見出し(h2〜h4タグ)を書く
    • 合わせて見出しの上にaタグ(name属性付き)を書く
  • 本編書き上がる
  • 見出し情報をエントリ本文から抜粋
  • 見出し作成用テンプレート(以下のようなもの)を用意
    <ul>
    <li><a href="#"></a></li>
    <li><a href="#"></a></li>
    <li><a href="#"></a></li>
    <li><a href="#"></a></li>
    <li><a href="#"></a></li>
    </ul>
    

  • 見出しの構成内容に合わせて入れ子をカスタマイズし、目次を作成(内容は見出し情報から切り貼り)

個人的にはこの作業自体、特に苦にする事無くやっていたのですが、よりスムーズかつ迅速に仕上げるためにはこの作業を自動化するしか無いなー、と思った次第です。

進め方

以降の内容では、HTMLコードからの目次自動生成に関する進め方について解説します。

01.ブログを書く(HTML形式で)

はい、まずこれが無いとお話が進みません。書きましょう。

 

...書けましたか?

まぁ、今回の場合は目次要素だけあれば良いので、全文書けて無くても大丈夫です。書きたいテーマについて以下の様な形で目次要素を並べ、構造を見直した上で用意してください。

当ブログ環境では見出しタグは<h2>レベルが記事編集上利用出来る最上位のタグとなりますので、<h2><h3>タグを使っています。

また、見出しタグにはそれぞれid属性を割り当て、値には一意の値を【人が読んである程度把握出来る文言で】(数字連番構成で並べていくよりも、個人的にはこちらの方が好きです。値が一意であれば問題ないので、実際利用される際は数字連番の設定でも差し支えありません)設定しておきます。

書いた内容については見出し構成が固まったタイミングで別途テキストファイルに保存しておきます(目次作成には保存したファイルを使います)。

<h2 id="reason-to-post">エントリ執筆のきっかけ</h2>

<h2 id="how-to">進め方</h2>

<h3 id="how-to-00-precondition">00.前提条件</h3>

<h3 id="how-to-01-write-blog">01.ブログを書く(HTML形式で)</h3>

<h3 id="how-to-02-setup-python3-env">02.Python実行環境(3.x系)を用意する</h3>

<h3 id="how-to-03-execute-script">03.スクリプトを実行し、出力結果を目次情報として利用</h3>

<h3 id="how-to-04-css-adjustment-for-displacement-of-link-transition">04.目次リンククリック → 見出し遷移時の「ズレ」に対応する</h3>

<h2 id="in-the-case-of-markdown">Markdown記法での見出しの場合はどうする?</h2>

<h2 id="matome">まとめ</h2>

02.Python実行環境(3.x系)を用意する

次に、後述するスクリプトを稼働させるための環境を用意します。今回はPythonスクリプトをこしらえたので、その環境となります。Pythonのバージョンは3.6のものを調達しました。

$ python --version
Python 3.6.4

03.スクリプトを実行し、出力結果を目次情報として利用

下記のPythonスクリプトをダウンロードし、所定のパスに配置してください。

ソースコード的に実行前の微調整・設定が必要な箇所は以下の通りです。

  • 7行目〜11行目では「その見出しタグを目次として認識させるか否か」を指定。この場合は<h2><h4>を対象としています。
  • 20行目〜29行目では「それぞれの見出しタグがあった場合、どういう文字列を生成するか」を指定しています。ソースコードの内容では後述する処理結果を出力する形になりますが、もしカスタマイズが必要であればこの箇所を見直して&書き換えてください

準備が出来たら、入力ファイルを引数としてPythonスクリプトを実行します。実行結果が以下の様に出力されるので、出力内容をエントリ内の所定の位置に貼り付ければOKです。

$ python toc-from-html.py my-blog-draft.txt 
<!-- auto generated Table of Contents:START. -->
<h2>目次</h2>
- <a href="#reason-to-post">エントリ執筆のきっかけ</a>
- <a href="#how-to">進め方</a>
    - <a href="#how-to-00-precondition">00.前提条件</a>
    - <a href="#how-to-01-write-blog">01.ブログを書く(HTML形式で)</a>
    - <a href="#how-to-02-setup-python3-env">02.Python実行環境(3.x系)を用意する</a>
    - <a href="#how-to-03-execute-script">03.スクリプトを実行し、出力結果を目次情報として利用</a>
    - <a href="#how-to-04-css-adjustment-for-displacement-of-link-transition">04.目次リンククリック → 見出し遷移時の「ズレ」に対応する</a>
- <a href="#in-the-case-of-markdown">Markdown記法での見出しの場合はどうする?</a>
- <a href="#matome">まとめ</a>
<!-- auto generated Table of Contents:END-->

基本的な挙動としては、上記までの設定でOKです。

ただ、この状態では、目次リンク押下時の挙動がちょっと残念な形となります。目次で生成されたリンクをクリックすると...

見出しに遷移はするのですが、以下の様に見え方がちょっとアレな感じになってしまいます。

この問題を解決するために、以下エントリの情報を使って調整しました。

エントリ記載の以下のCSSの内容を、エントリが参照するCSS設定の部分に追記する事で、

@-webkit-keyframes modify{
      0% { padding-top: 30px; margin-top: -30px; }
    100% { padding-top: 0; margin-top: 0; }
}
@keyframes  modify{
      0% { padding-top: 30px; margin-top: -30px; }
    100% { padding-top: 0; margin-top: 0; }
}

h2:target {
    -webkit-animation: modify 0.1s;
    animation: modify 0.1s;
}

h3:target {
    -webkit-animation: modify 0.1s;
    animation: modify 0.1s;
}

h4:target {
    -webkit-animation: modify 0.1s;
    animation: modify 0.1s;
}

以下の様に遷移後の状態を程良く見出しが見え易い位置に調整する事が出来ました!

Markdown記法での見出しの場合はどうする?

ここまでは(当エントリでは)「HTML記法での見出し」で目次を生成する方法について言及してきましたが、Markdown記法の場合だとどうでしょうか?

Markdown記法については以下の様な形で便利な技やプラグイン等が公開されているようです。お使いの環境に合った形の方法を探してみると良いかも知れません。

まとめ

という訳で、HTMLソースコードの見出し情報から、目次を自動生成する手順についてのご紹介でした。エントリ執筆の際は見出し書きの部分に集中する事でこの手の煩わしさから幾分解消される形になるとは思いますので、宜しければお使い頂けますと幸いです。