Publicado por & archivado en PHP, Programación.

Me encuentro con un problema en una web de alto tráfico y con muchos PDF de gran tamaño, en la que se está abusando de las descargas. Lo primero que hago es mandar al DROP con iptables todos los rangos de Baidu, que se comporta como un ataque de denegación de servicio, en vez de como un crawler. Luego, limito la cantidad de descargas por IP y tiempo, para evitar el abuso. Hasta aquí todo fácil, pero me doy cuenta al analizar los datos de que estoy bloqueando a los crawlers de Google, Bing y Yahoo (Slurp).

Necesito detectar los bots más populares, para permitirles que abusen un poco más de las peticiones de archivos que un usuario normal, o estaré enviándoles errores 429 constantemente.

 

Cuando busco las soluciones que han usado en otros sitios, veo que lo más usado es detectar el user_agent, muy fácil y rápido, pero tienen un problema, y es que cualquiera puede hacerse pasar por un bot modificando el user_agent.

 

Leyendo en la web de Bing, veo que recomiendan hacer una resolución inversa de la IP y ver si el host es search.msn.com, porque según ellos, usar rangos de IP es poco fiable, así que con un gethostbyaddr, leo las IPs y comparo el nombre con substr:


//Nombre de host
$host = gethostbyaddr($ip);

//Detecta MSN Bot por el nombre de host
$length = strlen($host);
$msn_host = substr($host, $length-15);
if ($msn_host == '.search.msn.com') $msnbot =1;

 

 

El problema de esto, es que es ultralento, resolver los hosts de cada IP cuando hay mucho tráfico, lo hace inutilizable, así que guardo las IPs en tiempo real y luego, obtengo el host al generar el listado, pero resulta que en mostrar un listado paginado de 50 en 50, tarda incluso varios minutos, por lo que finalmente lo descarto, porque es un proceso demasiado lento.

 

Así que a pesar de lo que recomienda Microsoft, decido usar sus rangos de IPs, a sabiendas de que tendré que vigilarlo por si añaden uno nuevo, pero este método es mucho más rápido.

 

Mirando los datos de accesos recopilados, además, he descubierto que a pesar del acuerdo entre Yahoo y Microsoft para usar el Bot de Bing, Yahoo sigue teniendo su propio bot, que identifica como xxx.yse.yahoo.net, averiguo los rangos de estas direcciones y buscando en Internet y analizando los accesos, obtengo el rango de IPs que están usando.

 

Me he escrito este sencilla función, que no puede ser engañada cambiando el user_agent y que es muy rápida, para permitir la detección en tiempo real.

 

He usado el formato numérico de las IPs porque es más rápido que hacer la conversión. Si la lista de rangos fuera muy grande, de miles de IPs, es mejor utilizar MySQL porque es más rápido. Para esta cantidad el medio más rápido es buscar en un array.

 

Se puede ver un ejemplo de búsqueda por rangos en base de datos en el artículo para buscar el país de una IP.


/**
 * @name Función para detectar bots
 * @copyright (c)2015 Intervia IT
 * @link http://intervia.com/doc/detectar-googlebot-bingbot-y-yahoobot/
 * @license MIT http://opensource.org/licenses/MIT
 */

/*
 * 

Rangos Googlebot:
64.233.160.0 - 64.233.191.255
66.102.0.0 - 66.102.15.255
66.249.64.0 - 66.249.95.255
72.14.192.0 - 72.14.255.255 
74.125.0.0 - 74.125.255.255 
209.85.128.0 - 209.85.255.255
216.239.32.0 - 216.239.63.255

Rangos MSN search:
23.96.0.0 - 23.103.255.255
40.77.167.0 - 40.77.167.255
65.52.0.0 - 65.55.255.255
131.253.21.0 - 131.253.47.255
157.54.0.0 - 157.60.255.255
207.46.0.0 - 207.46.255.255
207.68.128.0 - 207.68.207.255
167.220.196.0 - 167.220.199.255

Rangos Yahoo search:
68.180.228.23 - 68.180.228.126
68.180.230.215 - 68.180.230.254

 */

//Detecta las IPs de Google y otros bots
function is_bot($ip){
 
 //Googlebot
 $_bots[] = array("1089052672","1089060863","google"); //64.233.160.0 - 64.233.191.255
 $_bots[] = array("1113980928","1113985023","google"); //66.102.0.0 - 66.102.15.255 
 $_bots[] = array("1123631104","1123639295","google"); //66.249.64.0 - 66.249.95.255
 $_bots[] = array("1208926208","1208942591","google"); //72.14.192.0 - 72.14.255.255
 $_bots[] = array("1249705984","1249771519","google"); //74.125.0.0 - 74.125.255.255
 $_bots[] = array("3512041472","3512074239","google"); //209.85.128.0 - 209.85.255.255
 $_bots[] = array("3639549952","3639558143","google"); //216.239.32.0 - 216.239.63.255

 //MSNbot
 $_bots[] = array("392167424","392691711","msn"); //23.96.0.0 - 23.103.255.255
 $_bots[] = array("676177664","676177919","msn"); //40.77.167.0 - 40.77.167.255
 $_bots[] = array("1093926912","1094189055","msn"); //65.52.0.0 - 65.55.255.255
 $_bots[] = array("2214401280","2214408191","msn"); //131.253.21.0 - 131.253.47.255
 $_bots[] = array("2637561856","2638020607","msn"); //157.54.0.0 - 157.60.255.255
 $_bots[] = array("3475898368","3475963903","msn"); //207.46.0.0 - 207.46.255.255
 $_bots[] = array("3477372928","3477393407","msn"); //207.68.128.0 - 207.68.207.255
 $_bots[] = array("2816263168","2816264191","msn"); //167.220.196.0 - 167.220.199.255

 //Yahoobot
 $_bots[] = array("1152705559","1152705662","yahoo"); //68.180.228.23 - 68.180.228.126
 $_bots[] = array("1152706263","1152706302","yahoo"); //68.180.230.215 - 68.180.230.254
 
 //Busca si la IP coincide con el rango
 $ipl = ip2long($ip);
 foreach ($_bots as $_ipl) {
   if ($ipl >= $_ipl[0] && $ipl <= $_ipl[1]) return $_ipl[2];
 }
 return 0;
}

 

La función se llama con la IP y devuelve el nombre del bot.


$bot = is_bot($_SERVER['REMOTE_ADDR']);
echo $bot;

 

Deja un comentario

Tu dirección de correo electrónico no será publicada.