המרת כתובות לקואורדינטות לשימוש ב-KML

מנו מרקס, צוות Google Geo
נכתב: דצמבר 2007
עודכן: דצמבר 2013

מטרה

המדריך הזה מיועד למפתחים שמכירים שפות סקריפטים ורוצים ללמוד איך להשתמש ב-Google Geocoding API כדי לבצע גיאו-קידוד של כתובות ולשלב אותן בקובץ KML. הדוגמאות לקוד מוצגות ב-Python, אבל אפשר להתאים אותן בקלות יחסית לרוב שפות התכנות האחרות.

גיאו-קידוד הוא תהליך של המרת כתובת לקבוצה של קואורדינטות של קווי אורך ורוחב, שמאפשרות לציין כתובות במפה. יכול להיות שתרצו לבצע גיאו-קידוד של כתובות ולהכניס אותן ישירות לקובץ KML. לדוגמה, זה קורה בדרך כלל כשמזינים נתונים לטופס ויוצרים קובצי KML בתגובה לבקשות. קובצי ה-KML האלה יכולים להיות מאוחסנים במסד נתונים, במערכת קבצים או להיות מוחזרים ל-NetworkLink שמתחבר לקובץ. חשוב לזכור: כשמשתמשים בטכניקה הזו, צריך לפעול בהתאם לתנאים ולהגבלות של Geocoding API, כי יש מגבלות על משך הזמן שבו אפשר לאחסן את התוצאות ועל מספר הרכיבים שאפשר לקודד גאוגרפית בכל יום.

במדריך הזה נסביר איך להשתמש ב-Python כדי לקחת את המחרוזת 1600 Amphitheatre Pkwy, Mountain View, CA 94043 ולהפוך אותה למחרוזת הבאה:

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

יצירת מסמך KML

‫KML היא שפת תגי עיצוב של XML, ולכן אנחנו יכולים להשתמש בפונקציות המובנות של xml.dom.minidom ב-Python כדי ליצור מסמך KML. ‫minidom של Python הוא הטמעה של DOM, ו-DOM נתמך ברוב שפות התכנות, כך שהתהליך הזה אמור להיות קל להעברה לשפת תכנות אחרת. אלה השלבים:

  1. יוצרים את המסמך באמצעות xml.dom.minidom.Document() של Python.
  2. יוצרים את רכיב הבסיס <kml> באמצעות createElementNS.
  3. מוסיפים אותו למסמך באמצעות appendChild.
  4. יוצרים רכיב Document באמצעות createElement.
  5. מוסיפים אותו לרכיב <kml> באמצעות appendChild.
  6. לכל כתובת, יוצרים רכיב <Placemark> באמצעות createElement ומוסיפים אותו לרכיב Document. לאחר מכן יוצרים רכיב <description> ומקצים לו את ערך הכתובת, ומוסיפים אותו לרכיב <Placemark>.
  7. יוצרים רכיב <Point> ומצרפים אליו רכיב צאצא <coordinates> ואז מוסיפים אותו לרכיב <Placemark>.
  8. שולחים את הכתובת אל Maps API Geocoder, שמחזיר תגובה בפורמט JSON או XML. משתמשים ב-urllib.urlopen() כדי לאחזר את הקובץ ולקרוא אותו למחרוזת.
  9. מנתחים את התגובה ומחלצים את רכיבי קו האורך וקו הרוחב.
  10. יוצרים צומת טקסט ברכיב <coordinates> ומקצים לו את המחרוזת של קו האורך או קו הרוחב כערך.
  11. כותבים את מסמך ה-KML בקובץ טקסט.

קוד Python לדוגמה

שימו לב שבקוד לדוגמה שבהמשך נעשה שימוש במשתנה mapsKey פיקטיבי – תצטרכו להחליף את המפתח הזה במפתח משלכם.

בהמשך מופיע קוד לדוגמה לגיאו-קידוד עם Python 2.7 ופלט 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')

דברים נוספים שכדאי לקחת בחשבון

תזמון הבקשות להמרת כתובות לקואורדינטות

בקשות לגיאו-קידוד כפופות למגבלות היומיות על קצב השאילתות המקסימלי של הגיאו-קודר. מידע נוסף על המגבלות האלה זמין במאמרי העזרה של Google Geocoding API. כדי לוודא שלא תשלחו שאילתות מהר מדי לגיאו-קודר, תוכלו לציין השהיה בין כל בקשה לגיאו-קוד. אפשר להגדיל את העיכוב הזה בכל פעם שמקבלים סטטוס OVER_QUERY_LIMIT, ולהשתמש בלולאה while כדי לוודא שבוצע גיאו-קידוד של כתובת לפני שממשיכים לכתובת הבאה.

שינוי המדינה הבסיסית

הגיאוקודר מתוכנת להטות את התוצאות שלו בהתאם לדומיין שממנו מגיעה הבקשה. לדוגמה, אם מזינים את השאילתה "syracuse" בתיבת החיפוש באתר maps.google.com, המערכת תבצע קידוד גיאוגרפי של העיר "Syracuse, NY", אבל אם מזינים את אותה שאילתה באתר maps.google.it (הדומיין של איטליה), המערכת תמצא את העיר "Siracusa" בסיציליה. אפשר לקבל את אותן תוצאות אם שולחים את השאילתה באמצעות קידוד גיאוגרפי של HTTP אל maps.google.it במקום אל maps.google.com. כדי לעשות זאת, צריך לשנות את המשתנה mapsUrl בדוגמת הקוד שלמעלה. מידע נוסף על הטיה אזורית זמין במאמרי העזרה של Geocoding API.

הערה: אי אפשר לשלוח בקשה לשרת maps.google.* שלא קיים, לכן חשוב לוודא שקיים דומיין של מדינה לפני שמפנים אליו את השאילתות של הגיאוקודינג. כדי לבדוק אילו מדינות נתמכות בגיאוקוד, אפשר לעיין במאמר הזה.

סיכום

בעזרת הקוד שלמעלה, עכשיו אפשר לבצע גיאו-קידוד של כתובת באמצעות Python, ליצור ממנה קובץ KML<Placemark> ולשמור אותו בדיסק. אם אתם צריכים לבצע גיאו-קידוד של יותר כתובות ביום מהמגבלות שנקבעו, או אם הגיאו-קודר של Google לא מכסה את האזורים שמעניינים אתכם, כדאי לשקול להשתמש בשירותי אינטרנט נוספים לגיאו-קידוד.

אחרי שלמדתם איך לבצע גיאו-קידוד של הכתובות, כדאי לעיין במאמרים בנושא שימוש ב-KML בכלי Google Mashup Editor ושימוש ב-PHP וב-MySQL ליצירת KML. אם נתקלתם בבעיות או שיש לכם שאלות לגבי המדריך הזה, אתם יכולים לפרסם אותן בפורום של Stack Overflow.