Direcciones de geocodificación para uso en KML

Mano Marks, equipo de Google Geo
Autor: Diciembre de 2007
Actualización: diciembre de 2013

Objetivo

Este instructivo está dirigido a los desarrolladores que están familiarizados con lenguajes de programación y desean aprender a usar la API de Google Geocoding para geocodificar direcciones y, luego, incorporarlas en un archivo KML. Si bien las muestras de código se presentan en Python, se pueden adaptar con bastante facilidad a la mayoría de los demás lenguajes de programación.

La geocodificación es el proceso de conversión de una dirección en un conjunto de coordenadas de latitud y longitud, lo que hace posible indicar direcciones en un mapa. Tal vez quieras geocodificar direcciones y colocarlas directamente en un archivo KML. Esto es común, por ejemplo, cuando se ingresan datos en un formulario y generas archivos KML en respuesta a solicitudes. Estos archivos KML se pueden almacenar en una base de datos, en un sistema de archivos o devolver a una NetworkLink que se conecta a tu archivo. Ten en cuenta que, cuando usas esta técnica, debes respetar las Condiciones del Servicio de la API de Geocoding, ya que existen algunas limitaciones en el momento en que se pueden almacenar los resultados, así como la cantidad de elementos que puedes geocodificar cada día.

En este instructivo, se muestra cómo usar Python para tomar la string “1600 Amphitheatre Pkwy, Mountain View, CA 94043” y convertirla en lo siguiente:

<?xml version='1.0' encoding='UTF-8'?> 
<kml xmlns='http://earth.google.com/kml/2.2'>
<Document>
<Placemark>
<description>1600 Amphitheatre Pkwy, Mountain View, CA 94043, USA</description>
<Point>
<coordinates>-122.081783,37.423111,0</coordinates>
</Point>
</Placemark>
</Document>
</kml>

Crear un documento KML

KML es un lenguaje de marcado XML, por lo que podemos usar las funciones integradas de xml.dom.minidom de Python para crear un documento KML. La libertad de Python es una implementación de DOM, y el DOM es compatible con la mayoría de los lenguajes de programación, por lo que este proceso debería ser fácil de portar a otro lenguaje de programación. A continuación, se indican los pasos que debes seguir:

  1. Crea el documento mediante xml.dom.minidom.Document() de Python.
  2. Crea el elemento raíz <kml> con createElementNS.
  3. Adjuntarlo al documento con appendChild
  4. Crea un elemento de documento con createElement.
  5. Agrégalo al elemento <kml> con appendChild.
  6. Para cada dirección, crea un elemento <Placemark> con createElement y adjúntalo al elemento Document. Luego, crea un elemento <description>, asígnale el valor de la dirección y adjúntalo al elemento <Placemark>.
  7. Crea un elemento <Point>, agrega un elemento secundario <coordinates> y adjúntalo al elemento <Placemark>.
  8. Envía la dirección al geocodificador API de Google Maps, que envía una respuesta en formato JSON o XML. Usa urllib.urlopen() para recuperar el archivo y leerlo en una string.
  9. Analizar la respuesta y extraer los elementos de longitud y latitud
  10. Crea un nodo de texto en el elemento <coordinates> y asigna la string de longitud y latitud como su valor.
  11. Escribe el documento KML en un archivo de texto.

Ejemplo de código de Python

Ten en cuenta que en el siguiente código de ejemplo se usa una variable ficticia mapsKey, deberás reemplazar esta clave con tu propia clave.

A continuación, se ofrece un ejemplo de código para la geocodificación con Python 2.7 y un resultado de JSON:

import urllib
import xml.dom.minidom
import json 

def geocode(address, sensor=False):
 # This function queries the Google Maps API geocoder with an
 # address. It gets back a csv file, which it then parses and
 # returns a string with the longitude and latitude of the address.

 # This isn't an actual maps key, you'll have to get one yourself.
 # Sign up for one here: https://code.google.com/apis/console/
  mapsKey = 'abcdefgh'
  mapsUrl = 'https://maps.googleapis.com/maps/api/geocode/json?address='
     
 # This joins the parts of the URL together into one string.
  url = ''.join([mapsUrl,urllib.quote(address),'&sensor=',str(sensor).lower()])
