Geolocalizar un listado de IPs con Perl
El otro día un cliente nos hizo el encargo de obtener los países a los que pertenecían un listado de IPs de un log. Bueno, pues usamos cualquier servicio de geolocalización de IPs y solucionado. El problema vino cuando el archivo tenía miles de IPs, de modo que era inviable hacerlo a mano. Así que para estos casos PERL viene de PERLas.
Bien, lo primero es tener instalado PERL en nuestra distribución de Linux favorita (sí, PERL se programa en Linux ^_^). Y mediante CPAN instalamos el módulo IP-Country, desde una terminal:
loquesea@loquesea:~$ sudo perl -MCPAN -e shell loquesea@loquesea:~$ install IP::Country
El archivo de entrada será un simple txt con una IP por cada línea, por ejemplo:
106.10.85.67 109.166.128.6 109.174.113.164 111.243.39.145 112.134.171.139 ...
Y el código PERL:
#!/usr/bin/perl
use IP::Country::Fast;
my $ips= "ips.txt"; #Archivo de entrada con una IP en cada línea
my $paises="paises.txt"; #Archivo de salida con el número de IPs por país
open (ENTRADA,"<$ips") or (die "ERROR: No puedo abrir el fichero $ips\n");
open (SALIDA,">$paises") or (die "ERROR: No puedo abrir el fichero $paises\n");
my $reg = IP::Country::Fast->new();
my %hashPaises; # Hash contador de veces que aparece cada país
while (){ #Recorremos línea a línea
$ip=$_;
chomp $ip; #Eliminamos el salto de línea
$pais = $reg->inet_atocc($ip); #Obtenemos el país asociado a la IP
$hashPaises{$pais}++; #Sumamos el contador de país
#print SALIDA ($ip."\t".$pais."\n"); #Si quisieramos imprimir cada IP a qué país pertenece, en mi caso eran demasiadas
}
foreach $pais (sort {$hashPaises{$a} <=> $hashPaises{$b} } keys %hashPaises){ #Imprimimos cada país con su cantidad de ocurrencias ordenado de menor a mayor
print SALIDA "$pais $hashPaises{$pais}\n";
}
close ENTRADA;
close SALIDA;
Le damos permisos de ejecución, y lo ejecutamos:
loquesea@loquesea:~$ chmod 777 geolocaliza.pl loquesea@loquesea:~$ ./geolocaliza.pl
Y la salida de nuestro programa se escribirá en paises.txt:
DE 9 VN 11 IN 17 UA 18 ES 21 US 22 BY 23 RU 31 ...