Seleccionar página

En los dos posts anteriores de datos del Gobierno de Aragón, vimos cómo procesar los ficheros Excel y la manera de consumir otros documentos en formato JSON / CSV que publica el portal www.aragon.es .

Si bien los casos anteriores son más adecuados para procesamiento de datos, existen casos en los que la información se muestra directamente en páginas web y no es posible a priori explotar estos datos puesto que van mezclados con las etiquetas HTML.

En este post, veremos cómo extraer los contenidos de las páginas web con una pequeña aplicación en Java que realiza scraping utilizando el proyecto Selenium.

Como caso práctico, accederemos al formulario de las subvenciones concedidas entre los años 2007 y 2013 por el Gobierno de Aragón, navegaremos por cada una de las páginas visualizando los resultados de 50 en 50) y extraeremos los datos útiles (id, concedente, beneficiario, …).

 

Nos descargamos el proyecto en Java de Selenium (disponible aquí) y lo descomprimimos en /usr/java :

root@fsolans-ThinkPad-L430:/usr/java# wget http://selenium-release.storage.googleapis.com/2.41/selenium-java-2.41.0.zip

root@fsolans-ThinkPad-L430:/usr/java# unzip selenium-java-2.41.0.zip

Arrancamos el Eclipse IDE, creamos un proyecto nuevo y agregamos las librerías selenium-2.41.0.jar y selenium-java-2.41.0-srcs.jar y las del directorio lib del proyecto Selenium (en nuestro caso está en /usr/java/selenium-2.41.0).

A continuación, creamos la siguiente clase WebScraping.java :

package es.neodoo.opendata.dga.subvencion;

import java.io.FileWriter;
import java.io.IOException;
import java.util.List;

import java.util.Arrays;
import java.util.StringTokenizer;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.Select;
import org.openqa.selenium.firefox.FirefoxDriver;

import org.openqa.selenium.WebDriverException;

public class WebScraping {

	public static void main(String[] args) throws Exception {

		WebDriver driver = new FirefoxDriver();

		List anyos = Arrays.asList("2007", "2008", "2009", "2010",
				"2011", "2012", "2013");
		for (String anyo : anyos) {

			iniciarAnyo(driver, anyo);
			procesarPagina(driver, anyo);

		}

		driver.quit();

	}

	public static void iniciarAnyo(WebDriver driver, String anyo) {

		driver.get("http://www.aragon.es/Temas/Transparencia/Subvenciones/Subtemas/ci.txt_buscador_subvenciones_new.detalleServicios");

		WebElement desplegable = driver.findElement(By.id("ejercicio"));

		Select select = new Select(desplegable);
		select.selectByVisibleText(anyo);

		desplegable.submit();

	}