#'&key=',mapsKey])
  jsonOutput = str(urllib.urlopen(url).read ()) # get the response 
  # fix the output so that the json.loads function will handle it correctly
  jsonOutput=jsonOutput.replace ("\\n", "")
  result = json.loads(jsonOutput) # converts jsonOutput into a dictionary 
  # check status is ok i.e. we have results (don't want to get exceptions)
  if result['status'] != "OK": 
    return ""
  coordinates=result['results'][0]['geometry']['location'] # extract the geometry 
  return str(coordinates['lat'])+','+str(coordinates['lng'])

def createKML(address, fileName):
 # This function creates an XML document and adds the necessary
 # KML elements.

  kmlDoc = xml.dom.minidom.Document()
  
  kmlElement = kmlDoc.createElementNS('http://earth.google.com/kml/2.2','kml')

  kmlElement = kmlDoc.appendChild(kmlElement)

  documentElement = kmlDoc.createElement('Document')
  documentElement = kmlElement.appendChild(documentElement)

  placemarkElement = kmlDoc.createElement('Placemark')
  
  descriptionElement = kmlDoc.createElement('description')
  descriptionText = kmlDoc.createTextNode(address)
  descriptionElement.appendChild(descriptionText)
  placemarkElement.appendChild(descriptionElement)
  pointElement = kmlDoc.createElement('Point')
  placemarkElement.appendChild(pointElement)
  coorElement = kmlDoc.createElement('coordinates')

  # This geocodes the address and adds it to a  element.
  coordinates = geocode(address)
  coorElement.appendChild(kmlDoc.createTextNode(coordinates))
  pointElement.appendChild(coorElement)

  documentElement.appendChild(placemarkElement)

  # This writes the KML Document to a file.
  kmlFile = open(fileName, 'w')
  kmlFile.write(kmlDoc.toprettyxml(' '))  
  kmlFile.close()

if __name__ == '__main__':
  createKML('1600 Amphitheatre Pkwy, Mountain View, CA 94043, USA', 'google.kml')

Otras consideraciones

Tiempo de las solicitudes de codificación geográfica

Las solicitudes de geocodificación estarán sujetas a los límites diarios de la tasa máxima de consultas del geocodificador. Consulta la documentación de la API de Google Geocoding para obtener más información sobre estos límites. Para asegurarte de no enviar consultas demasiado rápido al geocodificador, puedes especificar una demora entre cada solicitud de codificación geográfica. Puedes aumentar esta demora cada vez que recibas un estado OVER_QUERY_LIMIT y usar un bucle while para asegurarte de geocodificar correctamente una dirección antes de iterar en la siguiente.

Cambio del país base

El geocodificador está programado para restringir sus resultados según el dominio de origen. Por ejemplo, si ingresas "syracuse" en el cuadro de búsqueda en maps.google.com, geocodificarás la ciudad de "Syracuse, NY", y, al ingresar la misma consulta en maps.google.it (dominio de Italia), se buscará la ciudad de "Siracusa" en Sicilia. Obtendrás los mismos resultados si envías esa consulta a través de la codificación geográfica HTTP a maps.google.it, en lugar de maps.google.com; para ello, modifica la variable mapsUrl en el código de muestra anterior. Consulta la documentación de la API de Geocoding para obtener más información sobre la restricción de regiones.

Nota: No puedes enviar una solicitud a un servidor de mapas que no exista. Por lo tanto, asegúrate de que exista un dominio de país antes de redireccionar las consultas de geocodificación a él. Si deseas obtener información sobre la compatibilidad geográfica con los países, consulta esta publicación.

Conclusión

Con el código anterior, ahora puedes geocodificar una dirección con Python, crear un <Placemark> KML a partir de él y guardarlo en el disco. Si necesitas geocodificar más direcciones por día de lo que permiten los límites o que el geocodificador de Google no cubre las regiones que te interesan, considera usar servicios web de geocodificación adicionales.

Ahora que sabes cómo geocodificar tus direcciones, consulta los artículos sobre cómo usar KML en Google Mashup Editor y Cómo usar PHP y MySQL para crear archivos KML. Si tienes problemas o preguntas sobre este instructivo, publícalos en el foro de Stack Overflow.