Comunicando Node.js y Python (I – la manera sencilla)

Estos últimos días estoy quemando mis horas de vacaciones en un pequeño proyecto que me he planteado que tiene por objetivo, más que nada, aprender. Cuando lo termine seguramente lo publique en GitHub bien documentado, de momento baste saber que me está sirviendo para practicar Node.js, MongoDB y Python.

Captura de pantalla 2014-08-02 13.45.32

El problema es que toda la información que maneja Node.js ha de obtenerse mediante web scraping, y realizar este en el servidor (Node) no me parecía correcto (y ni tan siquiera sé si se podría hacer de manera sencilla), máxime cuando con Python y BeautifulSoup, si el HTML tiene una estructura más o menos coherente, el scrap es fácil.

Así que una vez montado el scraper en Python, la duda quedaba en cuándo dispararlo. Se me planteaban dos opciones: hacer un scrap a lo bestia de manera periódica de toda la información que maneja Node y guardarla en MongoDB, o correr el scraper bajo demanda del usuario, con la BD en el medio, de manera que la primera vez que se pidiese algo que no hubiese sido aún scrapeado tardase más por tener que correr el script Python para obtener la información, pero que en veces sucesivas este contenido ya estuviese cacheado en la base de datos.

Posiblemente el peor diagrama de secuencia de la historia

Posiblemente el peor diagrama de secuencia de la historia

Como os podéis imaginar viendo el diagrama de secuencia, me quedé con la segunda opción, así que ya solo faltaba una forma en la que poder llamar a Python desde Node.js. Lo primero que me planteé es utilizar algún módulo estilo system de manera que se pudiese correr el script haciendo llamadas tipo consola de comandos (python my_script.py > salida.txt). Que Python guardase el resultado en un fichero de texto intermedio y de ahí que lo leyese Node. Un sindiós complicado que, de funcionar, lo haría una vez de cada tres siendo optimistas (no hay que olvidar que Node.js crea los hilos asíncronos que crea necesarios, y a no ser que utilizásemos promesas, es probable que el servidor intentase leer el fichero de texto antes de que Python terminase de crearlo). Por suerte, ya alguien había pensado en eso, y parece ser que Node es capaz de crear procesos hijos que no son Node, por lo que la cosa queda más sencilla gracias a Python-shell.

Con python-shell podremos correr y comunicarnos con scripts Python desde Node.js. La comunicación se realiza en dos tiempos. En el sentido Node -> Python deberemos utilizar los argumentos del script (módulo sys, lista sys.argv a partir de la posición 1, ya que la 0 se reserva para el nombre del programa al estilo *argv de C), y en el sentido Python -> Node deberemos usar la función print, de manera que todo lo que imprima el script por stdout será devuelto a Node.js en un vector de String en el mismo orden en el que Python lo envió.

Este método tiene la desventaja de que si queremos devolver a Node objetos complejos deberemos escoger una representación de datos intermedia. Mi apuesta sería sobreescribir el método __str__ de nuestros objetos Python para que devuelva la representación en formato JSON al ejecutar print str(nuestro_objeto), pero para gustos los colores. Un ejemplo de uso sencillo es el siguiente:

Deja un comentario