[Python] Extrayendo coordenadas de las paradas de FGC

Durante el desarrollo de un proyecto personal que a su vez es una contribución al Open Source - OpenData, me encontré con un pequeño obstáculo con el que algún conocido ya se había encontrado en circunstancias parecidas.

Trasfondo

El proyecto en cuestión consiste en crear una aplicación móvil para Android, de código abierto y siguiendo los estándares de diseño del sistema; la cual permita a los usuarios de los servicios de Ferrocarrils de la Generalitat de Catalunya no tener que utilizar la aplicación oficial, la cual tiene varios elementos que interfieren bastante en la experiencia de usuario.
Por si a alguien le interesa, el proyecto está en desarrollo, y subido a GitHub.

El problema

En esta aplicación me gustaría añadir un mapa en el cuál se pudieran visualizar las paradas de las que FGC dispone en el territorio catalán, y para ello necesitaría una de estas dos cosas:

  • Que alguien hubiera realizado este trabajo antes (como Arasthel)
  • Que FGC tuviera un compromiso con el OpenData y las hubiera liberado en formato KML, CSV... o como fuera

Pero como ninguna de las anteriores se hizo realidad, tuve que pasar al "háztelo tu mismo".

Recopilando datos

Mirando por la web de FGC, intentando encontrar alguna referencia a las coordenadas de las paradas, terminé desistiendo.
En ese momento me planteé incluir en la aplicación un acceso directo a la versión móvil de la web, así que entré para ver qué ofrecía.
Cuál fue mi sorpresa al encontrarme con un regalo tal que así:
Descubrimiento

Un botón con el icono de Google que redirige a la página web de Google Maps y con un atributo... las coordenadas de la parada!

Además, la URL a la página era bastante friendly, de modo que lo único que tenía que hacer era recorrerme todas las líneas y extraer las coordenadas de cada parada asociada.

La solución

Siendo Python mi lenguaje predilecto para hacer scripts rápidos, y existiendo herramientas como Beautiful Soup para hacer scrapping con ese lenguaje, solo tuve que dedicar un ratillo para montar algo que me ayudara en mi propósito.

Aquí os dejo el script, tanto en formato texto como su enlace al gist:

# -*- coding: utf-8 -*-
import urllib2
from bs4 import BeautifulSoup

# Array de todas las lineas de FGC
linies = ['l6', 'l7', 's1', 's2', 's5', 's55', 's8', 's33', 's4', 's8', 'r5', 'r50', 'r6', 'r60']

# Creamos el opener y le añadimos los headers
opener = urllib2.build_opener()
opener.addheaders = [('User-agent', 'Mozilla/5.0')]

# Declaramos los arrays en los que almacenaremos los resultados
arrayNoms = []
arrayX = []
arrayY = []

# Iniciamos el for que se recorrera todas las lineas
numLinia=0
for linia in linies:

	# Cargamos el contenido de la web correspondiente a la linea en la que estamos
	response = opener.open('http://www.fgc.cat/mobil/linia.php?linia='+linies[numLinia])

	# Leemos el contenido y lo cargamos en BeautifulSoup
	data = response.read()
	soup = BeautifulSoup(data)

	# Cogemos los nombres de las paradas, situados en div con la clase .nomEstacio
	for nom in soup.select('.nomEstacio'):

		# Metemos el nombre de la parada en el array correspondiente
		arrayNoms.append(nom.string)

	# Cogemos los elementos situados dentro del div con la clase .iconosEstacio
	for coord in soup.select('.iconosEstacio'):

		# Seleccionamos el elemento a, que es el correspondiente al icono de Google
		google = coord.find('a')

		# Obtenemos el href
		hrefs = google['href']

		# Separamos el href por el simbolo de igual, ya que solo nos interesan las coordenadas
		coords = hrefs.split('=')

		# Separamos las coordenadas por una , para poder tener diferenciadas las latitudes de las longitudes
		coordsSplitted = coords[1].split(',')

		# Metemos cada una en su array correspondiente
		arrayX.append(coordsSplitted[0])
		arrayY.append(coordsSplitted[1])

	#Incrementamos el numero de linea
	numLinia += 1


# Abrimos el fichero en el cual volcaremos los datos en forma de SQL.
# Lo abrimos en modo append
f = open('SQL.txt', 'a')

# Iniciamos el for que recorrera todos los elementos de los arrays
i=0
for nom in arrayNoms:

	# Creamos la secuencia SQL
	# NOTA: Al ser una empresa catalana, algunos de los nombres incluyen caracteres extraños como ç o ' de modo que lo codificamos como utf-8
	# para evitar problemas al añadirlo al archivo
	sequence = u''.join('INSERT INTO coordenadas (PARADA, X, Y) VALUES(\"'+arrayNoms[i]+'\", '+arrayX[i]+', '+arrayY[i]+');\n').encode('utf-8')

	# Añadimos la secuencia SQL al archivo
	f.write(sequence)

	i += 1

# Cerramos el fichero
f.close()

URL AL GIST

El script genera un archivo llamado SQL.txt, el cual contiene la secuencia SQL para añadir todos los datos (nombre de la parada, latitud y longitud) a una base de datos para posteriores consultas desde la propia aplicación.