自動化スクレイピング

クロールは「リンク探索」から卒業する ― Sitemap起点のURL発見設計

サイトマップ(XML Sitemap)を起点に、最短でURL収集とクロール設計を行う入門ガイド。robots.txtからの発見、sitemapindex対応、lastmodを使った差分クロール、正規化・重複排除まで実装例で解説。

Ibuki Yamamoto
Ibuki Yamamoto
2026年2月20日 10分で読めます

スクレイピング(クローリング)で「必要なURLだけを、最短で、漏れなく集めたい」と思っても、リンクを辿る方式だけでは遠回りになりがちです。そこで効くのがサイトマップ(XML Sitemap)。本記事では、サイトマップを起点にしたクロール設計の考え方と、実装時の注意点を、入門者向けに整理します。

この記事でわかること
  • サイトマップを使うクロール設計の基本
  • 最短でURL収集する具体手順と優先順位
  • 落とし穴(lastmod、重複、ブロック)への対処

サイトマップの基礎

サイトマップ(XML Sitemap)は、サイト内のURL一覧を検索エンジン等のクローラーに伝えるための仕組みです。スクレイピングでも同様に、対象URL群の「公式インデックス」として活用できます。

XMLサイトマップの要素

サイトマップの主要タグは <loc>(URL)と、任意で <lastmod>(更新日)などです。仕様では <changefreq><priority> も定義されています。詳しくは仕様を参照してください。

押さえておきたい結論:スクレイピングで最も価値が高いのは、まず <loc> によるURL集合の確定です。次に <lastmod> を活用できると差分クロールが楽になります。

最短クロールの設計

「最短」を目指すなら、リンク探索よりも先に URLの母集団 を確定し、不要URLを早めに捨てるのが基本方針です。サイトマップはこの方針と相性が良い手段です。

まずURL集合を確定

  1. サイトマップURLを発見(/sitemap.xml/sitemap_index.xml が典型)
  2. サイトマップ(またはインデックス)を取得してURLを列挙
  3. 正規化(末尾スラッシュ、クエリ、http/httpsの扱い)
  4. 収集対象のパスだけ残す(例:/product/ のみ)

優先順位の付け方

次の順で優先度を決めると、業務用途でも事故が減ります。

  • 重要度(業務要件):商品ページ、店舗一覧、求人など「欲しいデータがあるURL」
  • 更新頻度:更新が多いURLを先に(ただし後述のとおりタグを過信しない)
  • コスト:重いページ(JS多用、巨大HTML)やレート制限が厳しい領域は後回し

注意:サイトマップに <changefreq><priority> が入っていても、常に信頼できるとは限りません。スクレイピング設計では「自分の要件(重要URL)」を優先し、タグは参考情報として扱うのが安全です。

差分クロールの考え方

<lastmod> が正しく運用されているサイトでは、前回クロール以降に更新されたURLだけを再取得できます。これにより、巡回時間・通信量・ブロックリスクをまとめて下げられます。

ただし、仕様上も「サイトマップ生成日」ではなく「対象ページの更新日」を入れることが前提です。誤った <lastmod> が入っているケースもあるため、実データ(HTMLやAPI応答の更新日時)と突合して妥当性を検証してください。

実装の最短手順

ここからが本題です。サイトマップを使ったURL収集の手順を、Pythonを例に示します(requests + 標準XMLパーサ)。

サイトマップを発見

まずは robots.txt を見に行き、Sitemap: 行からサイトマップURLを拾うのが堅実です(複数行ある場合もあります)。

import re
import requests


def discover_sitemaps(base_url: str):
    robots_url = base_url.rstrip("/") + "/robots.txt"
    r = requests.get(robots_url, timeout=20)
    r.raise_for_status()

    sitemaps = []
    for line in r.text.splitlines():
        m = re.match(r"(?i)^sitemap:\s*(\S+)", line.strip())
        if m:
            sitemaps.append(m.group(1))
    return sitemaps


print(discover_sitemaps("https://example.com"))

サイトマップを解析

サイトマップは「URL一覧のXML(urlset)」だけでなく、「サイトマップの一覧(sitemapindex)」の場合があります。両方に対応して、最終的にURLのリストを返すようにします。

import requests
import xml.etree.ElementTree as ET

NS = {"sm": "http://www.sitemaps.org/schemas/sitemap/0.9"}


def fetch_xml(url: str) -> ET.Element:
    r = requests.get(url, timeout=30)
    r.raise_for_status()
    return ET.fromstring(r.content)


def parse_sitemap(url: str):
    root = fetch_xml(url)

    # sitemapindex
    if root.tag.endswith("sitemapindex"):
        locs = [e.find("sm:loc", NS).text for e in root.findall("sm:sitemap", NS)]
        urls = []
        for loc in locs:
            urls.extend(parse_sitemap(loc))
        return urls

    # urlset
    if root.tag.endswith("urlset"):
        out = []
        for u in root.findall("sm:url", NS):
            loc = u.find("sm:loc", NS).text
            lastmod_el = u.find("sm:lastmod", NS)
            lastmod = lastmod_el.text if lastmod_el is not None else None
            out.append({"loc": loc, "lastmod": lastmod})
        return out

    raise ValueError(f"Unknown sitemap root: {root.tag}")


