Hace unos años se vendía "Infobel", un CD con una base de datos que contenía los nombres, apellidos, dirección postal y teléfono fijo de todos los usuarios de telefonía fija de España y otras ediciones para otros paises de Europa. Esta base de datos se solía utilizar para automatizar contestadores con publicidad y otros fines similares de marketing, además se podían hacer búsquedas inversas. Es decir, dado un número de teléfono fijo, averiguar quién te estaba llamando.
Como Infobel ya no existe por distintos problemas con la ley de protección de datos, a Yago se le ocurrió ver si éramos capaces de hacernos nuestra propia base de datos usando la página web de páginas blancas, ya que había visto que no usaban captchas.
Como Infobel ya no existe por distintos problemas con la ley de protección de datos, a Yago se le ocurrió ver si éramos capaces de hacernos nuestra propia base de datos usando la página web de páginas blancas, ya que había visto que no usaban captchas.
En ese momento me acordé del año pasado cuando Ron de SkullSecurity recorría automáticamente el directorio de Facebook y generaba un curioso diccionario de más de 100 millones de nombres únicos. Más tarde, en mayo de este año, un estudiante repetía la jugada con Google, descargando unos 35 millones de perfiles.
Comentada la idea, me puse a mirar la web, eso sí, sin llegar a guardar los datos en ningún sitio, ya que eso requeriría dar de alta el archivo por contener datos de caracter personal.
Lo primero que observé es que paginas blancas requiere que se introduzca como mínimo un nombre, apellido o razón social y una provincia.

Si no se meten esos dos valores, mostrará un error similar al siguiente:

Así que como un buen chico, metí Alejandro como prueba en "A Coruña", a ver los resultados que ofrecia.

Vaya, ya tenía 589 Alejandros localizados en A Coruña, la lastima es que solo deja mostrar los 50 primeros, tal y como informa la propia web:

Y una vez avanzas 5 páginas y obtienes los 50 registros, la web cambia y elimina el botón "Siguiente", evitando que obtengamos todos:

Seguro que los más vivos ya os habréis imaginado por dónde van los tiros. ¡Estos datos los valida en el lado del cliente!, y tanto la provincia como el número de página son parámetros que se ingresan en la URL, es decir, que yo cambio de la URL el parámetro "nomprov" y elimino "A Coruña", buscará todos los Alejandros de España. Tal y como muestro para mayor claridad en la siguiente imagen con Hackbar:

El número cambia de los tristes 589 a 29.952 ¡wow!
De esta misma forma, modificando el parámetro "pg" de la URL puedo avanzar y obtener todos los resultados, ya que lo único que hace el botón de "Siguiente" es incrementar en uno ese valor.
Bien, con estos dos "pequeños" fallos ya solo queda programar un algo que haga el trabajo sucio. Buscar muchos nombres y recorrer las páginas.Como diccionario de nombres en primera instancia se me ocurrió usar los que ya se habían sacado de Facebook, pero 100 millones de nombres, definitivamente, son DEMASIADOS nombres. Así que me acordé del Instituto Nacional de Estadística, que ofrece datos sobre frecuencia de nombres. Sumando los de hombre y mujer, conseguí 16.101 distintos, parecía mucho más acotado que los 100.000.000 de Ron.
Una vez copiados del INE a un fichero, tocaba hacer el script, que pese a que es horrible, funciona:
#!/bin/bash
# Jun 12 02:41:36 CEST 2011 It's time to scrap!
# $1 = archivo con nombres
BURL="http://blancas.paginasamarillas.es/jsp/resultados.jsp?"
for name in `cat $1`; do
PARAM="no=$name&sec=15&tbus=0&idioma=tml_lang&pg=1&pext=null"
count=`curl -s ${BURL}${PARAM}|grep Encontrados | tail -1 |sed -e 's|.*ng> \(.*\)<.*|\1|'`
if [ -z $count ]; then echo "saltando: $name"; continue; fi
echo "encontrados $count de $name"
get=0
fetch=$(( $count / 10 + 1 ))
while [ "$fetch" -gt "$get" ]; do
get=$(( $get + 1 ))
echo "debug: obteniendo $get de $fetch de $name"
PARAMS="no=$name&sec=15&tbus=0&idioma=tml_lang&pg=$get&pext=null"
curl -s ${BURL}${PARAMS} | grep listatel | tee -a $1.out
done
done
Fueron 10 minutos para hacerlo asi que no quiero oír quejas, el output además es aún peor:
<a href="#" onclick="return imprimeAnuncio('resultados_imp.jsp?LO1=OURENSE&CALL=Galicia&PR=OURENSE&NUME=&TP=IG&NO=LUIS MANUEL GON&APE1=-&
APE2=&CP=32005&tel=988 242 xxx&sec=28&vez=0&listatel=')" >
<a href="#" onclick="return imprimeAnuncio('resultados_imp.jsp?LO1=LLEIDA&CALL=Castelló Aleu&PR=LLEIDA&NUME=&TP=IG&NO=BORRELL SENA SL&AP
E1=-&APE2=&CP=25005&tel=973 830 xxx&sec=28&vez=0&listatel=')" >
<a href="#" onclick="return imprimeAnuncio('resultados_imp.jsp?LO1=LLEIDA&CALL=Germans Recasens&PR=LLEIDA&NUME=&TP=IG&NO=CONSUELO SANCHE&
APE1=-&APE2=&CP=25005&tel=973 248 xxx&sec=28&vez=0&listatel=')" >
Por lo que luego hubo que hacerse otro para convertir la salida HTML en un CSV, esta vez en perl. Como los machos ;-)
#!/usr/bin/perl while() { s/.*jsp?//; s/\&sec.*//; #print $_; ($loc) = $_ =~ m/.*LO1=(.*)\&CALL.*/; ($call)= $_ =~ m/.*CALL=(.*)\&PR.*/; ($pr) = $_ =~ m/.*PR=(.*)\&NUME.*/; ($tp) = $_ =~ m/.*TP=(.*)\&NO.*/; ($no) = $_ =~ m/.*NO=(.*)\&APE1.*/; ($ape1) = $_ =~ m/.*APE1=(.*)\&APE2.*/; ($ape2) = $_ =~ m/.*APE2=(.*)\&CP.*/; ($cp) = $_ =~ m/.*CP=(.*)\&tel.*/; ($tel) = $_ =~ m/.*tel=(.*)/; $tel =~ s/ //g; print "\"$loc\",\"$call\",\"$pr\",\"$tp\",\"$no\",\"$ape1\",\"$ape2\",\"$cp\",\"$tel\"\n" } done
Cuando terminé y me sentía realizado, pensé que lo mismo la lista de nombres no era lo suficiente completa, así que se me ocurrió que cuando terminase (con 8 millones de resultados), podría hacer una lista de Apellidos de todos los datos obtenidos, y consultar nuevamente con ese otro nuevo diccionario.
Sumando los resultados de ambas ejecuciones y eliminado los duplicados, finalmente quedarian (supongo) unos 9.7 millones de registros.
Una vez reportado y arreglado, esta es la historia.























