【PHP】ユーザーエージェントからクローラー(bot)を判別する
ブログで投稿の閲覧数などを記録する処理を作る場合、純粋なアクセスユーザーだけのデータを計測したいとなると、WEB上にはびこるクローラー(SEO用の自動ページ解析システム)によるアクセスを省いた数値を計測しなければなりません。
結論から言いますが、以下のコードで判別することが可能です。(ほとんど検証してないので、100%完璧な処理ではないと思います。大体これでOK、という感じ。)
$ua = strtolower($_SERVER["HTTP_USER_AGENT"]);
return stripos($ua, "bot") !== false || stripos($ua, "spider") !== false;
以下で、コードの説明をちょっと詳細にしていきます。
【注意点】ユーザーエージェントの利用
この記事を書いていてあれですが、ユーザーエージェントについて、Google Chromeを筆頭に、各ブラウザで廃止の流れが出てきています。
参考:Update on User-Agent String Reduction in Chrome
参考先の記事を要約すると、以下のようなことが書いてあります。
えーと、ユーザーエージェントは現在たくさんの情報を文字列に入れているけど、それを段階的に減らしていくよ。
もっと情報量をすっきりさせるために、User Agent Client Hints APIでスマートにデータを扱えるようにしていくから、今後はそっちを参照していくようにすると、いいかも~
参考:Update on User-Agent String Reduction in Chrome
2025年7月現在では本記事のプログラムが正常にクローラーを弾いてくれているのは確認済みですが、今後どこかのタイミングで要改修案件になるかもしれません。
プログラム説明
冒頭のプログラムについて、以下の順序で説明します。
- ユーザーエージェントの文字列を全て小文字に
- 指定の文字列が含まれているかどうか検索
ユーザーエージェントの文字列を全て小文字に
まず、下記コードの部分では、ユーザーエージェントの文字列を全て小文字にしています。
$ua = strtolower($_SERVER['HTTP_USER_AGENT']);
/** Chromeのユーザーエージェント文字列の変換例 */
Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36
↓↓小文字に変換↓↓
mozilla/5.0 (x11; linux x86_64) applewebkit/537.36 (khtml, like gecko) chrome/51.0.2704.103 safari/537.36
大文字だけ小文字になっているのがわかると思います。
今回のプログラムでは、クローラーかどうかをユーザーエージェントの文字列内に、それらしき文字列が含まれているかどうかで判定するため、小文字大文字ごとに判定処理を書かなくてもいいよう、全て小文字にしてから判定処理を行っています。
指定の文字列がUAに含まれているか検索
次に、下記コードでユーザーエージェントの文字列内に、クローラー特有の文字列かないかを検索しています。
stripos($ua, "bot") !== false || stripos($ua, "spider") !== false;
まず、striposメソッドは、第一引数の文字列のうち、第二引数に指定した文字列が含まれていれば、第二引数が含まれている部分の開始位置(先頭から何文字目に含まれているか)を返し、含まれていない場合はFalseを返します。
つまり、上記のコードは、ユーザーエージェントの文字列に「bot」あるいは「spider」の文字列が含まれいればTrue、どちらも含まれていなければFalseを返す、ということをしています。
まあ、正直これだけでクローラーを弾ききれないのは管理人もわかっていますが、クローラーあってもなくてもそこまで閲覧数に差は出ないので、これぐらい気休め程度のコードにしておいても問題はないでしょう。
spiderとbotって?
「bot」と「spider」としているのは、なんかクローラーにはそれ系の単語が入っている名前のものが多いからです。
ユーザーエージェントにクローラー以外で上記単語が入ることはほぼないというか、入っていたらそれは命名の仕方に問題がある、という話になるので、この2つの単語でクローラーかどうかを判定しています。
詳細にやるなら、クローラーの名前をAPIか何かでまとめておいて、それを受け取る、とかにした方がいいでしょうね。
str_containsは使わない?
PHP8.0から、「文字列が含まれているかどうか」を判定する専用のメソッドとして「str_contains」メソッドが追加されました。
別にどっちで書いてもいいんですけど、基本的にstriposメソッドの方が処理速度が高速らしいので、管理人はそちらを使っています。
まあ、たかがこれだけのコードなら、str_containsでも速度に大した差は出ないと思うので、どっちでもいいです。