robots.txt はクローラーに「どこを巡回してよいか」を伝えるファイルで、sitemap.xml は「巡回してほしいURLの一覧」を伝えるファイルです。 前者は巡回の範囲を絞り、後者は巡回の入口を増やします。2つは役割が逆向きなので、セットで設計すると迷いが減ります。

この記事では、Google の公式仕様(RFC 9309 準拠)を確認したうえで、構文の早見表、そのまま使えるテンプレート(一般サイト/WordPress/静的サイト/AIクローラーだけ拒否)、Python で「どのURLがどのクローラーに許可されるか」を判定した実行結果、sitemap.xml の自動生成スクリプトと xmllint での検証結果をまとめました。Python 標準の urllib.robotparser と Google の判定ルールが実際に食い違うケースも、出力つきで紹介します。

robots.txt・sitemap.xmlの早見表

やりたいこと 書き方 ポイント
全クローラーに全ページを許可 User-agent: * + Disallow:(空) 空の Disallow は「制限なし」
全ページの巡回を止める User-agent: * + Disallow: / 公開前の検証環境などに
ディレクトリを除外 Disallow: /admin/ 前方一致。/admin/ 以下すべて
除外の中の一部だけ許可 Disallow: /admin/ + Allow: /admin/public/ Google は長いパスのルールが優先
パラメータ付きURLを除外 Disallow: /*?sort= * は0文字以上の任意文字列
拡張子で除外 Disallow: /*.pdf$ $ はURLの末尾
AI学習用クローラーだけ拒否 User-agent: GPTBot 等 + Disallow: / 検索用クローラーは別名なので影響なし
サイトマップの場所を伝える Sitemap: https://example.com/sitemap.xml 絶対URL。グループの外に書ける
検索結果から消す robots.txt では不可 noindex(meta / X-Robots-Tag)を使う
sitemap.xml の上限 1ファイル 50,000 URL / 50MB(非圧縮) 超えたら分割して sitemap index
priority / changefreq 書いてもよいが Google は無視 lastmod を正確に書くほうが効果的
置き場所 https://ホスト/robots.txt(ルート直下) ホスト・プロトコル・ポートごとに別扱い

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「robots.txt・sitemap.xmlの書き方|テンプレートと検証手順」

robots.txtの基本:Googleの仕様を確認

robots.txt の規格は RFC 9309(Robots Exclusion Protocol)で、Google はこれに沿って処理します。 公式ドキュメント(Google 検索セントラル「Google による robots.txt の指定の解釈」)で確認した主な仕様は次のとおりです。

項目 Google の仕様
準拠規格 RFC 9309
サイズ上限 500KiB。超えた部分は無視される
文字コード UTF-8 のプレーンテキスト。改行は CR、CR/LF、LF のいずれか
有効なフィールド user-agent、allow、disallow、sitemap の4つ(crawl-delay は Google 非対応)
大文字・小文字 フィールド名は区別しない。パスは区別する(/Admin/ と /admin/ は別)
適用範囲 置いたホスト・プロトコル・ポートのみ(www ありなし、サブドメインは別ファイル)
キャッシュ 通常最大24時間キャッシュされる
3xx 少なくとも5回までリダイレクトを追い、それ以上は 404 扱い
4xx(429除く) robots.txt がないものとして扱う(=制限なし)
5xx 最初の12時間は巡回停止、その後30日間は最後に取得できた内容を使う

構文の早見表

記号・フィールド 意味 例 マッチする例
User-agent: ルールを適用するクローラー名 User-agent: Googlebot Googlebot
User-agent: * 名前で指定されていない全クローラー User-agent: * 個別指定のないクローラー
Disallow: 巡回しないパス(前方一致) Disallow: /tmp/ /tmp/a.html
Allow: 巡回してよいパス Allow: /tmp/ok.html /tmp/ok.html
* 0文字以上の任意文字列 Disallow: /*.json /api/a.json、/a.json?x=1
$ URLの末尾 Disallow: /*.json$ /a.json(/a.json?x=1 は対象外)
# コメント # 管理画面 ―
Sitemap: サイトマップの絶対URL Sitemap: https://example.com/sitemap.xml ―

最長一致のルール(AllowとDisallowが両方当たるとき)

Google は、URLに当たるルールのうち「パスが最も長い(具体的な)ルール」を採用し、長さが同じなら制限の少ないほう(Allow)を採用します。 書いた順番は関係ありません。

ルール URL 当たるルール 結果
Disallow: /admin/ Allow: /admin/public/ /admin/public/help.html Allow(14文字)が Disallow(7文字)より長い 許可
Disallow: /admin/ Allow: /admin/public/ /admin/login Disallow のみ 拒否
Allow: /page Disallow: /page /page 同じ長さ 許可(制限が少ないほう)
Allow: /$ Disallow: / / /$ のほうが長い 許可(トップだけ許可)
Allow: /$ Disallow: / /news Disallow のみ 拒否

User-agentのグループの書き方

1つのクローラーに適用されるグループは1つだけです。 Google は「最も具体的に名前が一致するグループ」を使い、それ以外のグループ(* を含む)は読みません。

User-agent: *
Disallow: /admin/

User-agent: Googlebot
Disallow: /tmp/

この場合、Googlebot には Disallow: /tmp/ だけが適用され、/admin/ は巡回対象になります。Googlebot にも /admin/ を除外したいなら、Googlebot のグループにも Disallow: /admin/ を書きます。名前で個別グループを作ったら、共通ルールもそこにコピーするのが基本です。

複数のクローラーに同じルールを当てたいときは、User-agent 行を続けて書きます。

User-agent: GPTBot
User-agent: ClaudeBot
Disallow: /

コピペ用robots.txtテンプレート

一般的なサイト(管理画面と検索結果ページを除外)

User-agent: *
Disallow: /admin/
Disallow: /search
Disallow: /*?sort=
Disallow: /*?sessionid=

Sitemap: https://www.example.com/sitemap.xml

並び替えやセッションIDのパラメータは、同じ内容のURLが大量にできやすいため、巡回から外すとクロールの無駄が減ります。CSS・JavaScript・画像は、ページの表示確認に使われるので除外しないようにします。

WordPress

WordPress(5.5以降)は、物理ファイルがない場合に仮想の robots.txt を返し、コアのサイトマップ wp-sitemap.xml も自動生成します。仮想 robots.txt の既定の中身は次の形です。

User-agent: *
Disallow: /wp-admin/
Allow: /wp-admin/admin-ajax.php

Sitemap: https://www.example.com/wp-sitemap.xml

カスタマイズしたいときは、ドキュメントルートに robots.txt を置くと物理ファイルが優先されます。追加の例です。

User-agent: *
Disallow: /wp-admin/
Allow: /wp-admin/admin-ajax.php
Disallow: /?s=
Disallow: /search/

Sitemap: https://www.example.com/wp-sitemap.xml
項目 理由
Allow: /wp-admin/admin-ajax.php テーマやプラグインの表示に使われることがあるため
Disallow: /?s= サイト内検索の結果ページ。無数にURLができる
/wp-content/ は除外しない CSS・JS・画像が入っており、表示確認に必要
Sitemap の URL SEOプラグインを使う場合はそのプラグインのサイトマップURLに合わせる

静的サイト(Hugo・Astro・Next.jsの静的出力など)

User-agent: *
Disallow:

Sitemap: https://www.example.com/sitemap-index.xml

静的サイトは除外したいページがほとんどないため、「全許可+Sitemap」だけで十分なことが多いです。ビルドツールのプラグインでサイトマップを生成している場合は、出力されるファイル名(sitemap.xml か sitemap-index.xml か)を確認して合わせます。

公開前の検証環境(ステージング)

User-agent: *
Disallow: /

検証環境は robots.txt に加えて Basic 認証などのアクセス制限をかけるのが確実です。robots.txt はアクセス制御ではなく「お願い」なので、URLが外部から知られると検索結果にURLだけ表示されることがあります。本番公開時にこのファイルを持ち込まないよう、環境ごとにファイルを分けておくと安心です。

AIクローラーをブロックする書き方

主なAIクローラーの名前と用途(各社公式で確認)

AIクローラーは「モデルの学習用」と「AI検索・回答用」で名前が分かれています。 学習だけ拒否して、AI検索には表示させる、という使い分けができます。

運営 User-agent トークン 用途(公式説明の要約) robots.txt
OpenAI GPTBot 生成AIの基盤モデルの学習に使う可能性があるコンテンツの収集 従う
OpenAI OAI-SearchBot ChatGPT の検索機能にサイトを表示するため 従う
OpenAI ChatGPT-User ユーザーの操作をきっかけにしたアクセス(自動巡回ではない) 適用されない場合があると公式に記載
Anthropic ClaudeBot モデルの学習・開発用のWebコンテンツ収集 従う
Anthropic Claude-SearchBot 検索結果の品質向上のためのインデックス 従う
Anthropic Claude-User ユーザーが Claude に質問したときのWeb取得 従う
Google Google-Extended Gemini の学習と、Gemini アプリ等でのグラウンディングへの利用可否 従う
Common Crawl CCBot 公開Webのアーカイブ(多くのAI学習データの元になる) 従う

Google-Extended は「巡回するクローラー」ではなく、利用可否を伝えるためのトークンです。 実際の巡回は Googlebot が行うため、HTTP の User-Agent 文字列に Google-Extended は現れません。Google は公式に「Google-Extended は Google 検索への掲載に影響せず、ランキングの要素にも使わない」と説明しています。

テンプレート:検索は許可、AI学習は拒否

# AI学習用クローラーは拒否
User-agent: GPTBot
User-agent: ClaudeBot
User-agent: Google-Extended
User-agent: CCBot
Disallow: /

# 検索エンジン・AI検索を含むその他のクローラー
User-agent: *
Disallow: /admin/
Allow: /admin/public/
Disallow: /*?sort=
Disallow: /*.pdf$

Sitemap: https://www.example.com/sitemap.xml

どこまでブロックするかの判断表

方針 書くトークン 結果
AI学習には使わせない。AI検索には表示したい GPTBot ClaudeBot Google-Extended CCBot 学習は拒否、ChatGPT検索・Claude検索・Google検索には表示
AI検索にも表示しない 上記+OAI-SearchBot Claude-SearchBot AIの検索機能からの参照が減る
すべて許可(AIからの流入も歓迎) 何も書かない 既定どおり巡回される
Google 検索にも出さない Googlebot を拒否 通常は選ばない(検索流入がなくなる)

AI検索(AI Overviews や ChatGPT 検索など)からの流入を重視するなら、検索用のトークンは拒否しないのがおすすめです。新しいクローラーは今後も増えるので、半年に一度ほど各社の公式ページで名称を確認すると安心です。

Pythonでrobots.txtの許可・拒否を判定する(実行結果つき)

公開前に「どのURLが、どのクローラーに許可されるか」を一覧で確認すると、書き間違いを防げます。 ここでは Python 標準の urllib.robotparser と、Google の仕様(最長一致・ワイルドカード)に沿って実装されたライブラリ Protego(Scrapy が使っているパーサー)を並べて判定しました。

  • 環境:Python 3.11.15、Protego 0.7.0(pip install protego)
  • 判定対象:上の「検索は許可、AI学習は拒否」テンプレートを robots.txt として保存
# check_robots.py
import sys
from urllib.robotparser import RobotFileParser
from protego import Protego

text = open("robots.txt", encoding="utf-8").read()

rp = RobotFileParser()
rp.parse(text.splitlines())
pg = Protego.parse(text)

agents = ["Googlebot", "Bingbot", "GPTBot", "ClaudeBot", "Google-Extended", "CCBot", "OAI-SearchBot"]
urls = [
    "https://www.example.com/",
    "https://www.example.com/admin/login",
    "https://www.example.com/admin/public/help.html",
    "https://www.example.com/items?sort=price",
    "https://www.example.com/docs/guide.pdf",
    "https://www.example.com/docs/guide.pdf?v=2",
]

print(f"Python {sys.version.split()[0]}")
print(f"{'User-agent':<16} {'URL':<34} robotparser  Protego")
for ua in agents:
    for u in urls:
        path = u.replace("https://www.example.com", "")
        a = "許可" if rp.can_fetch(ua, u) else "拒否"
        b = "許可" if pg.can_fetch(u, ua) else "拒否"
        mark = "  <- 差" if a != b else ""
        print(f"{ua:<16} {path:<34} {a:<10}  {b}{mark}")
print("site_maps():", rp.site_maps())

実行結果(抜粋。GPTBot・ClaudeBot・Google-Extended・CCBot は全URLで「拒否」、Bingbot・OAI-SearchBot は Googlebot と同じ結果でした):

Python 3.11.15
User-agent       URL                                robotparser  Protego
Googlebot        /                                  許可          許可
Googlebot        /admin/login                       拒否          拒否
Googlebot        /admin/public/help.html            拒否          許可  <- 差
Googlebot        /items?sort=price                  許可          拒否  <- 差
Googlebot        /docs/guide.pdf                    許可          拒否  <- 差
Googlebot        /docs/guide.pdf?v=2                許可          許可
GPTBot           /                                  拒否          拒否
GPTBot           /admin/public/help.html            拒否          拒否
ClaudeBot        /                                  拒否          拒否
Google-Extended  /                                  拒否          拒否
CCBot            /                                  拒否          拒否
OAI-SearchBot    /                                  許可          許可
OAI-SearchBot    /admin/public/help.html            拒否          許可  <- 差
site_maps(): ['https://www.example.com/sitemap.xml']

標準のrobotparserとGoogleの判定が違う3つのポイント

AIクローラーの拒否はどちらも同じ結果ですが、Allow やワイルドカードを含む行では判定が分かれました。 原因は次の3つです。

違い urllib.robotparser(3.11) Google(RFC 9309) / Protego
Allow と Disallow の優先 上から順に最初に当たったルール 最も長いパスのルール
*(パス中のワイルドカード) 解釈しない(文字としての * 扱い) 0文字以上の任意文字列
$(末尾一致) 解釈しない URLの末尾

順番の違いは、次のテストで確認できます。

# order_test.py
from urllib.robotparser import RobotFileParser
from protego import Protego
a = """User-agent: *
Disallow: /admin/
Allow: /admin/public/
"""
b = """User-agent: *
Allow: /admin/public/
Disallow: /admin/
"""
tie = """User-agent: *
Allow: /page
Disallow: /page
"""
url = "https://www.example.com/admin/public/help.html"
for name, t in [("Disallowが先", a), ("Allowが先", b)]:
    rp = RobotFileParser(); rp.parse(t.splitlines())
    print(f"{name}: robotparser={rp.can_fetch('Googlebot', url)}  Protego={Protego.parse(t).can_fetch(url, 'Googlebot')}")
rp = RobotFileParser(); rp.parse(tie.splitlines())
u="https://www.example.com/page"
print(f"同じ長さで競合: robotparser={rp.can_fetch('Googlebot', u)}  Protego={Protego.parse(tie).can_fetch(u, 'Googlebot')}")
Disallowが先: robotparser=False  Protego=True
Allowが先: robotparser=True  Protego=True
同じ長さで競合: robotparser=True  Protego=True

Google 向けの確認には、最長一致とワイルドカードに対応したパーサー(Protego や Google 公開の robots.txt ライブラリ)を使うと、実際の挙動に近い結果になります。標準の robotparser で確認したい場合は、Allow を Disallow より上に書くと両者の結果がそろいやすくなります(Google は順番を見ないので、この並べ方でも問題ありません)。

sitemap.xmlの書き方

基本形(urlset)

<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  <url>
    <loc>https://www.example.com/</loc>
    <lastmod>2026-10-01</lastmod>
  </url>
  <url>
    <loc>https://www.example.com/articles/robots-guide</loc>
    <lastmod>2026-09-28T10:30:00+09:00</lastmod>
  </url>
</urlset>
タグ 必須 書き方 Google の扱い
urlset 必須 名前空間 http://www.sitemaps.org/schemas/sitemap/0.9 ―
url / loc 必須 絶対URL(https:// から)。& は &amp; 正規URL(canonical)をそろえて書く
lastmod 任意 W3C 日付形式(2026-10-01 または 2026-10-01T10:30:00+09:00) 正確で一貫していれば使われる
changefreq 任意 daily など 無視される
priority 任意 0.0〜1.0 無視される

lastmod は「本文・構造化データ・リンクなど、意味のある更新をした日時」を書きます。 フッターの年表記を変えただけ、のような更新で日付を動かすと、値の信頼性が下がり使われにくくなります。

サイトマップインデックス(sitemapindex)

1ファイルの上限は 50,000 URL または 50MB(非圧縮)です。超える場合は分割し、それらをまとめるインデックスファイルを作ります。

<?xml version="1.0" encoding="UTF-8"?>
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  <sitemap>
    <loc>https://www.example.com/sitemap-1.xml</loc>
    <lastmod>2026-10-01</lastmod>
  </sitemap>
  <sitemap>
    <loc>https://www.example.com/sitemap-2.xml</loc>
    <lastmod>2026-09-28</lastmod>
  </sitemap>
</sitemapindex>
項目 内容
1サイトマップの上限 50,000 URL / 50MB(非圧縮)。gzip 圧縮して配信してもよい
置き場所 ルート直下が基本(Search Console で送信しない場合、置いたディレクトリ配下にしか効かない)
文字コード UTF-8
入れるURL 検索結果に出したい正規URLだけ(noindex、リダイレクト元、404 は入れない)

Pythonでsitemap.xmlを自動生成するスクリプト

DBやCMSの記事一覧からサイトマップを作り、50,000件ごとに自動で分割してインデックスまで出力するスクリプトです。標準ライブラリだけで動きます。

# gen_sitemap.py(Python 3.11 で確認)
"""sitemap.xml を自動生成する(50,000件ごとに分割し、sitemap_index.xml を作る)"""
from datetime import date
from pathlib import Path
from xml.sax.saxutils import escape

BASE = "https://www.example.com"
OUT = Path("public")
MAX_URLS = 50_000             # Google の上限:1ファイル 50,000 URL
MAX_BYTES = 50 * 1024 * 1024  # 同じく 50MB(非圧縮)

def load_pages():
    """本来はDBやCMSから取得する。ここではダミーの記事 120,000 件"""
    yield ("/", date(2026, 10, 1))
    for i in range(1, 120_000):
        yield (f"/articles/{i}?lang=ja&ref=top", date(2026, 9, (i % 28) + 1))

def url_entry(path, lastmod):
    loc = escape(BASE + path)  # & < > をエスケープ(&amp; になる)
    return f"  <url>\n    <loc>{loc}</loc>\n    <lastmod>{lastmod.isoformat()}</lastmod>\n  </url>\n"

HEAD = '<?xml version="1.0" encoding="UTF-8"?>\n<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n'
TAIL = "</urlset>\n"

def write_chunks(pages):
    OUT.mkdir(exist_ok=True)
    files, buf, size, n = [], [], 0, 0
    def flush():
        nonlocal buf, size, n
        if not buf:
            return
        name = f"sitemap-{len(files) + 1}.xml"
        (OUT / name).write_text(HEAD + "".join(buf) + TAIL, encoding="utf-8")
        files.append((name, max_lastmod))
        buf, size, n = [], 0, 0
    max_lastmod = date.min
    for path, lastmod in pages:
        entry = url_entry(path, lastmod)
        b = len(entry.encode("utf-8"))
        if n >= MAX_URLS or size + b + 200 > MAX_BYTES:
            flush(); max_lastmod = date.min
        buf.append(entry); size += b; n += 1
        max_lastmod = max(max_lastmod, lastmod)
    flush()
    return files

def write_index(files):
    lines = ['<?xml version="1.0" encoding="UTF-8"?>',
             '<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">']
    for name, lastmod in files:
        lines += ["  <sitemap>", f"    <loc>{BASE}/{name}</loc>",
                  f"    <lastmod>{lastmod.isoformat()}</lastmod>", "  </sitemap>"]
    lines.append("</sitemapindex>")
    (OUT / "sitemap_index.xml").write_text("\n".join(lines) + "\n", encoding="utf-8")

if __name__ == "__main__":
    files = write_chunks(load_pages())
    write_index(files)
    for name, _ in files:
        p = OUT / name
        print(f"{name}: {p.read_text(encoding='utf-8').count('<url>'):,} URL, {p.stat().st_size/1024/1024:.1f} MB")
    print("sitemap_index.xml:", len(files), "files")

実行結果(python3 gen_sitemap.py):

sitemap-1.xml: 50,000 URL, 5.9 MB
sitemap-2.xml: 50,000 URL, 6.0 MB
sitemap-3.xml: 20,000 URL, 2.4 MB
sitemap_index.xml: 3 files

生成された sitemap-1.xml の先頭です。& が &amp; にエスケープされています。

<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  <url>
    <loc>https://www.example.com/</loc>
    <lastmod>2026-10-01</lastmod>
  </url>
  <url>
    <loc>https://www.example.com/articles/1?lang=ja&amp;ref=top</loc>

インデックス側の lastmod には、そのファイルに含まれるURLの最新の lastmod を入れています。 こうすると、更新があったサイトマップだけを再取得してもらいやすくなります。

xmllintでsitemap.xmlの妥当性をチェックする

サイトマップのエラーで多いのは「& のエスケープ漏れ」と「lastmod の日付形式」です。 どちらも xmllint(libxml2 付属。Ubuntu では apt-get install libxml2-utils)で公開前に見つけられます。

整形式(XMLとして壊れていないか)

xmllint --noout public/sitemap-1.xml public/sitemap_index.xml && echo "OK: well-formed"
OK: well-formed

& をエスケープし忘れたファイルでは、次のエラーになりました(libxml 2.9.14)。

<loc>https://www.example.com/items?color=red&size=m</loc>
bad.xml:4: parser error : EntityRef: expecting ';'
    <loc>https://www.example.com/items?color=red&size=m</loc>
                                                     ^
exit=1

直し方:& を &amp; にする(Python なら xml.sax.saxutils.escape() を通す)。

スキーマ検証(タグと値の形式)

sitemaps.org が配布している公式 XSD を使うと、タグ名や値の形式まで確認できます。ここでは同じ構造の簡易スキーマ(loc 必須、lastmod は日付または日時)を作って試しました。

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
  targetNamespace="http://www.sitemaps.org/schemas/sitemap/0.9"
  xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" elementFormDefault="qualified">
  <xsd:element name="urlset">
    <xsd:complexType><xsd:sequence>
      <xsd:element name="url" maxOccurs="50000"><xsd:complexType><xsd:sequence>
        <xsd:element name="loc" type="xsd:anyURI"/>
        <xsd:element name="lastmod" minOccurs="0">
          <xsd:simpleType><xsd:union memberTypes="xsd:date xsd:dateTime"/></xsd:simpleType>
        </xsd:element>
        <xsd:element name="changefreq" type="xsd:string" minOccurs="0"/>
        <xsd:element name="priority" type="xsd:decimal" minOccurs="0"/>
      </xsd:sequence></xsd:complexType></xsd:element>
    </xsd:sequence></xsd:complexType>
  </xsd:element>
</xsd:schema>
xmllint --noout --schema sitemap-mini.xsd public/sitemap-3.xml
xmllint --noout --schema sitemap-mini.xsd bad2.xml   # lastmod が 2026/10/01
public/sitemap-3.xml validates
bad2.xml:5: element lastmod: Schemas validity error : Element '{http://www.sitemaps.org/schemas/sitemap/0.9}lastmod': '2026/10/01' is not a valid value of the local union type.
bad2.xml fails to validate

lastmod はスラッシュ区切りではなく 2026-10-01 の形で書く、と一目でわかります。CI に xmllint --noout を入れておくと、生成スクリプトを変更したときも安心です。

よくある間違いと直し方

よくある書き方 起きること こうするとよい
robots.txt に Noindex: を書く Google は2019年9月から非対応。効果なし ページに <meta name="robots" content="noindex"> か X-Robots-Tag ヘッダー
noindex したいページを Disallow する 巡回されないので noindex が読まれず、URLだけ検索結果に残ることがある noindex が反映されるまでは Disallow しない
/wp-content/ や CSS・JS を Disallow ページの表示を正しく確認できなくなる 表示に必要なファイルは許可する
Googlebot 用グループに共通ルールを書き忘れ * のグループは読まれず、除外したいページが巡回される 個別グループにも共通ルールをコピー
Disallow: /Admin/ と書いた パスは大文字・小文字を区別するので /admin/ に効かない 実際のURLと同じ表記で書く
サブドメインにも効くと思っていた robots.txt はホストごと blog.example.com/robots.txt を別に置く
Crawl-delay で Google の頻度を下げる Google は非対応 サーバー負荷は Search Console のクロール統計で確認し、必要ならサーバー側で調整
sitemap に相対URLを書く 読み込まれない https:// から始まる絶対URL
sitemap に noindex・リダイレクト・404 のURL 正規URLの判断がぶれる 検索結果に出したい正規URLだけ入れる
priority を細かく調整 Google は無視する 正確な lastmod と内部リンクに時間を使う
秘密のページを Disallow で隠す robots.txt は誰でも読めるので、かえって場所が知られる 認証・アクセス制限で守る

Search Consoleでの送信と確認手順

sitemap.xmlを送信する

  1. Search Console で対象のプロパティを選ぶ
  2. 左メニューの「サイトマップ」を開く
  3. 「新しいサイトマップの追加」に sitemap_index.xml など(ドメイン以降の部分)を入力して「送信」
  4. ステータスが「成功しました」になり、「検出されたページ数」が想定に近いか確認する

インデックスファイルを送信すれば、中の各サイトマップもまとめて読み込まれます。 あわせて robots.txt に Sitemap: 行を書いておくと、Google 以外の検索エンジンにも場所が伝わります。なお、以前あった「ping URL にアクセスして更新を知らせる方法」は Google が2023年に廃止を告知しているため、Search Console への送信と robots.txt への記載を基本にします。

robots.txtを確認する

確認したいこと 方法
Google が取得した robots.txt の内容・取得日時・エラー Search Console の「設定」→「robots.txt」レポート
特定のURLがブロックされているか Search Console の「URL検査」
公開前にローカルで判定 Google 公開の robots.txt パーサー(オープンソース)や Protego で判定(上のスクリプト)
公開されているか シークレットウィンドウで https://ホスト/robots.txt を開く

以前の「robots.txt テスター」は提供が終了しており、現在は上の robots.txt レポートが公式の確認手段です。修正後に早く反映させたいときは、robots.txt レポートから再クロールをリクエストできます。

よくある質問

Q. robots.txt と sitemap.xml は両方必要ですか? A. 小さなサイトなら、どちらもなくても巡回はされます。ただ、robots.txt に Sitemap の場所を書き、sitemap.xml を Search Console に送信しておくと、新しいページが見つかるまでの時間を短くしやすくなります。 除外したいページがなければ robots.txt は「全許可+Sitemap 行」だけで十分です。

Q. GPTBot を拒否すると ChatGPT の検索結果にも出なくなりますか? A. OpenAI の公式説明では、学習用の GPTBot と ChatGPT 検索用の OAI-SearchBot は別のクローラーです。GPTBot だけを拒否すれば、学習には使われず、検索機能には表示される設定になります。Anthropic の ClaudeBot と Claude-SearchBot も同じ考え方です。

Q. Google-Extended を拒否すると Google 検索の順位に影響しますか? A. Google の公式ドキュメントに「Google 検索への掲載に影響せず、ランキングの要素にも使わない」と明記されています。Gemini の学習やグラウンディングへの利用可否だけを伝えるトークンです。

Q. robots.txt を変更したのに反映されません。 A. Google は robots.txt を通常最大24時間キャッシュします。Search Console の robots.txt レポートで取得日時を確認し、必要なら再クロールをリクエストしてください。

まとめ

  • robots.txt は「巡回の範囲」、sitemap.xml は「巡回してほしいURLの一覧」を伝えるファイル
  • Google は RFC 9309 準拠。500KiB 上限、パスは大文字小文字を区別、最長一致で判定
  • AIクローラーは学習用と検索用で名前が別。GPTBot・ClaudeBot・Google-Extended・CCBot を拒否しても検索には表示される
  • Python 標準の robotparser は上から順に判定し、* と $ を解釈しないため、Google 向けの確認は Protego などを使う
  • sitemap.xml は絶対URL・正確な lastmod・50,000 URL / 50MB で分割。priority と changefreq は Google が無視する
  • xmllint で & のエスケープ漏れや日付形式を公開前に検出できる
  • 検索結果から外すのは robots.txt ではなく noindex。送信と確認は Search Console で行う

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「robots.txt・sitemap.xmlの書き方|テンプレートと検証手順」

株式会社RJCでは、クローラーとの付き合い方のようなWebの基礎知識を仲間と学び合っています。こうした知識を共有しながら、日々技術を磨いています。

株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。

WE ARE HIRING

RJCで一緒に開発しながら、
成長を楽しみませんか?

RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!

  • 127日年間休日
  • 12時間平均残業時間
  • 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!

ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。

ABOUT RJC RJCがどんな会社か知る 考え方、研修、働き方、福利厚生、社員の前職まで。RJCのことが丸わかり! RJC丸わかりページへ JOB DESCRIPTION 仕事内容・待遇を見てみる 仕事内容、給与・待遇、選考の流れ。経験者も未経験も!応募前に知りたいこと、まとめました! 募集要項を見る ENTRY エントリーする エントリーは1〜2分・履歴書不要です。まずは話を聞いてみたい、という方でも歓迎です! エントリーフォームへ

RJCで一緒に開発しながら、 成長を楽しみませんか?