BUSCADOR

Mostrando entradas con la etiqueta informatica. Mostrar todas las entradas
Mostrando entradas con la etiqueta informatica. Mostrar todas las entradas

domingo, 2 de enero de 2011

Analizando las 130 mil obras del Gobierno (Parte IV: Palabras finales)

Una tarea algo tediosa pero que ha rendido sus frutos. Lo raro y quizás sea porque haya cometido algún error es que el archivo obras-todo.txt tenga 126314 registros en cambio el script para MySQL muestre 126629 registros... muy raro en ese caso recomendaría que se trabaje con el archivo para MySQL.

Finalmente tenemos, para repetir:

- Webs descargados hacia mi disco duro usando el script en Perl.
- Información extraida de las páginas web y almacenadas en archivos de texto, organizados por región.
- Información compilada en un sólo archivo, con separaciones de tabulación, para Excel.
- Información compilada en un script para MySQL.

- Archivo de texto con separación de tabulaciones convertido a partir del script SQL.

Ahora la siguiente tarea será procesar la información y publicar los resultados. Si quieren hacer una consulta más potente les sugeriría que ejecuten la instrucción ALTER TABLE sobras ADD FULLTEXT KEY (obra) después de cargar el archivo MySQL en la base de datos.

Analizando las 130 mil obras del Gobierno (Parte III: Pasando de HTML a txt y a sql)

Bien, el drama lo tenía casi resuelta y ya era hora de poner a Perl nuevamente en acción.

procesar_txt_tab.pl
************************************


************************************

Los archivos html los tengo en la misma carpeta que los scripts. Creamos un archivo llamado obras-todo.txt en el cual vamos a almacenar todas las obras extraidas de los 2642 archivos html.
El mecanismo que voy a usar consiste en eliminar los saltos de línea y posteriormente separar las nuevas líneas del documento usando nuevos saltos de línea en las etiquetas TR (fila)
He utilizado la variable hash %zonas para almacenar las regiones y las páginas, con el bucle exterior itero entre esos valores para generar los nombres de los archivos que voy a abrir.
Cada vez que se abre un archivo eliminamos los saltos de línea y retornos de carro con la expresión regular

$contenedor =~ s/(\n|\r)//g;

para luego tener todo el texto en una sóla línea y poder separar las filas de tabla. Primero pongo saltos de línea que rodeen a las etiquetas SCRIPT y HEAD, las que luego voy a eliminar en totalidad. Después acomodo saltos de línea que rodeen a cada fila TR del código HTML.
Una vez hecho esto uso la función split, indicándole que corte el código de la página abierta a partir de los saltos de línea y los almacene en el vector @filas.
Una vez generado mi arreglo @lineas, con un bucle foreach empiezo a extraer cada uno de sus elementos y los almaceno en la variable $fila, la cual va a pasar a ser procesado.

Se deben tener en cuenta unas reglas adicionales para esto. Establecemos una jerarquía de condiciones para almacenar la información de Regiones, Provincias, Sector, etc. Si no se cumple una condición el programa salta a la siguiente y así hasta terminar. Entonces tenemos:

Primero: Verificamos si es una línea que contenga al código de número de página, si es así lo ignoramos con una sentencia next y pasamos a analizar la siguiente fila, mejor dicho, el contenido del siguiente elemento del vector @filas.

# Ignoramos a las conteniendo el numero de pagina
             if ($linea =~ /javascript:/) {    next;    }

Segundo: Verificamos si es una fila que indique si es información de región (en este caso dice DEPARTAMENTO). De ser así tenemos a una variable $region que almacenará el bombre de la región encontrada. después saltamos al siguiente valor de @filas usando la sentencia next.

# Verificamos si hay region
             if ($linea =~ /DEPARTAMENTO: (.+)<\/td>/) {

                $region = $1;
                next;
             }


Tercero: Verificamos si la fila tiene información de una provincia, de ser así almacenamos el nombre de la provincia en la variable $provincia para usarla finalmente en la construcción del texto final.

 # Verificamos si hay provincia
             if ($linea =~ /PROVINCIA: (.+)<\/td>/) {
                 $provincia = $1;
                 next;
             }