items = parse_sitemap("https://example.com/sitemap.xml")
print(len(items), items[:3])

実務のコツ:最初に「URL収集(サイトマップ)」と「ページ取得(クロール)」を分離してください。URL収集を先に完了させると、重複排除・優先順位付け・リトライ設計が簡単になります。

フィルタと正規化

サイトマップには、収集対象外のURL(タグ、検索結果、ヘルプ、言語別など)が混ざることがあります。そこで、パスプレフィックス等でフィルタします。

from urllib.parse import urlparse, urlunparse


def normalize_url(u: str) -> str:
    p = urlparse(u)
    # クエリやフラグメントを落とす(要件次第で保持)
    p = p._replace(query="", fragment="")
    # 末尾スラッシュ統一はサイト仕様に合わせる
    return urlunparse(p)


def filter_urls(items, allow_prefixes):
    out = []
    for it in items:
        loc = normalize_url(it["loc"])
        path = urlparse(loc).path
        if any(path.startswith(prefix) for prefix in allow_prefixes):
            out.append({**it, "loc": loc})
    return out


filtered = filter_urls(items, allow_prefixes=["/product/", "/item/"])
print(len(filtered))

よくある落とし穴

サイトマップが複数ある

大規模サイトでは、サイトマップを分割し「サイトマップインデックス」で束ねる構成が一般的です。実装では sitemapindex を必ず処理できるようにしておきましょう。

lastmodが信用できない

<lastmod> は差分クロールに有効ですが、運用が雑だと「全部が当日更新」になっていることもあります。その場合は以下の方針に切り替えるのが現実的です。

  • HTTPの ETag / If-Modified-Since を使う(サーバが対応していれば)
  • 重要ページだけは定期巡回、その他は低頻度にする
  • ページ内の更新日時(例:商品更新日)を抽出して比較する

正規URLと重複

サイトマップには「正規URL(canonical)」のみを載せるのが推奨ですが、実際にはパラメータ付きURLや多言語URLが混在する場合もあります。URL正規化(クエリの扱い、末尾スラッシュ、大小文字、www有無)と重複排除は必須です。

robots.txtと衝突

サイトマップでURLを見つけても、robots.txt でクロールを禁止している領域は取得しないのが原則です。クロール対象の設計時に、robots.txt のルールを読み取り、禁止パスをキュー投入前に弾いてください。

注意:スクレイピングは対象サイトの利用規約・法令・技術的制限(レート制限等)に配慮が必要です。サイトマップが公開されていることは「何でも自由に取得してよい」ことを意味しません。

サイトマップ比較

最後に、URL収集の起点として「サイトマップ」「リンク探索」「サイト内検索(一覧ページ)」を比較します。最短設計では、サイトマップを主軸にしつつ、欠落補完として他手段を併用するケースが多いです。

手段 強み 弱み 向くケース
サイトマップ URL収集が速い、網羅性が高い 欠落・誤運用があり得る 商品/記事などURLが多いサイト
リンク探索 サイトマップが無い場合でも動く 深い階層に時間がかかる 小規模サイト、導線が整理されたサイト
一覧ページ起点 カテゴリ構造を反映しやすい ページングやJSで欠落しやすい カテゴリ別に収集したい場合

クロール設計を短縮しませんか?

サイトマップ起点の設計から運用まで整えると、収集の速度と安定性が上がります。要件に合わせたクロール設計の相談も可能です。

お問い合わせスクレイピングに関するご相談・お見積もりはお気軽にどうぞ
相談する

まとめ

  • 最短クロールの第一歩は、リンク探索の前にサイトマップでURL集合を確定すること
  • <lastmod> が正しければ差分クロールに有効。ただし誤運用もあるため検証が必要
  • URL正規化・重複排除・robots.txt配慮まで含めて設計すると、運用が安定する

公式仕様や検索エンジンのガイドは、挙動の前提を確認するのに役立ちます。必要に応じて参照してください。


この記事を書いた人

Ibuki Yamamoto
Ibuki Yamamoto

Webスクレイピングエンジニア。10年以上の実務経験を持ち、大規模なデータ収集プロジェクトを数多く手がける。PythonとJavaScriptを得意とし、技術ブログでは実践的なスクレイピング手法を発信している。

データ収集のプロに
お任せください

年間1億件以上のデータ収集実績を持つプロフェッショナルチームが、大規模スクレイピング・アンチボット対策など、あらゆる課題を解決します。

1億+
年間データ収集件数
24/7
安定稼働
高品質
データ精度