А кто говорит, что на каждый чих запрос делать. Тем более, делать это на php - нечего тогда говорить о производительности, ибо запрос от плохого бота должен рубиться на подлете, чем раньше, тем лучше.Согласен частично, т.к. необходима некая золотая середина между суперточностью определения и производительностью
Логика достаточно проста и легко вписывается в тот же nginx.
Есть список ASN того же яндекса, он достаточно статичен, чтобы выдергивать все подсети по крону скажем раз в неделю или раз в сутки и сохранять в удобном виде.
Дальше, приходит бот с юзерагентом яндекса, проверяем, входит ли в диапазон этих подсетей, если да - проверяем по блеклисту, если нет - отлуп. Все пишем в лог. Дальше по крону вытягиваем лог, парсим, число совпадений на подсеть /24 (к примеру) - значит подсеть в черный список (допустим ipset), туда же одиночные с пачкой запросов, одиночные и редкие - в серый (путь там limit работает).
Это все пишется на банальном баше. Работает быстро и непринужденно.