Cuarto: Verificamos el sector de inversión. De igual manera usamos una variable $rubro para almacenar dicho valor.

 # Verificamos si hay rubro
             if ($linea =~ /class="textotitFun">(.+)<\/td>/) {
                 $rubro = $1;
                 next;
             }


Quinto: Si encontramos una fila de etiquetas, las ignoramos y pasamos al siguiente elemento de @filas.

# Ignoramos las etiquetas
             if ($linea =~ /align="justify">OBRAS<\/td>/) {
                 next;
             }


Sexto: Si no se han cumplido algunas de las condiciones anteriores es posible que se trate de una fila de datos. Primero reemplazamos los valores enteros por comas por valores enteros sin comas, esto en la columna (TD) de Monto. Luego reemplazamos los códigos de columna TD, y filas TR para ir limpiando la cadena de texto. Luego eliminamos los códigos de etiqueta que quedan al igual que los saltos de línea y quedarán como separadores del texto las cadenas de caracteres   las cuales reemplazaremos al final por tabulaciones o caracteres ',' si se desea hacer los archivos de texto con separación de tabulaciones para MS Excel o si se desea generar un archivo script para MySQL.

#ordenamos los registros de obras
             if ($linea =~ / /) {
                
                # Arreglamos el numero natural (monto en soles)
                $linea =~ /align="right">(.+) /;
                $temporal = $1;
                $temporal =~ s/,//g;
                $linea =~ s/align="right">(.+) /align="right">$temporal /g;
                
                $linea =~ s/(<\/td>||<\/tr>)/\n/g;
                #print "ELIMINAMOS ,,: \n$linea\n";
              
                $linea =~ s/<.+>//g;
                #print "ELIMINAMOS ETIQUETAS: \n$linea\n";
              
                $linea =~ s/(\n|\r|\t)//g;
                #print "ELIMINAMOS SALTOS: \n$linea\n";
              
                $linea =~ s/ /\t/g;
                #print "FINAL DE PROCESADO: \n$linea\n\n\n\n\n";
                $contenedor = "\n".$linea."\t".$rubro."\t".$provincia."\t".$region;
                print RELLENAR $contenedor;


RELLENAR es el manejador del archivo que creamos para guardar la información extraida de los archivos HTML previamente descargados a nuestro disco duro. En cada ciclo interno se abre y cierra cada archivo. Al final se cierra el archivo en el cual hemos escrito nuestros datos.

Si quieren ver el código para generar el archivo MySQL es el siguiente:

procesar_mysql.pl
*********************************





*********************************

Es una tarea agotadora cuando se trata de analizar HTML y tienes muchas alternativas para procesarlo.

Analizando las 130 mil obras del Gobierno (Parte II: Analizando el código html)

Como les mencionaba, mi experiencia con Perl y con objetos es muy baja, sé que a muchos programadores expertos se les ocurrirá usar módulos XML DOMDocument en cualquier lenguaje, Perl, Python, PHP, etc. sin embargo mi meta era hacer todo esto rápidamente y eso dependía del código fuente de estos archivos descargados.

Después de minutos rebanándome los sesos, al fin pude encontrar la respuesta a a todo esto, encontré un camino fácil para procesar rápidamente todo ese código HTML sin necesidad de utilizar librerías adicionales.

Tablas anidadas, títulos en filas, etiquetas y el contenido primordial...

El hecho que sea una página simple ayuda, el asunto era cómo automatizar sin mucho esfuerzo toda esa data sin requerir ayuda divina. Para facilitarme el análisis tomé los archivos obra-99-1.html, obra-99-2.html y obra-99-3.html generados al descargar las 3 páginas de la región 99 (Multidepartamental) si vieron mi post anterior. Resumiré la estructura del código HTML como la siguiente:

******************************



******************************
Como se observará hay dos tablas dentro de una en cada página web, con la pecularidad que la primera no nos sirve, pero la segunda si, a su vez en la segunda tabla, la más importante, hay 4 filas poco frecuentes pero muy importantes para determinar la Región, la Provincia y el Sector en el que se efectúa la obra, las siguientes son filas que especifican cada obra. Una de las cosas que sucede es que a veces la fila Provincia vuelve a aparecer para enumerar las "obras" para otra provincia.

Con esto ya tenía en mente qué reglas utilizar para procesar los 2462 archivos HTML sin perder la información. La clave estaba en las etiquetas de fila.

Pérdida de la información
Cuando se trata de pasar información de un medio a otro muchas veces se deben cambiar las estructuras y la forma de representación real de los datos. Ese problema tenía con las comas utilizadas en los montos en nuevos soles S/. que estaban indicados por obra, pues verán que enteros con comas no los acepta MySQL y en excel hay problemas de acuerdo a la región geográfica en la que uno se encuentra.

En mi siguiente post revelaré el script en perl de procesado de datos para generar un archivo de texto con separación de tabulaciones y uno para generar un script para MySQL.

Analizando las 130 mil obras del Gobierno (Parte II: Descargando la información al disco duro)

Nota: A los impacientes de toda la vida les pongo de una vez a disposición los enlaces para que puedan descargar los archivos a su computadora, revisarlos con Excel o en el mejor de las casos con MySQL:

- Los archivos los pueden descargar desde: http://achahuasoncco.blogspot.com/2011/01/analizando-las-130-mil-obras-del_5784.html


Pronto conocerán que esta web no es lo demasiado compleja como para extraer esa información y hacerla disponible para los diferentes analistas.
******************************

Pagina tediosa, para revisar los archivos de uno en uno. Mi idea era, y desde que apareció el bendito sitio, automatizar la descarga de la misma para que desde mi propia PC y con herramientas más útiles pudiera hacerme una idea acerca de los datos que nos ofrecía el Gobierno.

Analizando la página con Mozilla Firebug: 

Recopilar toda la información de cuántas páginas y cuales eran sus URL exactas para hacer una copia local sería una tarea titánica de no ser por el firebug:


La página usa un iframe en el cual se puede ver la información, la primera impresión es que usaron ajax, pero no es así. Bien, después de analizar el código HTML y el código javascript encuentro que las URL de las páginas tienen la siguiente forma

http://www.130milobras.presidencia.gob.pe/detobras.asp?dep=XX&hidpage=YY

En donde XX indica el código de la Región en donde esta hecha la "obra" y YY indica el número de página. Después de darle otra mirada a cada una de las páginas de la lista tenemos lo siguiente:

La Región 01 es Amazonas: 79 páginas
La Región 02 Ancash: 223 páginas
La Región 03 Apurimac: 88 páginas
La Región 04 Arequipa: 137 páginas
La Región 05 Ayacucho:  142 páginas
La Región 06 Cajamarca: 169 páginas
La Región 07 Callao: 22 páginas
La Región 08 Cusco: 190 páginas
La Región 09 Huancavelica: 125 páginas
La Región 10 Huanuco: 87 páginas
La Región 11 Ica: 64 páginas
La Región 12 Junin: 157 páginas
La Región 13 La Libertad: 120 páginas
La Región 14 Lambayeque: 67 páginas
La Región 15 Lima: 274 páginas
La Región 16 Loreto: 76 páginas
La Región 17 Madre de Dios: 18 páginas
La Región 18 Moquegua: 46 páginas
La Región 19 Pasco: 54 páginas
La Región 20 Piura: 117 páginas
La Región 21 Puno: 158 páginas
La Región 22 San Martín: 87 páginas
La Región 23 Tacna: 60 páginas
La Región 24 Tumbes: 35 páginas
La Región 25 Ucayali: 44 páginas
La Región 99 Multidepartamental: 3 páginas

Teniendo esta información sólo queda usar una herramienta para que descargue hacia mi PC, haga una copia local. Al inicio me vino a la mente PHP y su librería cURL para poder automatizar la tarea, sin embargo antes tuve problemas porque PHP por defecto no puede ejecutar un script que supere los 300 segundos, o 5 minutos, así que descarté esa alternativa. En mi corta experiencia con Perl pude recordar que una vez comparé dos archivos de texto, uno con 12 mil registros y otro con 2 mil y el tiempo de procesamiento fue bastante muy rápido pese a que lo hice en una computadora con un procesador Pentium D...

En Perl tenemos:

descargar.pl
******************************************
#! /bin/usr/perl

%zonas = ("01" => "79",
"02" => "223",
"03" => "88",
"04" => "137",
"05" => "142",
"06" => "169",
"07" => "22",
"08" => "190",
"09" => "125",
"10" => "87",
"11" => "64",
"12" => "157",
"13" => "120",
"14" => "67",
"15" => "274",
"16" => "76",
"17" => "18",
"18" => "46",
"19" => "54",
"20" => "117",
"21" => "158",
"22" => "87",
"23" => "60",
"24" => "35",
"25" => "44",
"99" => "3");

use LWP::UserAgent;
use HTTP::Request;

my $ua = LWP::UserAgent->new;
$ua->agent("AgenteSmith 1.0 (http://achahuasoncco.blogspot.com/)");
while (($zona,$paginas) = each %zonas) {
    for ($i = 1; $i <= $paginas; $i++) {
        $nombre = "obra-".$zona."-".$i.".html";
        open(PRUEBA,">>$nombre") || die "No se pudo crear archivo";
        $url = "http://www.130milobras.presidencia.gob.pe/detobras.asp?dep=$zona&hidpage=$i";
        $req = HTTP::Request->new(GET => $url);
        $response = $ua->request($req);
        $cadena = $response->content();
        print PRUEBA $cadena;
        close(PRUEBA);
    }
}

******************************************
Archivo en el cual he almacenado en la variable %zonas los códigos de región (clave) y las páginas a descargar (valor), teniendo la estructura de la forma: $zonas{"region"} = "paginas";
El bucle while externo lo uso para iterar entre regiones y valores por dos razones: La primera es acceder a la URL exacta para descargar la web respectiva y, segundo, para escribir en el disco duro un archivo de la forma obra-XX-YY.html, en donde XX indica la región y YY indica la página respectiva desde donde se está descargando. Para poder hacer la descarga uso los módulos LWP::UserAgent y HTTP::Request.

Después de esperar unos 30 minutos en el segundo intento obtengo las 2642 páginas descargadas a mi disco duro. Durante la primera prueba la conexión con el servidor se cortó después de 458 páginas.

Para poder extraer la información se necesita analizar el código fuente de la página web, ese es el siguiente post.

Analizando las 130 mil obras del Gobierno (Parte I)

Como todos ya saben, la tan promocionada página de las 130 mil obras que tanto ha promocionado últimamente el Gobierno peruano recopila lo invertido por el Estado entre los periodos comprendidos entre el 2006 y el 2009. sin embargo, analizar todos estos datos desde la misma página web se convierte en una tarea tediosa y casi de hacer.

Y digo casi porque en tres días, trabajando en mis ratos libres, he podido descargar todo el contenido y pasarlo a un archivo para mysql y otro archivo de texto con separación de tabulaciones, para que los no programadores lo puedan analizar en Excel. Se van a llevar sorpresas y van a darse cuenta de las mentiras de los encargados de dicho sistema, es más, llamarle obras a cosas que no deberían llamárseles obras es el colmo de los casos.

El único inconveniente es que mis scripts me arrojan resultados diferentes. El archivo de texto con separación de tabulaciones tiene 126 315 registros, pero el archivo mysql contienen 126 629 registros, una diferencia de 314... para mis análisis voy a utilizar el archivo mysql... convertir el archivo mysql texto separado con tabulaciones va a ser una tarea adicional, pero estoy algo frustrado por lo de mis scripts.


Herramientas utilizadas

Para comenzar, no soy muy metido en la programación. Trabajo principalmente en plataformas Windows y el Visual Studio apenas lo conozco. Más he estado inmerso en la programación web trabajando con editores simples en Html, Javascript, Php, Mysql. No trabajo con Objetos (gran debilidad mía) pero varios de mis trabajos los he realizado de forma artesanal...

Para hacer esta tareita he utilizado:

Active Perl. El interprete/compilador gratuito que se puede utilizar en Windows, tanto en línea de comandos y como si se tratase de algún Visual Basic Script.


Scintillia: Algunos preferirán Notepad++ pero el Scite no me ha arrojado errores cuando se trata de abrir archivos inmensos.


Mozilla Firefox 3.6.13: El navegador de toda mi vida y en el que tengo instalado mis extensiones favoritas como el Web Developer y Firebug.

En mis siguientes posts voy a liberar la información para que otras personas puedan hacer lo que quieran...