# -*- 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 7 - 35580 St Senoux FR 47.9 -1.7833333 """ 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 - 35580 Guichen FR 47.9666667 -1.8 0.0 """ 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? FR France 39163 01000 98000 """ 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 3 - Laill� 47.9833333 -1.7166667 """ 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)