MakeSiteMap.py 技術ドキュメント

プログラムの動作

MakeSiteMap.py は、指定されたウェブサイトを再帰的にクロールし、その構造を視覚的に理解しやすいHTML形式のサイトマップツリービューとして生成するPythonスクリプトです。

目的と主な機能

このプログラムの主な目的は、ウェブサイトの全体像を把握し、コンテンツの網羅性や階層構造を視覚的に確認できるツールを提供することです。 具体的な機能は以下の通りです。

  1. ウェブサイトの再帰的クロール: 指定されたルートURLから出発し、同一ドメイン内のリンクを辿ってウェブサイト全体を深さ優先でクロールします。

  2. HTMLサイトマップツリービューの生成: クロールによって発見されたすべてのURLとそれに関連するメタデータ(ページのタイトル、最終更新日)を、HTMLの折りたたみ可能なツリー構造として整形して出力します。

  3. メタデータの抽出: 各ページのHTMLコンテンツから<title>タグを抽出してページのタイトルとし、HTTPレスポンスヘッダーのLast-Modifiedから最終更新日を取得します。

  4. URLのフィルタリングと除外:

    • 指定されたベースドメイン外のリンクは追跡しません。

    • デフォルトで一般的なファイル拡張子(PDF、画像、アーカイブなど)を持つURLをサイトマップから除外するオプションがあります。

    • 特定のパスパターン(正規表現)にマッチするURLをクロールおよびサイトマップから除外する機能があります。

  5. URLの正規化: URLのフラグメント(#以降のアンカー部分)を削除し、同じページを指す異なるURLが重複して扱われるのを防ぎます。

  6. 文字コードの自動判別: 取得したHTMLコンテンツの文字コードを自動で判別し、適切にデコードします。

  7. モダンなUI: 生成されるHTMLサイトマップはTailwind CSSを使用してスタイリングされており、視認性の高いツリービューを提供します。

解決する課題

  • サイト構造の可視化: 大規模なウェブサイトの階層構造やリンク関係を直感的に把握するのが困難な場合、このツールは全体像を明確に示します。

  • コンテンツの網羅性確認: サイトマップを生成することで、ウェブサイト内のすべての重要なページが適切にリンクされているか、また意図しないページが公開されていないかを確認できます。

  • ページの更新状況の把握: 各ページの最終更新日が表示されるため、コンテンツの鮮度管理や更新頻度の低いページの特定に役立ちます。

  • SEO対策: 検索エンジンがサイトの構造を理解しやすくなるよう、人間が視覚的に確認するためのサイトマップとして利用できます(XMLサイトマップとは目的が異なります)。

原理

MakeSiteMap.py は、以下の主要なアルゴリズムと技術を組み合わせて動作します。

1. ウェブクロール機構

  • 再帰的深さ優先探索 (DFS): crawl_recursive 関数は、指定された開始URLから再帰的にリンクを辿り、ウェブサイトを探索します。これは深さ優先探索の原則に従います。

  • 訪問済みURLの管理: visited セットを使用して、既にクロールしたURLを追跡します。これにより、無限ループを防ぎ、同じページを複数回クロールする無駄を省きます。URLはフラグメントを除去した形で正規化されてからセットに追加されます。

  • HTTPリクエスト: requests ライブラリを使用してウェブページを取得します。これにより、HTTPステータスコードのチェックやレスポンスヘッダーの取得(例: Last-Modified)が可能になります。

2. URL処理とフィルタリング

  • URLの正規化: normalize_url 関数は urllib.parse モジュールを利用してURLを解析し、フラグメント部分(#以降)を削除してURLを標準化します。これにより、example.com/page#section1example.com/page#section2 が同じページとして扱われます。

  • ドメインフィルタリング: クロール中、抽出されたURLが base_domain と一致しない場合、そのURLは内部リンクではないと判断され、追跡されません。

  • ファイル拡張子による除外: is_target_url 関数は、URLのパス部分が.html.shtmlで終わるか、またはパスがない(ルートURL)場合にTrueを返します。EXCLUDE_FILES 設定がTrueの場合、exclude_file_extensions リストに定義された拡張子を持つURLは対象外とします。

  • パスパターンによる除外: is_excluded_path 関数は、COMPILED_EXCLUDE_PATHS にコンパイルされた正規表現パターンリストに対して、URLのパス部分(クエリパラメータを含む)がマッチするかどうかをチェックします。マッチした場合、そのURLはクロール対象から除外されます。

3. HTML解析とメタデータ抽出

  • 文字コードの自動判別: HTTPレスポンスのバイト列コンテンツは、charset_normalizer ライブラリの detect 関数を使用して、最適な文字コードを自動的に推測します。これにより、多様なウェブサイトのエンコーディングに対応します。

  • ページのタイトル抽出: get_page_title 関数は、正規表現 r"<title>(.*?)</title>" を使用してHTMLコンテンツから<title>タグの内容を抽出します。

  • 最終更新日の抽出: HTTPレスポンスヘッダーの Last-Modified フィールドから、ページの最終更新日を取得します。取得した日付は datetime モジュールでパースされ、YYYY-MM-DD 形式に変換されます。

  • リンクの抽出: find_urls_in_html 関数は、正規表現 r"url:\s*[\"']([^\"']+)[\"']|href=[\"']([^\"']+)[\"']|src=[\"']([^\"']+)[\"']" を使用して、HTML内のhref, src, url()属性からリンクを抽出します。

4. サイトマップの構造構築とレンダリング

  • 階層構造の構築: build_hierarchy_dict 関数は、クロールによって収集されたフラットなURLとメタデータのリストを受け取り、それらをURLのパスセグメントに基づいてネストされた辞書構造に変換します。この辞書は、ファイルシステムのような階層を表現します。クエリパラメータはパスの一部として扱われ、一意のノードを形成します。

    • 例: /dir1/page.htmlroot["__children"]["dir1"]["__children"]["http://domain.com/dir1/page.html"] のように表現されます。

  • HTMLツリーのレンダリング: render_tree 関数は、build_hierarchy_dict で構築された階層辞書を再帰的にトラバースし、HTMLの<details>, <summary>, <ul>, <li> タグを組み合わせて、折りたたみ可能なツリービューを生成します。

  • HTMLテンプレート: 生成されたツリー構造は、Tailwind CSSを含む静的なHTMLテンプレートに埋め込まれ、最終的な出力ファイル (sitemap.html) として保存されます。これにより、モダンでレスポンシブなデザインのサイトマップが提供されます。

必要な非標準ライブラリとインストール方法

MakeSiteMap.py の実行には、以下の非標準Pythonライブラリが必要です。

  • requests: HTTPリクエストを送信してウェブページを取得するために使用されます。

  • charset_normalizer: HTTPレスポンスのバイト列から文字コードを自動的に判別するために使用されます。

これらのライブラリは、Pythonのパッケージ管理システム pip を使用してインストールできます。 以下のコマンドをターミナルで実行してください。

pip install requests charset_normalizer

必要な入力ファイル

MakeSiteMap.py は、プログラムが動作するために特定の入力ファイルを必要としません。 クロールを開始するルートURLは、コマンドライン引数として直接指定するか、プログラム内のデフォルト値が使用されます。

生成される出力ファイル

プログラムを実行すると、ウェブサイトの階層的なサイトマップが記述されたHTMLファイルが生成されます。

  • ファイル名: デフォルトでは sitemap.html という名前で保存されます。この名前はコマンドライン引数で変更可能です。

  • 内容:

    • 生成されたHTMLファイルは、指定されたルートURLから辿り着けるすべてのページ(フィルタリングされた後)を、階層的なツリービューとして表示します。

    • 各ノード(ページ)には、そのページのタイトル、完全なURLへのリンク、そして発見された場合は最終更新日が含まれます。

    • フォルダのようなパスセグメントは折りたたみ可能な<details>タグで表示され、その下に子ページやサブディレクトリがネストされます。

    • RootURL, OutputFile, Exclude Files, Exclude Path Patterns などの実行時設定がHTMLファイル上部に表示されます。

    • Tailwind CSSのCDNが読み込まれており、モダンで使いやすいデザインが適用されています。

コマンドラインでの使用例 (Usage)

MakeSiteMap.py は、以下の形式でコマンドラインから実行できます。

python MakeSiteMap.py [RootURL] [OutputFile] [ExcludeFiles(True/False)]
  • RootURL: クロールを開始するウェブサイトのルートURL。

    • 省略した場合、プログラム内のデフォルト値 http://d2mate.mdxes.iir.isct.ac.jp/D2MatE/D2MatE_programs.html?page=statistcs が使用されます。

  • OutputFile: 生成されるHTMLサイトマップファイルのパスと名前。

    • 省略した場合、デフォルトで sitemap.html が使用されます。

  • ExcludeFiles(True/False): 特定のファイル拡張子(.pdf, .jpg など)を持つURLをサイトマップから除外するかどうかを指定します。

    • True, 1, t のいずれかを指定すると除外が有効になります。

    • それ以外の値を指定するか省略すると、除外は無効になります。

    • デフォルトは True です。

パス除外パターンについて: EXCLUDE_PATHS 変数に定義された正規表現パターンは、コマンドライン引数では変更できませんが、プログラムのソースコードを直接編集することでカスタマイズ可能です。

コマンドラインでの具体的な使用例

例1: デフォルト設定での実行

ルートURL、出力ファイル名、ファイル除外設定を全てデフォルト値のまま実行します。

python MakeSiteMap.py
  • RootURL: http://d2mate.mdxes.iir.isct.ac.jp/D2MatE/D2MatE_programs.html?page=statistcs が使用されます。

  • OutputFile: sitemap.html が生成されます。

  • ExcludeFiles: True (ファイル除外有効) となります。

  • EXCLUDE_PATHS: ソースコードに定義されたパス除外パターンが適用されます。

実行結果: sitemap.html というファイルが現在のディレクトリに生成されます。このファイルをウェブブラウザで開くと、指定されたルートURLからクロールされたページの階層的なリストが表示されます。PDFや画像ファイルなどの一般的なファイルは、サイトマップの対象外としてスキップされます。コンソールにはクロール中のURL、その文字コード、タイトル、最終更新日などの情報が表示されます。


例2: 特定のURLと出力ファイルを指定して実行

自身のウェブサイトをクロールし、my_website_sitemap.html という名前で出力する場合。

python MakeSiteMap.py https://www.example.com/ my_website_sitemap.html
  • RootURL: https://www.example.com/ からクロールが開始されます。

  • OutputFile: my_website_sitemap.html が生成されます。

  • ExcludeFiles: デフォルトの True (ファイル除外有効) となります。

  • EXCLUDE_PATHS: ソースコードに定義されたパス除外パターンが適用されます。

実行結果: my_website_sitemap.html というファイルが生成され、https://www.example.com/ のウェブサイト構造が視覚化されます。


例3: ファイル除外を無効にして実行

すべてのファイルタイプ(HTML以外のPDFや画像なども)をサイトマップに含めたい場合。

python MakeSiteMap.py https://docs.python.org/3/ python_docs_full_sitemap.html False
  • RootURL: https://docs.python.org/3/ からクロールが開始されます。

  • OutputFile: python_docs_full_sitemap.html が生成されます。

  • ExcludeFiles: False となるため、指定された除外ファイル拡張子のリストは無視され、すべてのファイルタイプがサイトマップの対象となりえます。ただし、is_target_url 関数の基本的なHTML/ディレクトリパス判定は残るため、例えばURL自体に拡張子がないパスはHTMLとみなされます。

  • EXCLUDE_PATHS: ソースコードに定義されたパス除外パターンは引き続き適用されます。

実行結果: python_docs_full_sitemap.html が生成され、Pythonドキュメントサイト内のHTMLページだけでなく、CSSやJavaScriptファイル(find_urls_in_html で除外されない限り)、その他の文書ファイルなどもサイトマップに含まれる可能性があります。これにより、サイト内のあらゆるリソースの構造を把握するのに役立ちます。