Web scraper en NodeJs: x-ray

Necesito obtener en un formato amigable los datos de los 130 congresistas, entiéndase por amigable: json o bueno en el más dramático y horrible de los casos algo tipo csv, txt, XML.
Voy a la web de nuestro eficiente congreso (NOT) y pierdo 19 minutos de mi vida buscando la data que quiero en uno de los formatos ya mencionados anteriormente.

Obviamente ya sabía que no iba a encontrar nada, salvo la gestión de municipal de Susana Villarán, ningún otro se ha preocupado jamás por iniciativas de open data, pero este no es un blog sobre política así que no voy a entrar en detalles... a menos que... NO!

Buscando un scraper en nodejs

¿Qué hago? Obviamente tengo que usar algún web scraper que obtenga los datos y luego los convierto a un formato .json.

Ya he hecho esto anteriormente, pero siempre con tools basados en python o ruby. Ya buen tiempo que uso javascript para todo, entonces busco algún módulo que me ayude con esta tarea.
Obviamente existen muchos en npm, pero luego de jugar con varios encuentro uno que me gusta y me permite hacer en cuestión de minutos lo que quiero.

X-RAY

X-ray me gusta porque solo le indicas el url, un selector css más los tags html que tienen la data deseada y automágicamente ya tienes un resultado que puedes grabar a un archivo.

Instalando x-ray

Creo un package.json usando npm init con valores por default, luego instalo la dependencia que necesito.

npm i x-ray -S  

La letra i es un shortcut para install mientras que -S es la manera abreviada de --save ya que deseo que esta dependencia se muestre en mi package.json

Obteniendo la lista de congresistas

Primero necesito saber la web de dónde sacaré los datos, para este caso la url es esta http://www.congreso.gob.pe/pleno?K=290.
Con esto ya tenemos el primer parámetro que x-ray requiere, pero ahora necesitamos estudiar un poco el html de la web dónde tenemos a los congresistas.

html congresistas

El html no luce complicado, una etiqueta table con la clase congresistas que contiene toda la información que necesitamos y que podemos usar como segundo parámetro con x-ray.
El tercer parámetro que x-ray necesita es un arreglo qué contiene un objeto que representará la data que vamos a obtener.

En este caso vamos a extraer la foto, el nombre y el partido político al que pertenecen (que probablemente no fue con el que entraron, pero ese es otro tema ya que prometí no hablar de política)
Si regresan a la imagen verán que resalté exactamente esa información pero con un énfasis especial en las etiquetas html y sus clases css para que se entienda luego en el código el tema de los selectores.
La imagen está en una etiqueta img (DUH), pero dentro de un span con la clase fotolist por lo cual podemos representarlo con el siguiente selector:

td span.fotolist img@src  

El @src del final le dice a x-ray que lo que queremos es el atributo source, ya que ese nos da acceso a la url que tiene la imagen.

Ahora vamos por el nombre, aunque lo ideal es separar el nombre y apellido en este caso no está representado de esa forma y tampoco es que me importe mucho. Al igual que la imagen, necesitamos ver en qué etiquetas se encuentra este dato y pues es bastante sencillo, en este caso tenemos directamente un link con la clase css conginfo.

td a.confinfo@text  

En este caso indicamos @text ya que queremos el texto que tiene la etiqueta, aunque no es necesario agregarlo ya que por defecto x-ray asume que quieres el texto de una etiqueta si no indicas nada. O sea que también funcionaría de la siguiente manera:

td a.confinfo  

Por último y también menos importante el partido político al que pertenecen los ineptos padres de la patria.
En este caso tenemos el partido político en una etiqueta span con la clase css partidolist

td span.partidolist@text  

Ya tenemos identificados los 3 selectores que nos darán la data que necesitamos, pero ¿Cómo se ve representando esto en código?

'use strict';

// Referenciamos xray y creamos una variable para el url
var xray = require('x-ray')(),  
        url = 'http://www.congreso.gob.pe/pleno?K=290';

function getRepresentatives() {

    var htmlTags = [],
        dataSelectors = {};

    // selector para el nombre
    dataSelectors.fullName = 'td a.conginfo@text';
    // selector para el partido político
    dataSelectors.politicalParty = 'td span.partidolist@text';
    // selector para la photo
    dataSelectors.photo = 'td span.fotolist img@src';

    // agregamos los selectores al arreglo
    htmlTags.push(dataSelectors);
    // pasamos los parámetros a x-ray, url, selector inicial
    // que es la tabla con la lista de congresistas
    // y por último el array con los selectores
    xray(url, 'table.congresistas > tr', htmlTags).write('representatives.json');

}

Vemos que la variable dataSelectors tiene los selectores que identificamos y asignados a propiedades con los nombres fullName, politicalParty y photo. Estos nombres pueden ser lo que a uno se le ocurra, no necesariamente deben o tienen relación al esquema html.
Luego de pasar los parámetros a x-ray llamamos al método write que nos permite grabar los resultados a un archivo, en este caso le pondré como nombre representatives.json.

El código final y las instrucciones para ejecutarlo lo pueden encontrar en mi cuenta de github.

https://github.com/eperedo/congress-peru