背景
robots.txt を、書いた順に上から評価されるものだと思っていました。
なので Disallow: /admin/ のあとに Allow: /admin/help/ を書けば、後勝ちで help だけ通る、と。
逆に書いたら通らない、と。
違いました。順番は関係ありませんでした…。
自分の理解を確かめるために、書いたルールで特定のパスが弾かれるかを判定するツールを作りました。
https://hashitosystem.com/tools/robotstxt/
勝つのは「一致した文字数が長いほう」
robots.txt の仕様は RFC 9309 になっています。
そこで決まっているのは、記述順ではなく 一致した長さ です。
- Disallow と Allow の両方に一致したら、パターンの文字数が長いほうが勝つ
- 同じ長さなら Allow が勝つ
具体例です。下記のルールに対して /admin/help/index.html を判定します。
User-agent: *
Disallow: /admin/
Allow: /admin/help/
/admin/ は 7文字、/admin/help/ は 12文字。
長いのは Allow のほうなので、クロールできます。
順番を入れ替えて Allow を先に書いても、結果は同じです。
ここが「後勝ち」だと思っていた私の勘違いでした。
判定を実装した部分が下記です。
dis と allow はそれぞれ入力欄の各行を配列にしたもの、matches() はパターンに一致したら「* を除いた文字数」を、一致しなければ -1 を返す関数です。
var bestD=-1, bestA=-1;
dis.forEach(function(p){ var n=matches(p,testPath); if(n>bestD) bestD=n; });
allow.forEach(function(p){ var n=matches(p,testPath); if(n>bestA) bestA=n; });
if(bestD<0) verdict='クロールできます'; // Disallow に1つも当たらない
else if(bestA>=bestD) verdict='クロールできます'; // 同数なら Allow が勝つ
else verdict='クロールされません';
bestA >= bestD の等号が「同じ長さなら Allow」の部分です。
ここを > にすると、Disallow: /a と Allow: /a が両方あるときの挙動が実際のクローラと変わります。
* と $ は使える
パスにはワイルドカードが2つ使えます。
-
*… 任意の並びに一致 -
$… URL の末尾に固定
Disallow: /*?sessionid= と書けば、セッションIDがクエリに付いたURLを全部弾けます。
実際に /page?sessionid=1 を入れると「クロールされません」になりました。
Disallow: /*.pdf$ なら、拡張子が .pdf で終わるURLだけです。
$ を付けないと /a.pdf.html にも一致してしまうので、拡張子で弾きたいときは必ず付けます。
そしてこれは検索結果からの削除ではない
いちばん大事なのはここだと思っています。
robots.txt が止めるのは クロール だけです。
インデックスは止まりません。
他のサイトからリンクされていれば、中身を読まれないまま URL だけが検索結果に出ることがあります。
説明文が空欄のまま出るあれです。
検索結果から消したいなら、ページ側に noindex の meta タグを置きます。
そのうえで、そのページを Disallow してはいけません。
Disallow するとクローラがページを取得できず、noindex を読めないからです。
消したくて両方やると、消えないどころか「読めないから判断できない」状態で残ります。
私はこれを逆に覚えていた期間が長くて、robots.txt に書けば消えると思っていました。
消えません。クロールを止めるのと、結果から消すのは、別の操作です。
本記事はAI補助で執筆した、個人開発の紹介記事です。