diff options
Diffstat (limited to 'lib/utils/GeoClient.py')
-rw-r--r-- | lib/utils/GeoClient.py | 292 |
1 files changed, 292 insertions, 0 deletions
diff --git a/lib/utils/GeoClient.py b/lib/utils/GeoClient.py new file mode 100644 index 0000000..d1966ca --- /dev/null +++ b/lib/utils/GeoClient.py @@ -0,0 +1,292 @@ +# -*- coding: utf-8 -*- + +"""Python wrapper for geoname web APIs + +created 20/03/2006 By Nicolas Laurance + +This module allows you to access geoname's web APIs, +and get the results programmatically. +Described here: + http://www.geonames.org/export/ + +def postalCodeSearch(postalcode, placename='', country=COUNTRY, maxRows='10', http_proxy=None): +def postalCodeLookupJSON(postalcode, placename='', country=COUNTRY, maxRows='10',gcallback='', http_proxy=None): +def findNearbyPostalCodes(postalcode, placename='', country=COUNTRY, radius='5', maxRows='10',lat=None,lng=None, http_proxy=None): +def postalCodeCountryInfo(http_proxy=None): +def search(placename='', country=COUNTRY, maxRows='10', style='SHORT',lang=LANG, fclass=None, http_proxy=None): +def findNearbyPlaceName(lat,lng, http_proxy=None): + +Sample usage: +>>> import geoname +>>> result=geoname.postalCodeSearch('35580','guichen','fr','10') +>>> result.totalResultsCount.PCDATA +u'1' +>>> result.code[0].lat.PCDATA +u'47.9666667' +>>> result.code[0].lng.PCDATA +u'-1.8' + + + +""" + +__author__ = "Nicolas Laurance (nlaurance@zindep.com)" +__version__ = "2.0" +__cvsversion__ = "$Revision: 2.0 $"[11:-2] +__date__ = "$Date: 2003/06/20 22:40:53 $"[7:-2] +__copyright__ = "Copyright (c) 2006 Nicolas Laurance" +__license__ = "Python" + +import gnosis.xml.objectify as objectify + +import os, sys, urllib, re +try: + import timeoutsocket # http://www.timo-tasi.org/python/timeoutsocket.py + timeoutsocket.setDefaultSocketTimeout(120) +except ImportError: + pass + +HTTP_PROXY = None +DEBUG = 0 +COUNTRY = 'FR' +LANG ='fr' + + +# don't touch the rest of these constants +class GeonameError(Exception): pass + +## administrative functions +def version(): + print """PyGeoname %(__version__)s +%(__copyright__)s +released %(__date__)s +""" % globals() + +def setProxy(http_proxy): + """set HTTP proxy""" + global HTTP_PROXY + HTTP_PROXY = http_proxy + +def getProxy(http_proxy = None): + """get HTTP proxy""" + return http_proxy or HTTP_PROXY + +def getProxies(http_proxy = None): + http_proxy = getProxy(http_proxy) + if http_proxy: + proxies = {"http": http_proxy} + else: + proxies = None + return proxies + +def _contentsOf(dirname, filename): + filename = os.path.join(dirname, filename) + if not os.path.exists(filename): return None + fsock = open(filename) + contents = fsock.read() + fsock.close() + return contents + +def _getScriptDir(): + if __name__ == '__main__': + return os.path.abspath(os.path.dirname(sys.argv[0])) + else: + return os.path.abspath(os.path.dirname(sys.modules[__name__].__file__)) + +class Bag: pass + +_intFields = ('totalResultsCount') +_dateFields = () +_listFields = ('code','geoname','country',) +_floatFields = ('lat','lng','distance') + +def unmarshal(element): + #import pdb;pdb.set_trace() + xml_obj = objectify.XML_Objectify(element) + rc = xml_obj.make_instance() + return rc + +def _do(url, http_proxy): + proxies = getProxies(http_proxy) + u = urllib.FancyURLopener(proxies) + usock = u.open(url) + rawdata = usock.read() + if DEBUG: print rawdata + usock.close() + data = unmarshal(rawdata) + return data + +## main functions + +def _buildfindNearbyPostalCodes(postalcode, placename, country, radius, maxRows ): + placename=urllib.quote(placename) + searchUrl = "http://ws.geonames.org/findNearbyPostalCodes?postalcode=%(postalcode)s&placename=%(placename)s&country=%(country)s&radius=%(radius)s&maxRows=%(maxRows)s" % vars() + return searchUrl + + +def _buildpostalCodeLookupJSON(postalcode,placename,country,maxRows,gcallback): + placename=urllib.quote(placename) + searchUrl = "http://ws.geonames.org/postalCodeLookupJSON?postalcode=%(postalcode)s&placename=%(placename)s&country=%(country)s&maxRows=%(maxRows)s&callback=%(gcallback)s" % vars() + return searchUrl + +def _buildfindNearbyPostalCodesLL(lat,lng,radius,maxRows): + searchUrl = "http://ws.geonames.org/findNearbyPostalCodes?lat=%(lat)s&lng=%(lng)s&radius=%(radius)s&maxRows=%(maxRows)s" % vars() + return searchUrl + +def _buildfindCountrySubdivision(lat,lng): + searchUrl = "http://ws.geonames.org/countrySubdivision?lat=%(lat)s&lng=%(lng)s" % vars() + return searchUrl + +def _buildfindNearbyPlaceName(lat,lng): + searchUrl = "http://ws.geonames.org/findNearbyPlaceName?lat=%(lat)s&lng=%(lng)s" % vars() + return searchUrl + +def _buildpostalCodeSearch(postalcode, placename, country, maxRows ): + placename=urllib.quote(placename) + searchUrl = "http://ws.geonames.org/postalCodeSearch?postalcode=%(postalcode)s&placename=%(placename)s&country=%(country)s&maxRows=%(maxRows)s" % vars() + return searchUrl + +def _buildsearch(placename, country, maxRows,style,lang, fclass): + placename=urllib.quote(placename) + if fclass: + urlfclass='' + for fc in fclass: + urlfclass+=urllib.quote("&fclass=%s" % fc) + searchUrl = "http://ws.geonames.org/search?q=%(placename)s&country=%(country)s&maxRows=%(maxRows)s&lang=%(lang)s&style=%(style)s&fclass=%(fclass)s" % vars() + return searchUrl + +def postalCodeSearch(postalcode, placename='', country=COUNTRY, maxRows='10', http_proxy=None): + """ + http://ws.geonames.org/postalCodeSearch?postalcode=35580&maxRows=10&country=fr + Url : ws.geonames.org/postalCodeSearch? + Parameters : postalcode ,placename,maxRows,country + <geonames> + <totalResultsCount>7</totalResultsCount> + - + <code> + <postalcode>35580</postalcode> + <name>St Senoux</name> + <countryCode>FR</countryCode> + <lat>47.9</lat> + <lng>-1.7833333</lng> + </code> + """ + url = _buildpostalCodeSearch(postalcode,placename,country,maxRows) + if DEBUG: print url + return _do(url,http_proxy) + +def postalCodeLookupJSON(postalcode, placename='', country=COUNTRY, maxRows='10',gcallback='', http_proxy=None): + """ + Webservice Type : REST /JSON + Url : ws.geonames.org/postalCodeLookupJSON? + Parameters : postalcode,country ,maxRows (default = 20),callback + Result : returns a list of places for the given postalcode in JSON format + """ + url = _buildpostalCodeLookupJSON(postalcode,placename,country,maxRows,gcallback) +# print url + proxies = getProxies(http_proxy) + u = urllib.FancyURLopener(proxies) + usock = u.open(url) + rawdata = usock.read() + if DEBUG: print rawdata + usock.close() + return eval(rawdata[:-3]) + +def findNearbyPostalCodes(postalcode, placename='', country=COUNTRY, radius='5', maxRows='10',lat=None,lng=None, http_proxy=None): + """ + Find nearby postal codes / reverse geocoding + This service comes in two flavors. You can either pass the lat/long or a postalcode/placename. + + Webservice Type : REST + Url : ws.geonames.org/findNearbyPostalCodes? + Parameters : + lat,lng, radius (in km), maxRows (default = 5),country (default = all countries) + or + postalcode,country, radius (in Km), maxRows (default = 5) + Result : returns a list of postalcodes and places for the lat/lng query as xml document + Example: + http://ws.geonames.org/findNearbyPostalCodes?postalcode=35580&placename=guichen&country=FR&radius=5 + <geonames> + - + <code> + <postalcode>35580</postalcode> + <name>Guichen</name> + <countryCode>FR</countryCode> + <lat>47.9666667</lat> + <lng>-1.8</lng> + <distance>0.0</distance> + </code> + """ + if lat and lng : + url = _buildfindNearbyPostalCodesLL(lat,lng,radius,maxRows) + else: + url = _buildfindNearbyPostalCodes(postalcode,placename,country,radius,maxRows) + if DEBUG: print url +# import pdb;pdb.set_trace() + return _do(url,http_proxy).code + + +def postalCodeCountryInfo(http_proxy=None): + """ + http://ws.geonames.org/postalCodeCountryInfo? + <country> + <countryCode>FR</countryCode> + <countryName>France</countryName> + <numPostalCodes>39163</numPostalCodes> + <minPostalCode>01000</minPostalCode> + <maxPostalCode>98000</maxPostalCode> + </country> + + """ + return _do("http://ws.geonames.org/postalCodeCountryInfo?",http_proxy).country + +def search(placename='', country=COUNTRY, maxRows='10', style='SHORT',lang=LANG, fclass=None, http_proxy=None): + """ + Url : ws.geonames.org/search? + Parameters : q : place name (urlencoded utf8) + maxRows : maximal number of rows returned (default = 100) + country : iso country code, two characters (default = all countries) + fclass : featureclass(es) (default= all feature classes); this parameter may occur more then once, example: fclass=P&fclass=A + style : SHORT,MEDIUM,LONG (default = MEDIUM), verbosity of returned xml document + lang : ISO 2-letter language code. (default = en), countryName will be returned in the specified language. + + http://ws.geonames.org/search?q=guichen&maxRows=10&style=SHORT&lang=fr&country=fr + <geonames> + <totalResultsCount>3</totalResultsCount> + - + <geoname> + <name>Laill�</name> + <lat>47.9833333</lat> + <lng>-1.7166667</lng> + </geoname> + """ + url = _buildsearch(placename, country, maxRows,style,lang, fclass) + if DEBUG: print url + return _do(url,http_proxy) + +def findNearbyPlaceName(lat,lng, http_proxy=None): + """ + Webservice Type : REST + Url : ws.geonames.org/findNearbyPlaceName? + Parameters : lat,lng + Result : returns the closest populated place for the lat/lng query as xml document + Example: + http://ws.geonames.org/findNearbyPlaceName?lat=47.3&lng=9 + """ + url = _buildfindNearbyPlaceName(lat,lng) + if DEBUG: print url + return _do(url,http_proxy) + +def findCountrySubdivision(lat,lng, http_proxy=None): + """ + Webservice Type : REST + Url : ws.geonames.org/findNearbyPlaceName? + Parameters : lat,lng + Result : returns the closest populated place for the lat/lng query as xml document + Example: + http://ws.geonames.org/findNearbyPlaceName?lat=47.3&lng=9 + """ + url = _buildfindCountrySubdivision(lat,lng) + if DEBUG: print url + return _do(url,http_proxy) + |