	public static void procesarPagina(WebDriver driver, String anyo) {

		FileWriter writer = null;

		try {

			writer = new FileWriter(anyo + ".csv");

			writer.append("Id;Concedente;Beneficiario;Finalidad;Importe;Norma;Orden;Ejercicio;Importe de ejercicio;Modo de concesión;Fecha de informe;Descripción línea\n");

			boolean masPaginas = true;

			while (masPaginas) {

				WebElement subvenciones = driver.findElement(By
						.xpath("//div[@class='margen2']"));

				List allOptions = subvenciones.findElements(By
						.tagName("p"));

				for (int i = 0; i < allOptions.size(); i = i + 2) {

					WebElement subvencion = allOptions.get(i);

					String subvencionTextoSinProcesar = subvencion.getText();

					StringTokenizer st = new StringTokenizer(
							subvencionTextoSinProcesar, "\n");

					// Id
					String fila = st.nextToken();
					writer.append(fila.trim());
					writer.append(";");

					// Concedente
					fila = st.nextToken();
					StringTokenizer stAux = new StringTokenizer(fila, ":");
					String nombre = stAux.nextToken();
					String valor = stAux.nextToken();
					writer.append(valor.trim());
					writer.append(";");

					// Beneficiario
					fila = st.nextToken();
					stAux = new StringTokenizer(fila, ":");
					nombre = stAux.nextToken();
					valor = stAux.nextToken();
					if (nombre.equals("Beneficiario")) {
						fila = st.nextToken();
					} else {
						nombre = "Beneficiario";
						valor = "";
					}
					writer.append(valor.trim());
					writer.append(";");

					// Finalidad
					stAux = new StringTokenizer(fila, ":");
					nombre = stAux.nextToken();
					valor = stAux.nextToken();
					writer.append(valor.trim());
					writer.append(";");

					// Importe
					fila = st.nextToken();
					stAux = new StringTokenizer(fila, ":");
					nombre = stAux.nextToken();
					valor = stAux.nextToken();
					writer.append(valor.trim());
					writer.append(";");

					// Norma
					fila = st.nextToken();
					stAux = new StringTokenizer(fila, ":");
					nombre = stAux.nextToken();
					valor = stAux.nextToken();
					writer.append(valor.trim());
					writer.append(";");

					// Orden
					fila = st.nextToken();
					stAux = new StringTokenizer(fila, ":");
					nombre = stAux.nextToken();
					valor = stAux.nextToken();
					if (nombre.equals("Orden")) {
						fila = st.nextToken();
					} else {
						nombre = "Orden";
						valor = "";
					}
					writer.append(valor.trim());
					writer.append(";");

					// Ejercicio
					stAux = new StringTokenizer(fila, ":");
					nombre = stAux.nextToken();
					valor = stAux.nextToken();
					writer.append(valor.trim());
					writer.append(";");

					// Importe de ejercicio
					fila = st.nextToken();
					stAux = new StringTokenizer(fila, ":");
					nombre = stAux.nextToken();
					valor = stAux.nextToken();
					writer.append(valor.trim());
					writer.append(";");

					// Modo de concesión
					fila = st.nextToken();
					stAux = new StringTokenizer(fila, ":");
					nombre = stAux.nextToken();
					valor = stAux.nextToken();
					writer.append(valor.trim());
					writer.append(";");

					// Fecha de informe
					fila = st.nextToken();
					stAux = new StringTokenizer(fila, ":");
					nombre = stAux.nextToken();
					valor = stAux.nextToken();
					writer.append(valor.trim());
					writer.append(";");

					// Descripción línea
					fila = st.nextToken();
					stAux = new StringTokenizer(fila, ":");
					nombre = stAux.nextToken();
					valor = stAux.nextToken();
					writer.append(valor.trim());
					writer.append("\n");

				}

				try {

					WebElement siguiente = driver.findElement(By
							.xpath("//img[@alt='documentos siguientes']"));

					siguiente.click();

				} catch (WebDriverException e) {
					masPaginas = false;
				}

				writer.flush();

			}

			writer.close();

		} catch (IOException e) {
			e.printStackTrace();

		}

	}

}

Podéis ver un vídeo en el que se observa como al arrancar la aplicación desde Eclipse IDE, se abre un navegador web en el que se va recorriendo automáticamente por las páginas a procesar :

 

Tras unas cuantas horas de espera, tendréis en el raíz de vuestro proyecto Java los ficheros 2007.csv, 2008.csv, 2009.csv, 2010.csv, 2011.csv, 2012.csv y 2013.csv.

Nota: Los he creado por separado por pura comodidad y tenerlos separados por años.

Una vez extraídos los datos, podemos explotar directamente los archivos CSV (ver ejemplo aquí) aunque es recomendable meter esta información en una base de datos (ver ejemplo aquí).

Con este post, ya tenemos 3 ejemplos básicos que muestran cómo obtener todos los datos que a fecha de hoy publica el Gobierno de Aragón tanto si aparecen como datos aislados (Excel, JSON, …) o páginas web.

Nota: Quiero recalcar que estos datos son abiertos y están disponibles al ciudadano tal cómo indica la Ley de Transparencia.