開示事項:私たちは Geonode であり、プロキシを販売しています。これは、記事の終盤で説明するクローリング手法の要素の一つです。 正直なところ、クローリングは最初に試すべきものではなく、最後に試すべきものです。 以下の8つの情報源のうち5つは無料で、インフラも不要であり、多くの場合、クローリングよりも完全なリストを作成できます。なぜなら、どこからもリンクされていないページも含まれているからです。 もし最初にクローラーを作成し始めると、作業量は増える一方で、カバーできる範囲は狭くなってしまいます。無料の情報源には埋めるべき空白があることが確認できてから、帯域幅を購入してください。そのタイミングは、多くの人が想定しているよりもずっと後になります。
「すべてのページ」に完全な答えがない理由
4つの理由があり、いずれも構造的なものです。
孤立ページが存在するからです。 被リンクのないページは、クロールでは到達できず、検索エンジンからは見えませんが、存在しており、公開されている可能性があります。古いランディングページ、キャンペーンURL、廃止されたセクションなどはすべてこのカテゴリーに該当します。
フォームや認証の背後にあるコンテンツは列挙できない。 検索結果、フィルタリングされたビュー、およびログインを必要とするものはすべて、検索によって特定することができない。
動的URLは無限に生成される可能性がある。 翌月のリンクを含むカレンダーは、無制限のURLを生成する。ECサイトのファセットナビゲーションは、組み合わせの爆発を引き起こす。「すべてのページ」は、一部のサイトでは有限な集合ではない。
サイトは「記載漏れ」によって事実を隠蔽している。 サイトマップには、所有者が掲載することを選択した内容が含まれており、それは多くの場合、実際に存在するページではなく、インデックス登録を希望するページである。
したがって、現実的な目標は「完全性」ではなく、目的を果たすのに十分な網羅性である。つまり、どの情報源を選択するかは、調査の目的によって異なるということだ。
サイトマップから始めよう
最も生産性の高い最初のステップであり、多くの人が見落としがちなものです。
サイトマッププロトコル は、サイトの URL を一覧表示する XML 形式を定義しています。サイトマップは「<urlset> タグで始まり、</urlset> タグで終わらなければならない」とされており、各エントリには <loc> 要素が必要です。オプションの <lastmod>、<changefreq>、<priority> 要素を併記することも可能ですが、プロトコルでは、これらの扱いは「検索エンジンによって異なる場合がある」と注記されています。
これらの制限は検索結果に影響します。1つのサイトマップファイルは「50,000件のURL」が上限であり、サイズは「50MB(52,428,800バイト)以下」でなければなりません。 大規模なサイトでは、他のサイトマップを一覧表示する<sitemapindex>である「サイトマップインデックス」が使用されますが、これにも同じ制限が適用されるため、1つのサイトに数十個のサイトマップファイルが存在する場合があります。
参照先:
https://example.com/sitemap.xml
https://example.com/sitemap_index.xml
https://example.com/sitemap.xml.gz
Gzip圧縮は許可されていますが、「解凍後のファイルは依然としてサイズ制限に準拠している必要があります」。
また、まず robots.txt を確認してください。このプロトコルでは、Sitemap: ディレクティブを使用して、そこにサイトマップを登録することが規定されているためです:
curl -s https://example.com/robots.txt | grep -i sitemap
これは、利用可能な最長の30秒間です。多くのサイトでは、製品、カテゴリ、ブログ記事、画像など、個別に作成されたサイトマップが複数リストされており、その名前は通常では想像もつかないようなものです。
インデックスを再帰的に追跡してください。 サイトマップのインデックスは、さらに別のサイトマップを指し示している可能性があります。それぞれを取得し、<loc>の値を抽出してください。なお、インデックス内のエントリはサイトマップファイルであるのに対し、urlset内のエントリはページであることに注意してください。
<lastmod>フィールドも、ここから始めるべきもう一つの理由です。このフィールドは変更された箇所を教えてくれるため、再クロールが、移動した少数のページのみを取得する作業に変わります。
robots.txt から読み取れる情報
サイトマップに関する指示以外にも、robots.txt には、サイト所有者が言及する価値があると判断したパスが一覧として記載されています。
Disallow: /admin/
Disallow: /internal/reports/
Disallow: /checkout/
Disallow: /search?
Disallowの各行には、実際に存在するパスが記載されています。これは侵入経路ではありません。クロールすべきでない箇所を示す声明であり、これを尊重することは正しい行為であると同時に、正規のクローラーと迷惑なクローラーを区別する基準でもあります。しかし、このファイルからはサイトの構造が読み取れ、知らなかったセクションが記載されていることもよくあります。
これを「ターゲットリスト」ではなく「地図」として読み取ってください。アクセスが禁止されているパスはクロール対象から外しておくべきですが、その存在を知ることで、サイトに対する理解を深めることができます。
検索エンジンの演算子
高速、無料、かつ部分的な検索。
site:example.com
site:example.com inurl:/products/
site:example.com -inurl:/blog/
site:example.com filetype:pdf
この検索で得られるもの:検索エンジンがインデックスに登録したページ。これは、実際に存在するページの一部に過ぎません。また、検索結果は上限が設けられており、網羅的ではなく概算値となります。
真に役立つ場面:知らなかったサブドメインやセクションの発見、およびナビゲーションからリンクされていないドキュメントファイルの検索です。企業サイトで「filetype:pdf」と検索すると、通常、誰も公開されているとは思わなかった資料が頻繁に表示されます。
制限として、検索結果を直接スクレイピングすることはほとんどの検索エンジンの利用規約に違反するほか、手動での操作は時間がかかります。プログラムで処理する必要がある場合は、Webインターフェースを自動化するのではなく、利用可能な場合は公式の検索APIを使用してください。
Webアーカイブ
多くの人が見落としがちな情報源であり、もはや存在しないページを見つけ出せる唯一の手段です。
インターネット・アーカイブの CDXサーバーAPI は、アーカイブのキャプチャインデックスを直接照会します。 ドキュメントには、「CDXサーバーに対する最も単純なクエリであり、唯一必須のパラメータはurlパラメータである」と記載されています。
curl -s "http://web.archive.org/cdx/search/cdx?url=example.com/*&output=json&fl=original&collapse=urlkey&limit=10000"
知っておくべきパラメータは以下の通りです:
**matchType
** は範囲を制御します。exact
は1つのURLに一致し、prefix
はパス以下のすべてを返し、host
は単一のホスト名を対象とし、domain
はドメインとそのすべてのサブドメインを対象とします。 URL にワイルドカードが含まれている場合、これは暗黙的に設定されるため、example.com/*
はプレフィックスマッチングとなります。
**collapse=urlkey
** は隣接する重複を削除します。アーカイブには同じ URL のキャプチャが多数保存されているため、これは不可欠です。
**output=json
** はデフォルトの CDX テキスト形式よりも便利であり、gzip=false
は、クライアントが gzip エンコーディングに対応していない場合に、デフォルトの gzip エンコーディングを無効にします。
制限事項: このAPIは「クエリあたり最大150,000件」というデフォルト制限を設けていますが、limit=N
で調整可能です。また、より大規模なクエリについては、ドキュメントではpage
およびpageSize
を使用したページネーションAPIの利用が推奨されています。
これが特に価値ある理由:過去のURLを明らかにしてくれる点です。削除されたページ、再構成されたセクション、リンクが切れたキャンペーンのランディングページなどです。サイトが以前どのような状態だったかを理解したり、まだ公開されている孤立したコンテンツを見つけたりするには、これに勝る手段はありません。しかも、対象サイトへの負荷は一切かかりません。
Common Crawl
クエリを実行できるインデックスを備えた大規模な公開クロールコーパスであり、その真価が十分に活かされていないリソースです。
Common Crawl は、ウェブの相当な部分を定期的にクロールしたデータと、URL インデックスを公開しています。これをクエリすることで、サイトにアクセスすることなく、そのドメインについてクロールが検出した URL を一括して取得できます。
そのトレードオフは明白です。網羅性は高いものの完全ではありません。これはクロールデータであるため、他のクロールと同様に死角が存在します。情報の鮮度は、どのクロールデータをクエリするかによって異なります。また、インデックスを大規模にクエリすることは、単一のリクエストというよりは、データ処理作業となります。
その真価が発揮されるのは、大規模な調査、多数のドメインの比較、およびサイトへのトラフィックを発生させることなくその状況を把握したいあらゆる場面です。
クローリング:最後の手段、その正しいやり方
無料の情報源ではカバーしきれない部分がある場合は、クローリングを行ってください。その際、問題を引き起こさないように注意して実施しましょう。
基本的なループ: ページを取得し、リンクを抽出し、対象ドメインに絞り込み、新しいリンクをキューに入れ、キューが空になるまで繰り返します。 原理は単純だが、細部には多くの注意点がある。
重要な詳細:
robots.txt を遵守する。 これは現在標準となっている――RFC 9309では、順序ではなく特異性によるマッチングを定義し、少なくとも1日1回のファイル更新を義務付け、サーバーエラーを完全なアクセス拒否として扱う。 パーサーを自作するのではなく、メンテナンスされているライブラリを使用しましょう。
URLを徹底的に正規化しましょう。 末尾のスラッシュ、クエリパラメータの順序、ホスト名の大文字小文字、セッション識別子、トラッキングパラメータはすべて重複の原因となります。正規化を行わないクローラーは、同じページを何百回も訪問することになります。
クロールを制限する。 深さの制限、ページ数の制限、カレンダーやファセットナビゲーションに対するパターンの除外など。これらがないと、一部のサイトは無限にクロールされ続けてしまう。
リクエストレートを自ら制限する。 1秒または2秒に1回のリクエストは礼儀正しく、ほとんどの作業にとって十分である。robots.txtのCrawl-delayは、尊重すべきリクエストである。
自身を識別する。 名前と連絡先URLを持つユーザーエージェントは、匿名の自動化プログラムに比べてブロックされる可能性がはるかに低くなります。
キャッシュを活用し、条件付きリクエストを使用する。 If-Modified-Since や If-None-Match を使用することで、再クロールを低負荷な一連の304レスポンスに変えることができます。
プロキシが役立つ場面: 本格的な大規模なクロール時、単一のアドレスがレート制限を受けた場合、またはコンテンツが地域によって異なる場合です。それ以前には使用しないでください。 この用途では、データセンターの帯域幅が合理的なデフォルト設定です(当社の場合は2026年9月時点で1GBあたり0.14ドルから)。住宅用回線への切り替えは、データセンターが明らかに機能不全に陥った場合にのみ検討すべきです。
知っておくべきその他の情報源
特定の情報を補完する4つの小規模な情報源。
証明書透明性(CT)ログ。 発行されたすべてのTLS証明書は公開ログに記録されており、証明書にはホスト名が記載されています。CTログアグリゲーターでドメインを照会すると、サブドメインが明らかになります。これには、他の手段では決して見つかることを意図していなかった、内部向けと思われるサブドメインも含まれます。これはサブドメインを発見する上で最も優れた手法であり、ターゲットとの接触を一切必要としません。
RSSおよびAtomフィード。 現在も広く公開されており、日付付きの構造化された形式でコンテンツを一覧表示しています。/feed、/rss、/atom.xml、およびページのヘッダーにある<link rel="alternate">タグを確認してください。
サイト独自の検索機能とナビゲーション。 A~Zの索引、タグ一覧、カテゴリページ、HTML形式のサイトマップページなど――多くのサイトが人間向けの訪問者向けにこれらを公開しており、XMLサイトマップよりも網羅性が高い場合が頻繁にあります。
フロントエンドの背後にあるAPI。 サイトがシングルページアプリケーション(SPA)である場合、コンテンツを取得するためにAPIを呼び出しており、そのAPIは多くの場合、すべての情報を構造化された形式で返す一覧エンドポイントを公開しています。ブラウザのネットワークタブを確認してみてください。これは現代のサイトにおいて常に最速のルートですが、人々が最後に気づくものとなっています。
ソースの統合
本格的な列挙を行うための実用的な方法、および順序が重要な理由。
個別に収集し、統合する。 サイトマップのURL、アーカイブのURL、フィードのURL、およびクロール結果を1つのセットにまとめる。統合する前に正規化を行わないと、同じページが複数回カウントされてしまう。
有効性を確認する。 アーカイブURLは、今日になって404エラーを返す可能性がある。URLごとにHEAD
リクエストを送信するコストは低い:
while read -r url; do
code=$(curl -sIL -o /dev/null --max-time 10 -w '%{response_code}' "$url")
echo "$code $url"
done < urls.txt
情報源同士を比較する。 アーカイブにはあるがサイトマップにはないURLは、削除されたページか孤立したページである。サイトマップにはあるが404エラーを返すURLは、古いエントリである。 クロールで検出されたがサイトマップに存在しないURLは、所有者がインデックス登録を望んでいなかったページです。こうした差異の一つひとつが情報となります。
経時的な変化を追跡する。 定期的に再実行して差分を確認することで、何が追加され、何が削除されたかがわかります。これは、多くの場合、「すべてのページを見つける」という要求の背後にある真の目的そのものです。
実践的な手順
作業負荷が最小限になる順序で、ソースを単一のドメインにまとめる。
1 — 宣言されているサイトマップを見つける:
DOMAIN="example.com"
curl -s "https://$DOMAIN/robots.txt" | grep -i '^sitemap:' | awk '{print $2}' > sitemaps.txt
# fall back to the conventional locations if nothing is declared
[ -s sitemaps.txt ] || printf 'https://%s/sitemap.xml\nhttps://%s/sitemap_index.xml\n' "$DOMAIN" "$DOMAIN" > sitemaps.txt
2 — インデックスを展開し、URLを収集する。 サイトマップインデックスには他のサイトマップを指す <loc>
値が含まれており、urlset にはページを指す <loc>
値が含まれているため、同じ抽出処理が両方のレベルで機能し、単にそれを繰り返すだけで済みます:
extract() { curl -s --compressed "$1" | grep -o '<loc>[^<]*</loc>' | sed 's/<[^>]*>//g'; }
: > all_urls.txt
while read -r sm; do
extract "$sm" | while read -r u; do
case "$u" in
*.xml|*.xml.gz) extract "$u" >> all_urls.txt ;;
*) echo "$u" >> all_urls.txt ;;
esac
done
done < sitemaps.txt
sort -u all_urls.txt -o all_urls.txt
wc -l all_urls.txt
3 — アーカイブのビューを追加する:
curl -s "http://web.archive.org/cdx/search/cdx?url=${DOMAIN}/*&output=text&fl=original&collapse=urlkey&limit=50000" \
| sort -u > archive_urls.txt
wc -l archive_urls.txt
4 — 単に結合するのではなく、比較を行う。 ここで興味深い出力が得られます:
comm -13 all_urls.txt archive_urls.txt > only_in_archive.txt # orphaned or removed
comm -23 all_urls.txt archive_urls.txt > only_in_sitemap.txt # new or never archived
only_in_archive.txt
は、まず確認すべきリストです。これらは、サイトがかつて提供していたものの、現在は公開されていないURLです。一部は404エラーを返すでしょうし、エラーが出ないものは、誰もリンクしていない稼働中のページです。
5 — 何かを信頼する前に、稼働状況を確認する。 どちらのリストにも古いエントリが含まれており、URL 1件あたりの HEAD
リクエストは、ページ全体をリクエストするよりも数百バイト程度のデータ量で済みます:
while read -r u; do
printf '%s %s\n' "$(curl -sIL -o /dev/null --max-time 10 -w '%{response_code}' "$u")" "$u"
done < only_in_archive.txt | tee liveness.txt
grep '^200 ' liveness.txt | wc -l
意図的な順序に注意してください:4つの情報源を参照し、数千のURLを収集しましたが、クローラーによるクロールは一切行っていません。ほとんどのサイトにおいて、この方法ではクローラーを使用する場合よりも完全な全体像を、わずかな時間で得ることができ、対象サイトもあなたがそこにいたことにほとんど気づきません。
よくある質問
ウェブサイトのすべてのページを見つけるにはどうすればよいですか?
まず robots.txt から始めてサイトマップの記述を探し、サイトマップを取得して、インデックスファイルがあればそれをたどります。さらに、過去のURLやRSSフィードについてはインターネットアーカイブのCDX APIを、site:の検索も併用してください。 これらで見逃された部分のみをクロールしてください。これは最も時間がかかり、サイトへの負荷も大きい方法です。
ウェブサイトのサイトマップはどこにありますか?
通常は /sitemap.xml または /sitemap_index.xml にあります。確実に見つける方法は、robots.txt 内の Sitemap: ディレクティブを確認することです。大規模なサイトでは、各サイトマップファイルが 50,000 個の URL と 50MB に制限されているため、複数のファイルを指すサイトマップインデックスを使用しています。
どこからもリンクされていないページを見つけることはできますか?
場合によります。クロールでは定義上それらを見つけることはできませんが、ウェブアーカイブではしばしば見つけることができます。Internet ArchiveのCDX APIは、もはやリンクされていないものを含め、過去のURLを返します。また、証明書透過性(CT)ログからも、どこからもリンクされていないサブドメインが明らかになります。
ウェブサイトのすべてのサブドメインを見つけるにはどうすればよいですか?
証明書透明性(CT)ログが最良の情報源です。発行されたすべてのTLS証明書は、ホスト名とともに公開ログとして記録されているためです。検索エンジンのオペレーターやDNS列挙ツールも、これを補完します。これらはいずれも、対象サイトに連絡する必要はありません。
ウェブサイトをクロールしてページ一覧を作成することは合法ですか?
管轄区域、サイトの利用規約、および結果の用途によって異なります。「robots.txt」を遵守し、クローラーを識別し、アクセス頻度を適度な範囲に抑えることで、通常の慣行の範囲内に収まります。ただし、利用規約によっては自動アクセスが禁止されている場合もあり、これは確認すべき契約上の問題です。
サイトマップにはいくつのURLを含めることができますか?
1ファイルあたり50,000件で、非圧縮時のサイズ上限は50MBです。これを超える場合、サイトでは複数のサイトマップファイルを一覧表示するサイトマップインデックスを使用します。なお、インデックス自体も同様に50,000件および50MBの上限が適用されます。
Wayback CDX APIとは何ですか?
インターネットアーカイブのキャプチャインデックスへのインターフェースであり、特定のドメインについてアーカイブされたURLを返します。matchType では、単一のURLからドメインおよびすべてのサブドメインまでの範囲を指定でき、collapse=urlkey では重複するキャプチャを削除します。デフォルトの結果上限は150,000件ですが、より大規模なクエリにはページネーションAPIが用意されています。
Webサイトのページを列挙するのにプロキシは必要ですか?
サイトマップ、アーカイブ、フィード、検索といった手法では必要ありません。これらはいずれも、実質的な負荷を生じさせません。プロキシが必要になるのは、単一のアドレスでレート制限がかかるような大規模なクロールや、地域によってコンテンツが異なる場合です。何かを購入する前に、無料のリソースに不足がないか確認してください。
まとめ
ウェブサイトのページを網羅した完全なリストなど存在せず、あるのは部分的なビューの集合に過ぎません。そこで役立つ手法は、コストのかかるビューを構築する前に、コストの低いビューをまず集めることです。
robots.txt で 30 秒ほど検索すれば、サイトマップの宣言が見つかります。サイトマップのインデックスを数分間たどれば、サイト所有者が自サイトをどう捉えているかが分かります。インターネットアーカイブの CDX API を使えば、かつて存在したページや、もはや誰もリンクしていないページも追加できます。フィード、証明書透明性ログ、そしてサイト独自の HTML インデックスは、それぞれ異なる空白を埋めてくれます。 これらはすべて無料で、対象サイトに負荷をかけることもありません。
robots.txtを尊重し、URLを正規化し、クロールの範囲を限定し、レートも控えめに保ちながら、残っているものをクロールしましょう。その際、まずそのサイトがAPIを呼び出すシングルページアプリケーション(SPA)かどうかを確認してください。その方法の方が通常はクロールよりも高速であり、ほとんどの場合見落とされがちだからです。
その後、単に統合するのではなく、ソースを比較してください。アーカイブには含まれているがサイトマップにはないページや、現在404を返すサイトマップのエントリは、この作業全体を通じて得られる最も興味深い情報となることがよくあります。
