Geokodowanie adresów do użycia w KML

Mano Marks, zespół Google Geo
Autor: grudzień 2007 r.
Aktualizacja: grudzień 2013 r.

Cel

Ten samouczek jest przeznaczony dla programistów, którzy znają języki skryptowe i chcą się dowiedzieć, jak używać interfejsu Google Geocoding API do geokodowania adresów i włączania ich do pliku KML. Przykłady kodu są podane w języku Python, ale można je dość łatwo dostosować do większości innych języków programowania.

Geokodowanie to proces przekształcania adresu w zestaw współrzędnych geograficznych (szerokości i długości), co umożliwia wskazywanie adresów na mapie. Możesz chcieć geokodować adresy i umieszczać je bezpośrednio w pliku KML. Jest to powszechne na przykład wtedy, gdy dane są wprowadzane do formularza, a w odpowiedzi na żądania generujesz pliki KML. Te pliki KML mogą być przechowywane w bazie danych, systemie plików lub zwracane do elementu NetworkLink, który łączy się z Twoim plikiem. Pamiętaj, że korzystając z tej techniki, musisz przestrzegać Warunków korzystania z usługi Geocoding API, ponieważ istnieją pewne ograniczenia dotyczące czasu, przez jaki można przechowywać wyniki, a także liczby elementów, które można geokodować każdego dnia.

Z tego samouczka dowiesz się, jak za pomocą Pythona przekształcić ciąg znaków „1600 Amphitheatre Pkwy, Mountain View, CA 94043” w ten sposób:

<?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>

Tworzenie dokumentu KML

KML to język znaczników XML, więc do utworzenia dokumentu KML możemy użyć wbudowanych funkcji Pythona xml.dom.minidom. Minidom w Pythonie to implementacja DOM, a DOM jest obsługiwany w większości języków programowania, więc ten proces powinien być łatwy do przeniesienia do innego języka programowania. Aby to zrobić:

  1. Utwórz dokument za pomocą funkcji xml.dom.minidom.Document() w Pythonie.
  2. Utwórz element główny <kml> za pomocą createElementNS.
  3. Dołącz go do dokumentu za pomocą tagu appendChild.
  4. Utwórz element Document za pomocą createElement.
  5. Dodaj go do elementu <kml> za pomocą appendChild.
  6. Dla każdego adresu utwórz element <Placemark> za pomocą elementu createElement i dołącz go do elementu Document. Następnie utwórz element <description> , przypisz mu wartość adresu i dołącz go do elementu <Placemark>.
  7. Utwórz element <Point>, dodaj element podrzędny <coordinates> i dołącz go do elementu <Placemark>.
  8. Wyślij adres do usługi Geocoder interfejsu Maps API, która zwraca odpowiedź w formacie JSON lub XML. Użyj urllib.urlopen(), aby pobrać plik i odczytać go jako ciąg znaków.
  9. Przeanalizuj odpowiedź i wyodrębnij elementy długości i szerokości geograficznej.
  10. Utwórz węzeł tekstowy w elemencie <coordinates> i przypisz mu ciąg znaków z długością i szerokością geograficzną.
  11. Zapisz dokument KML w pliku tekstowym.

Przykładowy kod w Pythonie

Pamiętaj, że w przykładowym kodzie poniżej użyto zmiennej mapsKey, która jest tylko symbolem zastępczym. Musisz ją zastąpić własnym kluczem.

Poniżej znajdziesz przykładowy kod geokodowania w Pythonie 2.7 z danymi wyjściowymi w formacie 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')

Inne kwestie do rozważenia

Określanie czasu żądań geokodowania

Żądania geokodowania będą podlegać dziennym limitom maksymalnej liczby zapytań geokodera. Więcej informacji o tych limitach znajdziesz w dokumentacji interfejsu Google Geocoding API. Aby mieć pewność, że nie wysyłasz zapytań do geokodera zbyt szybko, możesz określić opóźnienie między poszczególnymi żądaniami geokodowania. Możesz zwiększać to opóźnienie za każdym razem, gdy otrzymasz stan OVER_QUERY_LIMIT, i używać pętli while, aby mieć pewność, że adres został prawidłowo geokodowany, zanim przejdziesz do następnego.

Zmiana kraju podstawowego

Geokoder jest zaprogramowany tak, aby faworyzować wyniki w zależności od domeny źródłowej. Na przykład wpisanie „syracuse” w polu wyszukiwania na stronie maps.google.com spowoduje geokodowanie miasta „Syracuse, NY”, a wpisanie tego samego zapytania na stronie maps.google.it (domena włoska) spowoduje znalezienie miasta „Siracusa” na Sycylii. Otrzymasz te same wyniki, wysyłając to zapytanie za pomocą geokodowania HTTP do maps.google.it zamiast do maps.google.com. Możesz to zrobić, modyfikując zmienną mapsUrl w przykładowym kodzie powyżej. Więcej informacji o określaniu regionu znajdziesz w dokumentacji interfejsu Geocoding API.

Uwaga: nie możesz wysłać żądania do nieistniejącego serwera maps.google.*, więc przed przekierowaniem do niego zapytań o geokodowanie upewnij się, że domena kraju istnieje. Informacje o obsłudze geokodowania w poszczególnych krajach znajdziesz w tym poście.

Podsumowanie

Korzystając z powyższego kodu, możesz teraz geokodować adres za pomocą Pythona, tworzyć z niego plik KML<Placemark> i zapisywać go na dysku. Jeśli okaże się, że musisz geokodować więcej adresów dziennie, niż pozwalają na to limity, lub że geokoder Google nie obejmuje interesujących Cię regionów, rozważ użycie dodatkowych internetowych usług geokodowania.

Teraz, gdy wiesz już, jak geokodować adresy, zapoznaj się z artykułami Korzystanie z KML w Edytorze Mashupów GoogleTworzenie KML za pomocą PHP i MySQL. Jeśli masz problemy z tym samouczkiem lub pytania dotyczące niego, opublikuj je na forum Stack Overflow.