Seleccionar página

En posts anteriores hemos contado como hacer scrapping con selenium de datos abiertos del gobierno de aragón.

En este post vamos a ver como hacer un sencillo scrapper con python-mechanize para extraer los mismos datos y guardarlos en una base de datos mongoDB, para terminar, crearemos un grafico de ejemplo con d3.js

Primero comprobamos que la paginación se hace especificando de que articulo a que articulo se va a mostrar (algo que por suerte ya no se suele hacer…)
De este modo, podemos pedirle de golpe todos los articulos de un tipo.
Esto es poco habitual en sitios modernos, pues puede dar problemas de consumo de memoria (no es lo mismo cargar 5000 articulos de golpe que 5 veces 1000 articulos).

Una vez comprobado esto, inicializamos un browser de mechanize, y creamos una clase para esto.
Mechanize actua como un navegador virtual, y beautifulsoup parsea html.
Como todo lo que devuelve la página son parrafos, simplemente podemos parsear los parrafos por bloques, que a su vez se componen de

NOMBRE: VALOR

Vamos a separar estos en una lista de diccionarios.

import mechanize, sys
import json
from BeautifulSoup import BeautifulSoup, SoupStrainer

class DGASubenciones(object):
    def __init__(self, year):
        self.year = year
        self.browser = mechanize.Browser()
        self.browser.set_handle_robots(False)
        self.base_url = "http://mov-brs-01.aragon.es/cgi-bin/CSUB/BRSCGI?CMD=VERLST&BASE=CSUB&DOCS=1-500000&SEC=CSUBPORTAL&SORT=DPTO&OPDEF=%%26&SEPARADOR=&DPTO-C=&BENE-C=&EJER-C=%s&MOCO-C=&NORM-C=&FINA-C="

    def parse_element(self, element):
        result = {}
        for line in str(element).split('\n'):
            children = BeautifulSoup(line).findChildren('span')
            if children != []:
                try:
                    title = children[-1].text
                    result[title] = BeautifulSoup(line).text.replace(title, "")
                except Exception, error:
                    pass
        return result

    def get_raw_by_year(self):
        return BeautifulSoup(self.browser.open(self.base_url %(self.year)).get_data()).findAll('p')

    def get_by_year(self):
        return [ self.parse_element(element) for element in self.get_raw_by_year() ]

if __name__ == "__main__":
    print(json.dumps(DGASubenciones(sys.argv[1]).get_by_year()))

parse_element nos devuelve un diccionario por cada parrafo, y la list comprehension de get_by_year procesa todos los elementos “p” y los agrupa en un diccionario.

Una vez visto esto, pasamos al segundo paso: Mongodb.

Inicializar una base de datos mongodb en python con pymongo es muy sencillo

from pymongo import MongoClient
client = MongoClient()
db = client.dga_db.dga_subvenciones

 

Con esto tenemos una coleccion “dga_subvenciones” en una base de datos “dga_db” disponible en db.
Para insertar elementos sólo tenemos que llamar a

db.insert("foo")

Y ahora, para terminar, vamos a arrancar un servidor Flask que renderice un ejemplo de d3 con estos datos.

Lo único que tenemos que tener en cuenta y es relevante a este articulo es que en el template de flask tenemos que decirle que los datos son seguros para que no los escape pasandole “| safe” y que tendremos que iterar

Esto ultimo lo haremos a la hora de insertar el template, así:

    return render_template('main.html', elements=[a for a in
        client.dga_db[year].find()])

Podeis encontrar el programa completo en github: https://github.com/XayOn/DgaScrapperSubvenciones