├── tests ├── __init__.py ├── results │ ├── google_timezone.json │ ├── bing_batch.csv │ ├── uscensus_batch.csv │ ├── google_elevation.json │ ├── canadapost_find_1.json │ ├── geonames.json │ ├── osm.json │ ├── geonames_proximity.json │ ├── geonames_extra.json │ ├── canadapost_find_2.json │ ├── geonames_children.json │ ├── locationiq_reverse.json │ ├── bing_batch_submission.json │ ├── uscensus.json │ ├── bing_batch_confirmation.json │ ├── mapquest_batch.json │ ├── geonames.geo.json │ ├── google.json │ ├── geonames_hierarchy.json │ └── geocodefarm.json ├── test_unicode.py ├── test_maxmind.py ├── test_ipinfo.py ├── test_freegeoip.py ├── test_geolytica.py ├── test_cli.py ├── test_ottawa.py ├── test_tomtom.py ├── test_tamu.py ├── test_w3w.py ├── test_yandex.py ├── test_mapzen.py ├── test_komoot.py ├── test_session.py ├── test_gisgraphy.py ├── test_arcgis.py ├── test_osm.py ├── test_gaode.py ├── test_here.py ├── test_baidu.py ├── test_geocodefarm.py ├── test_geocoder.py ├── test_mapbox.py ├── test_canadapost.py ├── test_mapquest.py ├── test_uscensus.py ├── test_locations.py ├── test_locationiq.py ├── test_google.py └── test_opencage.py ├── docs ├── authors.rst ├── _themes │ ├── .gitignore │ ├── kr │ │ ├── theme.conf │ │ ├── relations.html │ │ ├── layout.html │ │ └── static │ │ │ └── small_flask.css │ ├── kr_small │ │ ├── theme.conf │ │ └── layout.html │ └── LICENSE ├── _static │ └── geocoder.png ├── examples │ ├── using proxies.md │ ├── QGISFieldCalculator.rst │ ├── write to csv.md │ └── using iPython.md ├── features │ ├── Well-Known Text.md │ ├── Command Line Interface.md │ ├── Confidence Score.md │ ├── GeoJSON.md │ ├── Caching.md │ └── Distance.md ├── providers │ ├── TGOS.rst │ ├── Yahoo.rst │ ├── Geocoder-ca.rst │ ├── FreeGeoIP.rst │ ├── Gaode.rst │ ├── GeoOttawa.rst │ ├── ArcGIS.rst │ ├── IPInfo.rst │ ├── MaxMind.rst │ ├── What3Words.rst │ ├── Baidu.rst │ ├── CanadaPost.rst │ ├── LocationIQ.rst │ ├── OpenCage.rst │ ├── Yandex.rst │ ├── TomTom.rst │ ├── GeocodeFarm.rst │ ├── Tamu.rst │ ├── OpenStreetMap.rst │ ├── HERE.rst │ ├── MapQuest.rst │ └── Mapbox.rst ├── _templates │ ├── side-secondary.html │ └── side-primary.html └── index.rst ├── pytest.ini ├── setup.cfg ├── requirements.txt ├── MANIFEST.in ├── .coveragerc ├── geocoder ├── locationiq_reverse.py ├── geonames_hierarchy.py ├── geonames_children.py ├── komoot_reverse.py ├── osm_reverse.py ├── locationiq.py ├── google_reverse.py ├── gisgraphy_reverse.py ├── mapquest_reverse.py ├── mapzen_reverse.py ├── bing_reverse.py ├── w3w_reverse.py ├── here_reverse.py ├── __init__.py ├── opencage_reverse.py ├── mapbox_reverse.py ├── mapquest_batch.py ├── google_timezone.py ├── w3w.py ├── google_elevation.py ├── yandex_reverse.py ├── gisgraphy.py ├── geocodefarm_reverse.py ├── ipinfo.py ├── cli.py ├── bing_batch_forward.py ├── keys.py ├── baidu_reverse.py ├── gaode.py ├── geolytica.py ├── arcgis_reverse.py ├── distance.py ├── mapzen.py ├── gaode_reverse.py ├── yahoo.py ├── ottawa.py ├── arcgis.py ├── bing_batch_reverse.py └── geonames_details.py ├── requirements-dev.txt ├── .gitignore ├── .travis.yml ├── Makefile ├── snap └── snapcraft.yaml ├── LICENSE ├── setup.py └── AUTHORS.rst /tests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/authors.rst: -------------------------------------------------------------------------------- 1 | ../AUTHORS.rst -------------------------------------------------------------------------------- /pytest.ini: -------------------------------------------------------------------------------- 1 | [pytest] 2 | pep8ignore = E501 3 | -------------------------------------------------------------------------------- /docs/_themes/.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | *.pyo 3 | .DS_Store 4 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [metadata] 2 | description-file = README.md 3 | [bdist_wheel] 4 | universal = 1 -------------------------------------------------------------------------------- /docs/_static/geocoder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DenisCarriere/geocoder/HEAD/docs/_static/geocoder.png -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | click==6.7 2 | ratelim==0.1.6 3 | requests==2.18.1 4 | six==1.10.0 5 | future==0.16.0 6 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include README.md 2 | include AUTHORS.rst 3 | include LICENSE 4 | recursive-include tests *.py 5 | include requirements.txt 6 | include requirements-dev.txt -------------------------------------------------------------------------------- /docs/_themes/kr/theme.conf: -------------------------------------------------------------------------------- 1 | [theme] 2 | inherit = basic 3 | stylesheet = flasky.css 4 | pygments_style = flask_theme_support.FlaskyStyle 5 | 6 | [options] 7 | touch_icon = 8 | -------------------------------------------------------------------------------- /tests/results/google_timezone.json: -------------------------------------------------------------------------------- 1 | { 2 | "dstOffset": 3600, 3 | "rawOffset": -18000, 4 | "status": "OK", 5 | "timeZoneId": "America/Toronto", 6 | "timeZoneName": "Eastern Daylight Time" 7 | } -------------------------------------------------------------------------------- /.coveragerc: -------------------------------------------------------------------------------- 1 | [run] 2 | omit = 3 | */tests* 4 | 5 | [report] 6 | exclude_lines = 7 | pragma: no cover 8 | def __repr__ 9 | raise NotImplementedError 10 | if __name__ == .__main__.: 11 | def parse_args -------------------------------------------------------------------------------- /tests/results/bing_batch.csv: -------------------------------------------------------------------------------- 1 | Bing Spatial Data Services, 2.0 2 | Id,GeocodeRequest/Query,GeocodeResponse/Point/Latitude,GeocodeResponse/Point/Longitude 3 | 0,"Denver,CO",39.7400093078613,-104.99201965332 4 | 1,"Boulder,CO",40.015739440918,-105.279243469238 -------------------------------------------------------------------------------- /docs/_themes/kr_small/theme.conf: -------------------------------------------------------------------------------- 1 | [theme] 2 | inherit = basic 3 | stylesheet = flasky.css 4 | nosidebar = true 5 | pygments_style = flask_theme_support.FlaskyStyle 6 | 7 | [options] 8 | index_logo = '' 9 | index_logo_height = 120px 10 | github_fork = '' 11 | -------------------------------------------------------------------------------- /tests/test_unicode.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # coding: utf8 3 | 4 | import geocoder 5 | 6 | 7 | def test_unicode(): 8 | g = geocoder.google('東京', key='') 9 | assert g 10 | 11 | 12 | def test_repr_unicode(): 13 | g = geocoder.osm('Tokyo, Japan') 14 | assert g 15 | -------------------------------------------------------------------------------- /tests/results/uscensus_batch.csv: -------------------------------------------------------------------------------- 1 | "1","42 Chapel Street, New Haven, , , ","Match","Exact","42 Chapel St, NEW HAVEN, CT, 06513","-72.89422,41.30435","3703918","L" 2 | "0","4650 Silver Hill Road, Suitland, MD 20746, , , ","Match","Exact","4650 Silver Hill Rd, SUITLAND, MD, 20746","-76.92681,38.846638","613199520","L" 3 | -------------------------------------------------------------------------------- /tests/test_maxmind.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # coding: utf8 3 | import geocoder 4 | 5 | location = '8.8.8.8' 6 | 7 | 8 | def test_maxmind(): 9 | g = geocoder.maxmind(location) 10 | assert g.ok 11 | osm_count, fields_count = g.debug()[0] 12 | assert osm_count >= 1 13 | assert fields_count >= 13 14 | -------------------------------------------------------------------------------- /tests/test_ipinfo.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # coding: utf8 3 | 4 | import geocoder 5 | 6 | location = '99.240.181.199' 7 | 8 | 9 | def test_ipinfo(): 10 | g = geocoder.ipinfo(location) 11 | assert g.ok 12 | osm_count, fields_count = g.debug()[0] 13 | assert osm_count >= 4 14 | assert fields_count >= 12 15 | -------------------------------------------------------------------------------- /tests/test_freegeoip.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # coding: utf8 3 | 4 | import geocoder 5 | 6 | location = '99.240.181.199' 7 | 8 | 9 | def test_freegeoip(): 10 | g = geocoder.freegeoip(location) 11 | assert g.ok 12 | osm_count, fields_count = g.debug()[0] 13 | assert osm_count >= 3 14 | assert fields_count >= 12 15 | -------------------------------------------------------------------------------- /tests/results/google_elevation.json: -------------------------------------------------------------------------------- 1 | { 2 | "results": [ 3 | { 4 | "elevation": 71.80732727050781, 5 | "location": { 6 | "lat": 45.4215296, 7 | "lng": -75.697193 8 | }, 9 | "resolution": 1.192993998527527 10 | } 11 | ], 12 | "status": "OK" 13 | } -------------------------------------------------------------------------------- /tests/test_geolytica.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # coding: utf8 3 | 4 | import geocoder 5 | 6 | location = '1552 Payette dr., Ottawa' 7 | 8 | 9 | def test_geolytica(): 10 | g = geocoder.geolytica(location) 11 | assert g.ok 12 | osm_count, fields_count = g.debug()[0] 13 | assert osm_count >= 5 14 | assert fields_count >= 11 15 | -------------------------------------------------------------------------------- /docs/examples/using proxies.md: -------------------------------------------------------------------------------- 1 | # Using Proxies 2 | 3 | Using proxies will hide the IP address of the client computer when calling a request using the Python Geocoder. 4 | 5 | ```python 6 | >>> import geocoder 7 | >>> proxies = {'http':'http://108.165.33.12:3128'} 8 | >>> g = geocoder.google('New York City', proxies=proxies) 9 | >>> g.json 10 | ... 11 | ``` -------------------------------------------------------------------------------- /tests/results/canadapost_find_1.json: -------------------------------------------------------------------------------- 1 | { 2 | "Items": [ 3 | { 4 | "Id": "CA|CP|ENG|ON-OTTAWA-BOOTH_ST-453", 5 | "Text": "453 Booth St", 6 | "Highlight": "0-3,4-12", 7 | "Cursor": 0, 8 | "Description": "Ottawa, ON, K1R 7K9 - 3 Addresses", 9 | "Next": "Find" 10 | } 11 | ] 12 | } -------------------------------------------------------------------------------- /tests/test_cli.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding: utf8 3 | 4 | import subprocess 5 | 6 | 7 | location = 'Ottawa, Ontario' 8 | 9 | 10 | def test_cli_google(): 11 | assert not subprocess.call(['geocode', location, '--provider', 'google']) 12 | 13 | 14 | def test_cli_osm(): 15 | assert not subprocess.call(['geocode', location, '--provider', 'osm']) 16 | -------------------------------------------------------------------------------- /geocoder/locationiq_reverse.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # coding: utf8 3 | 4 | from __future__ import absolute_import 5 | from geocoder.locationiq import LocationIQQuery 6 | 7 | 8 | class LocationIQReverse(LocationIQQuery): 9 | provider = 'locationiq' 10 | method = 'reverse' 11 | 12 | if __name__ == '__main__': 13 | g = LocationIQReverse("45.3, -75.4") 14 | g.debug() 15 | -------------------------------------------------------------------------------- /requirements-dev.txt: -------------------------------------------------------------------------------- 1 | certifi==2017.4.17 2 | chardet==3.0.4 3 | click==6.7 4 | decorator==4.1.2 5 | idna==2.5 6 | py==1.4.34 7 | flake8==3.3.0 8 | pytest==3.1.3 9 | codecov==2.0.9 10 | coveralls >= 0.4 11 | pytest-cov==2.5.1 12 | ratelim==0.1.6 13 | requests==2.18.1 14 | six==1.10.0 15 | urllib3==1.21.1 16 | requests-mock==1.3.0 17 | sphinx==1.6.3 18 | mock==2.0.0 19 | future==0.16.0 20 | -------------------------------------------------------------------------------- /tests/test_ottawa.py: -------------------------------------------------------------------------------- 1 | # coding: utf8 2 | 3 | import geocoder 4 | 5 | location = 'Ottawa' 6 | 7 | 8 | def test_ottawa(): 9 | g = geocoder.ottawa(location) 10 | assert g.ok 11 | osm_count, fields_count = g.debug()[0] 12 | assert osm_count >= 3 13 | assert fields_count >= 10 14 | 15 | 16 | def test_multi_results(): 17 | g = geocoder.ottawa(location, maxRows=3) 18 | assert len(g) == 3 19 | -------------------------------------------------------------------------------- /tests/test_tomtom.py: -------------------------------------------------------------------------------- 1 | # coding: utf8 2 | 3 | import geocoder 4 | 5 | location = 'Ottawa' 6 | 7 | 8 | def test_tomtom(): 9 | g = geocoder.tomtom(location) 10 | assert g.ok 11 | osm_count, fields_count = g.debug()[0] 12 | assert osm_count >= 2 13 | assert fields_count >= 12 14 | 15 | 16 | def test_multi_results(): 17 | g = geocoder.tomtom(location, maxRows=3) 18 | assert len(g) == 3 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .cache 2 | geocoder/__pycache__/ 3 | .coverage 4 | htmlcov 5 | MANIFEST 6 | coverage.xml 7 | nosetests.xml 8 | junit-report.xml 9 | pylint.txt 10 | toy.py 11 | tox.ini 12 | violations.pyflakes.txt 13 | cover/ 14 | build/ 15 | docs/_build 16 | geocoder.egg-info/ 17 | *.pyc 18 | *.swp 19 | *.egg 20 | *.pyo 21 | env/ 22 | .env 23 | .idea 24 | .vscode 25 | .workon 26 | 27 | t.py 28 | 29 | t2.py 30 | dist 31 | .pypirc 32 | -------------------------------------------------------------------------------- /tests/test_tamu.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # coding: utf8 3 | 4 | import geocoder 5 | 6 | location = '595 Market Street' 7 | 8 | 9 | def test_tamu(): 10 | g = geocoder.tamu( 11 | location, 12 | city='San Francisco', 13 | state='CA', 14 | zipcode='94105') 15 | assert g.ok 16 | osm_count, fields_count = g.debug()[0] 17 | assert osm_count >= 5 18 | assert fields_count >= 28 19 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | sudo: false 3 | python: 4 | - "2.7" 5 | - "3.5" 6 | - "3.6" 7 | 8 | before_install: 9 | - pip install -r requirements-dev.txt 10 | - pip install -r requirements.txt 11 | 12 | install: 13 | - python setup.py develop 14 | 15 | script: 16 | - pytest --cov=geocoder tests 17 | 18 | after_success: 19 | - codecov 20 | 21 | notifications: 22 | email: 23 | - carriere.denis@gmail.com 24 | -------------------------------------------------------------------------------- /tests/test_w3w.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # coding: utf8 3 | import geocoder 4 | 5 | location = 'index.home.raft' 6 | ottawa = (45.4215296, -75.6971930) 7 | 8 | 9 | def test_w3w(): 10 | g = geocoder.w3w(location) 11 | assert g.ok 12 | osm_count, fields_count = g.debug()[0] 13 | assert osm_count == 0 14 | assert fields_count >= 7 15 | 16 | 17 | def test_w3w_reverse(): 18 | g = geocoder.w3w(ottawa, method='reverse') 19 | assert g.ok 20 | -------------------------------------------------------------------------------- /tests/test_yandex.py: -------------------------------------------------------------------------------- 1 | # coding: utf8 2 | 3 | import geocoder 4 | 5 | location = 'Ottawa' 6 | coordinates = {'lat': 41.005407, 'lng': 28.978349} 7 | 8 | 9 | def test_yandex(): 10 | g = geocoder.yandex(location) 11 | assert g.ok 12 | 13 | 14 | def test_yandex_reverse(): 15 | g = geocoder.yandex(coordinates, method='reverse') 16 | assert g.ok 17 | 18 | 19 | def test_multi_results(): 20 | g = geocoder.yandex(location, maxRows=3) 21 | assert len(g) == 3 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: docs 2 | 3 | setup: 4 | python setup.py install 5 | 6 | init: 7 | pip install -r requirements.txt 8 | 9 | test: 10 | flake8 --ignore=E305,E501 geocoder 11 | py.test --cov=./ tests 12 | coverage html 13 | 14 | clean: 15 | python setup.py clean --all 16 | rm -rf build-* 17 | rm -rf *egg* 18 | rm -rf dist 19 | 20 | tox: 21 | tox 22 | 23 | publish: 24 | python setup.py sdist upload -r pypi 25 | python setup.py bdist_wheel upload -r pypi 26 | 27 | docs: 28 | make -C docs html 29 | xdg-open docs/_build/html/index.html 30 | -------------------------------------------------------------------------------- /tests/test_mapzen.py: -------------------------------------------------------------------------------- 1 | # coding: utf8 2 | import pytest 3 | 4 | import geocoder 5 | 6 | location = 'Ottawa' 7 | 8 | 9 | def test_mapzen(): 10 | with pytest.raises(DeprecationWarning) as e: 11 | g = geocoder.mapzen(location) 12 | 13 | 14 | def test_mapzen_reverse(): 15 | with pytest.raises(DeprecationWarning) as e: 16 | g = geocoder.mapzen("45.4049053 -75.7077965", method='reverse') 17 | 18 | 19 | def test_multi_results(): 20 | with pytest.raises(DeprecationWarning) as e: 21 | g = geocoder.mapzen(location, maxRows=3) 22 | -------------------------------------------------------------------------------- /tests/results/geonames.json: -------------------------------------------------------------------------------- 1 | { 2 | "totalResultsCount": 142, 3 | "geonames": [{ 4 | "adminCode1": "08", 5 | "lng": "-75.69812", 6 | "geonameId": 6094817, 7 | "toponymName": "Ottawa", 8 | "countryId": "6251999", 9 | "fcl": "P", 10 | "population": 812129, 11 | "countryCode": "CA", 12 | "name": "Ottawa", 13 | "fclName": "city, village,...", 14 | "countryName": "Canada", 15 | "fcodeName": "capital of a political entity", 16 | "adminName1": "Ontario", 17 | "lat": "45.41117", 18 | "fcode": "PPLC" 19 | }] 20 | } -------------------------------------------------------------------------------- /tests/results/osm.json: -------------------------------------------------------------------------------- 1 | [{"place_id":"173725143","licence":"Data © OpenStreetMap contributors, ODbL 1.0. http:\/\/www.openstreetmap.org\/copyright","osm_type":"relation","osm_id":"4136816","boundingbox":["44.9617738","45.5376502","-76.3555857","-75.2465783"],"lat":"45.421106","lon":"-75.690308","display_name":"Ottawa, Ontario, Canada","place_rank":16,"category":"place","type":"city","importance":0.89749985126194,"icon":"https:\/\/nominatim.openstreetmap.org\/images\/mapicons\/poi_place_city.p.20.png","address":{"city":"Ottawa","state":"Ontario","country":"Canada","country_code":"ca"}}] -------------------------------------------------------------------------------- /geocoder/geonames_hierarchy.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | 3 | from geocoder.geonames_children import GeonamesChildren 4 | 5 | 6 | class GeonamesHierarchy(GeonamesChildren): 7 | """ Hierarchy: 8 | http://api.geonames.org/hierarchyJSON?formatted=true&geonameId=6094817 9 | """ 10 | 11 | provider = 'geonames' 12 | method = 'hierarchy' 13 | 14 | _URL = 'http://api.geonames.org/hierarchyJSON' 15 | 16 | 17 | if __name__ == '__main__': 18 | print("Searching Ottawa's hierarchy...") 19 | c = GeonamesHierarchy(6094817) 20 | c.debug() 21 | -------------------------------------------------------------------------------- /tests/test_komoot.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # coding: utf8 3 | 4 | import geocoder 5 | 6 | location = 'Ottawa, Ontario' 7 | ottawa = (45.4215296, -75.6971930) 8 | 9 | 10 | def test_komoot(): 11 | g = geocoder.komoot(location, timeout=10) 12 | assert g.ok 13 | assert len(g) == 1 14 | osm_count, fields_count = g.debug()[0] 15 | assert osm_count >= 3 16 | assert fields_count >= 15 17 | 18 | 19 | def test_komoot_multi_result(): 20 | g = geocoder.komoot(location, maxRows=3, timeout=10) 21 | assert g.ok 22 | assert len(g) == 3 23 | 24 | 25 | def test_komoot_reverse(): 26 | g = geocoder.komoot(ottawa, method='reverse', timeout=10) 27 | assert g.ok 28 | -------------------------------------------------------------------------------- /docs/_themes/kr/relations.html: -------------------------------------------------------------------------------- 1 |

Related Topics

2 | 20 | -------------------------------------------------------------------------------- /tests/results/geonames_proximity.json: -------------------------------------------------------------------------------- 1 | { 2 | "totalResultsCount": 134, 3 | "geonames": [ 4 | { 5 | "adminCode1": "08", 6 | "lng": "-75.69812", 7 | "geonameId": 6094817, 8 | "toponymName": "Ottawa", 9 | "countryId": "6251999", 10 | "fcl": "P", 11 | "population": 812129, 12 | "countryCode": "CA", 13 | "name": "Ottawa", 14 | "fclName": "city, village,...", 15 | "countryName": "Canada", 16 | "fcodeName": "capital of a political entity", 17 | "adminName1": "Ontario", 18 | "lat": "45.41117", 19 | "fcode": "PPLC" 20 | } 21 | ] 22 | } -------------------------------------------------------------------------------- /tests/results/geonames_extra.json: -------------------------------------------------------------------------------- 1 | { 2 | "totalResultsCount": 2, 3 | "geonames": [ 4 | { 5 | "adminCode1": "08", 6 | "lng": "-75.69717", 7 | "geonameId": 8581623, 8 | "toponymName": "Ottawa", 9 | "countryId": "6251999", 10 | "fcl": "A", 11 | "population": 0, 12 | "countryCode": "CA", 13 | "name": "Ottawa", 14 | "fclName": "country, state, region,...", 15 | "countryName": "Canada", 16 | "fcodeName": "second-order administrative division", 17 | "adminName1": "Ontario", 18 | "lat": "45.41858", 19 | "fcode": "ADM2" 20 | } 21 | ] 22 | } -------------------------------------------------------------------------------- /tests/test_session.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # coding: utf8 3 | 4 | import geocoder 5 | import requests 6 | 7 | try: 8 | import mock 9 | except ImportError: 10 | from unittest import mock 11 | 12 | address = 'Booth Street, Ottawa' 13 | 14 | 15 | def test_session(): 16 | with requests.Session() as session: 17 | g = geocoder.google(address, session=session) 18 | assert g.ok 19 | osm_count, fields_count = g.debug()[0] 20 | assert osm_count >= 4 21 | assert fields_count >= 16 22 | 23 | 24 | def test_session_called(): 25 | with mock.patch('requests.Session.get'): 26 | with requests.Session() as session: 27 | geocoder.google(address, session=session) 28 | session.get.assert_called_once() 29 | -------------------------------------------------------------------------------- /tests/test_gisgraphy.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # coding: utf-8 3 | 4 | import geocoder 5 | 6 | location = 'Ottawa, Ontario' 7 | ottawa = (45.4215296, -75.6971930) 8 | 9 | 10 | def test_gisgraphy(): 11 | g = geocoder.gisgraphy(location, timeout=10) 12 | assert g.ok 13 | assert len(g) == 1 14 | osm_count, fields_count = g.debug()[0] 15 | assert osm_count >= 3 16 | assert fields_count >= 9 17 | 18 | 19 | def test_gisgraphy_multi_result(): 20 | print(geocoder.komoot) 21 | print(geocoder.gisgraphy) 22 | 23 | g = geocoder.gisgraphy(location, maxRows=3, timeout=10) 24 | assert g.ok 25 | assert len(g) == 3 26 | 27 | 28 | def test_gisgraphy_reverse(): 29 | g = geocoder.gisgraphy(ottawa, method='reverse', timeout=10) 30 | assert g.ok 31 | -------------------------------------------------------------------------------- /docs/_themes/kr_small/layout.html: -------------------------------------------------------------------------------- 1 | {% extends "basic/layout.html" %} 2 | {% block header %} 3 | {{ super() }} 4 | {% if pagename == 'index' %} 5 |
6 | {% endif %} 7 | {% endblock %} 8 | {% block footer %} 9 | {% if pagename == 'index' %} 10 |
11 | {% endif %} 12 | {% endblock %} 13 | {# do not display relbars #} 14 | {% block relbar1 %}{% endblock %} 15 | {% block relbar2 %} 16 | {% if theme_github_fork %} 17 | Fork me on GitHub 19 | {% endif %} 20 | {% endblock %} 21 | {% block sidebar1 %}{% endblock %} 22 | {% block sidebar2 %}{% endblock %} 23 | -------------------------------------------------------------------------------- /tests/test_arcgis.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # coding: utf8 3 | import geocoder 4 | 5 | location = 'Ottawa, Ontario' 6 | ottawa = (45.4215296, -75.6971930) 7 | 8 | 9 | def test_arcgis(): 10 | g = geocoder.arcgis(location) 11 | assert g.ok 12 | osm_count, fields_count = g.debug()[0] 13 | assert osm_count == 0 14 | assert fields_count > 1 15 | 16 | 17 | def test_arcgis_reverse(): 18 | g = geocoder.arcgis(ottawa, method='reverse') 19 | assert g.ok 20 | 21 | 22 | def test_multi_results(): 23 | g = geocoder.arcgis(location, maxRows='5') 24 | assert len(g) == 5 25 | 26 | expected_results = [ 27 | 'Ottawa, Ontario', 28 | 'Ottawa, Ontario', 29 | 'Ontario, Oklahoma' 30 | ] 31 | assert [result.address for result in g][:3] == expected_results 32 | -------------------------------------------------------------------------------- /docs/features/Well-Known Text.md: -------------------------------------------------------------------------------- 1 | # Well Known Text 2 | 3 | Well-known text (WKT) is a text markup language for representing vector geometry objects on a map, spatial reference systems of spatial objects and transformations between spatial reference systems. A binary equivalent, known as well-known binary (WKB), is used to transfer and store the same information on databases, such as PostGIS, Microsoft SQL Server and DB2. The formats were originally defined by the Open Geospatial Consortium (OGC) and described in their Simple Feature Access and Coordinate Transformation Service specifications. 4 | 5 | [Wikipedia WKT](http://en.wikipedia.org/wiki/Well-known_text) 6 | 7 | # Python Example 8 | 9 | ```python 10 | >>> import geocoder 11 | >>> g = geocoder.google('New York City') 12 | >>> g.wkt 13 | 'POINT(-74.0111421 40.7069226)' 14 | ``` -------------------------------------------------------------------------------- /tests/test_osm.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # coding: utf8 3 | import geocoder 4 | 5 | location = 'Ottawa, Ontario' 6 | city = 'Ottawa' 7 | ottawa = (45.4215296, -75.6971930) 8 | 9 | 10 | def test_osm(): 11 | g = geocoder.osm(location) 12 | assert g.ok 13 | osm_count, fields_count = g.debug()[0] 14 | assert osm_count >= 3 15 | assert fields_count >= 21 16 | 17 | 18 | def test_osm_reverse(): 19 | g = geocoder.osm(ottawa, method='reverse') 20 | assert g.ok 21 | 22 | 23 | def test_multi_results(): 24 | g = geocoder.osm(location, maxRows='5') 25 | assert len(g) == 5 26 | 27 | def test_detailed_query(): 28 | g = geocoder.osm("",postalcode="45326", street="Ellernstraße", method="details") 29 | assert g.postal == "45326" 30 | assert "ellern" in g.street.lower() 31 | assert g.ok 32 | 33 | -------------------------------------------------------------------------------- /snap/snapcraft.yaml: -------------------------------------------------------------------------------- 1 | name: geocoder # you probably want to 'snapcraft register ' 2 | version: '1.23.2' # just for humans, typically '1.2+git' or '1.3.2' 3 | summary: Geocoder is a simple and consistent geocoding library. 4 | description: | 5 | Simple and consistent geocoding library written in Python. 6 | Many online providers such as Google & Bing have geocoding services, these providers do not include Python libraries and have different JSON responses between each other. 7 | 8 | grade: stable # must be 'stable' to release into candidate/stable channels 9 | confinement: strict # use 'strict' once you have the right plugs and slots 10 | 11 | apps: 12 | geocoder: 13 | command: bin/geocode 14 | plugs: [network] 15 | 16 | parts: 17 | geocoder: 18 | # See 'snapcraft plugins' 19 | plugin: python 20 | python-version: python2 21 | -------------------------------------------------------------------------------- /tests/results/canadapost_find_2.json: -------------------------------------------------------------------------------- 1 | { 2 | "Items": [ 3 | { 4 | "Id": "CA|CP|B|80225509", 5 | "Text": "A-453 Booth St", 6 | "Highlight": "", 7 | "Cursor": 0, 8 | "Description": "Ottawa, ON, K1R 7K9", 9 | "Next": "Retrieve" 10 | }, 11 | { 12 | "Id": "CA|CP|B|20202526", 13 | "Text": "B-453 Booth St", 14 | "Highlight": "", 15 | "Cursor": 0, 16 | "Description": "Ottawa, ON, K1R 7K9", 17 | "Next": "Retrieve" 18 | }, 19 | { 20 | "Id": "CA|CP|B|20202527", 21 | "Text": "C-453 Booth St", 22 | "Highlight": "", 23 | "Cursor": 0, 24 | "Description": "Ottawa, ON, K1R 7K9", 25 | "Next": "Retrieve" 26 | } 27 | ] 28 | } -------------------------------------------------------------------------------- /tests/test_gaode.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | import geocoder 3 | 4 | location = '兆维华灯大厦,北京' 5 | city = '北京' 6 | place = (39.9789660352, 116.497157786) 7 | 8 | 9 | def test_gaode(): 10 | """ Expected result : 11 | http://restapi.amap.com/v3/geocode/geo?address=兆维华灯大厦,北京&output=XML&key=<用户的key> 12 | """ 13 | g = geocoder.gaode(location, key='0716e5809437f14e3dd0793a5c6d2b13') 14 | assert g.ok 15 | 16 | 17 | def test_gaode_reverse(): 18 | """ Expected result : 19 | http://restapi.amap.com/v3/geocode/regeo?output=xml&location=116.310003,39.991957&key=<用户的key>&radius=1000&extensions=all 20 | """ 21 | g = geocoder.gaode(place, method='reverse', key='0716e5809437f14e3dd0793a5c6d2b13') 22 | assert g.ok 23 | assert g.country == u'中国' 24 | assert g.state == u'北京市' 25 | assert g.city == u'北京市' 26 | assert g.street == u'UBP东街' 27 | -------------------------------------------------------------------------------- /docs/examples/QGISFieldCalculator.rst: -------------------------------------------------------------------------------- 1 | QGIS Field Calculator 2 | ===================== 3 | 4 | Using the QGIS Field Calculator this will output WKT format. 5 | 6 | Output Field 7 | ------------ 8 | 9 | - **Name:** wkt 10 | 11 | - **Type:** Text, unlimited length (text) 12 | 13 | Function Editor 14 | --------------- 15 | 16 | .. code-block:: python 17 | 18 | import geocoder 19 | 20 | @qgsfunction(group='Geocoder') 21 | def geocode(location, feature, parent): 22 | g = geocoder.google(location) 23 | return g.wkt 24 | 25 | Expression 26 | ---------- 27 | 28 | Find the **geocode** expression in the **Geocoder** function list, the final result will look something like this: 29 | 30 | .. code-block:: bash 31 | 32 | geocode("address") 33 | 34 | Once the wkt field is added, you can then save your document as a CSV format and in the **Layer Options** define the **GEOMETRY** = **AS_WKT**. -------------------------------------------------------------------------------- /docs/providers/TGOS.rst: -------------------------------------------------------------------------------- 1 | TGOS 2 | ==== 3 | 4 | TGOS Map is official map service of Taiwan. 5 | 6 | Geocoding 7 | ~~~~~~~~~ 8 | 9 | .. code-block:: python 10 | 11 | >>> import geocoder # pip install geocoder 12 | >>> g = geocoder.tgos('台北市內湖區內湖路一段735號', key='') 13 | >>> g.json 14 | ... 15 | 16 | Command Line Interface 17 | ---------------------- 18 | 19 | .. code-block:: bash 20 | 21 | $ geocode '台北市內湖區內湖路一段735號' --provider tgos 22 | 23 | Parameters 24 | ---------- 25 | 26 | - `location`: Your search location you want geocoded. 27 | - `key`: Use your own API Key from TGOS. 28 | - `method`: (default=geocode) Use the following: 29 | 30 | - geocode 31 | 32 | - `language`: (default=taiwan) Use the following: 33 | 34 | - taiwan 35 | - english 36 | - chinese 37 | 38 | References 39 | ---------- 40 | 41 | - `TGOS Maps API `_ 42 | -------------------------------------------------------------------------------- /geocoder/geonames_children.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | 3 | from geocoder.geonames import GeonamesQuery 4 | 5 | 6 | class GeonamesChildren(GeonamesQuery): 7 | """ Children: 8 | http://api.geonames.org/childrenJSON?formatted=true&geonameId=6094817 9 | """ 10 | 11 | provider = 'geonames' 12 | method = 'children' 13 | 14 | _URL = 'http://api.geonames.org/childrenJSON' 15 | 16 | def _build_params(self, location, provider_key, **kwargs): 17 | """Will be overridden according to the targetted web service""" 18 | return { 19 | 'geonameId': location, 20 | 'username': provider_key, 21 | } 22 | 23 | 24 | if __name__ == '__main__': 25 | print("Searching Ottawa...") 26 | g = GeonamesQuery('Ottawa, Ontario') 27 | g.debug() 28 | print("Searching its children...") 29 | c = GeonamesChildren(g.pop().geonames_id) 30 | c.debug() 31 | -------------------------------------------------------------------------------- /docs/_templates/side-secondary.html: -------------------------------------------------------------------------------- 1 | 6 |

7 | 9 |

10 | 11 |

12 | Geocoder is a simple and consistent geocoding library written in Python. 13 | Dealing with multiple different geocoding provider such as Google, Bing, OSM & many more has never been easier. 14 |

15 | 16 |

Support

17 |

18 | If you are having issues we would love to hear from you. Just 19 | hit me up. You can alternatively raise an issue here on Github. 21 |

-------------------------------------------------------------------------------- /docs/providers/Yahoo.rst: -------------------------------------------------------------------------------- 1 | Yahoo 2 | ===== 3 | 4 | Yahoo PlaceFinder is a geocoding Web service that helps developers make 5 | their applications location-aware by converting street addresses or 6 | place names into geographic coordinates (and vice versa). 7 | Using Geocoder you can retrieve Yahoo's geocoded data from Yahoo BOSS Geo Services. 8 | 9 | Geocoding 10 | ~~~~~~~~~ 11 | 12 | .. code-block:: python 13 | 14 | >>> import geocoder 15 | >>> g = geocoder.yahoo('San Francisco, CA') 16 | >>> g.json 17 | ... 18 | 19 | Command Line Interface 20 | ---------------------- 21 | 22 | .. code-block:: bash 23 | 24 | $ geocode 'San Francisco, CA' --provider yahoo --out geojson 25 | 26 | Parameters 27 | ---------- 28 | 29 | - `location`: Your search location you want geocoded. 30 | - `method`: (default=geocode) Use the following: 31 | 32 | - geocode 33 | 34 | References 35 | ---------- 36 | 37 | - `Yahoo BOSS Geo Services `_ 38 | -------------------------------------------------------------------------------- /tests/test_here.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # coding: utf8 3 | 4 | import geocoder 5 | 6 | location = 'Ottawa, Ontario' 7 | ottawa = (45.4215296, -75.6971930) 8 | 9 | winnetka = 'Winnetka' 10 | winnetka_bbox = [-118.604794,34.172684,-118.500938,34.236144] 11 | 12 | 13 | def test_here(): 14 | g = geocoder.here(location) 15 | assert g.ok 16 | osm_count, fields_count = g.debug()[0] 17 | assert osm_count >= 4 18 | assert fields_count >= 13 19 | 20 | 21 | def test_here_with_bbox(): 22 | g = geocoder.here(winnetka, bbox=winnetka_bbox) 23 | assert g.ok 24 | osm_count, fields_count = g.debug()[0] 25 | assert osm_count >= 2 26 | assert fields_count >= 11 27 | 28 | for result in g: 29 | assert (result.lng >= winnetka_bbox[0]) and (result.lng <= winnetka_bbox[2]) 30 | assert (result.lat >= winnetka_bbox[1]) and (result.lat <= winnetka_bbox[3]) 31 | 32 | 33 | def test_here_reverse(): 34 | g = geocoder.here(ottawa, method='reverse') 35 | assert g.ok 36 | -------------------------------------------------------------------------------- /tests/test_baidu.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | import geocoder 3 | 4 | location = '兆维华灯大厦,北京' 5 | city = '北京' 6 | place = (39.9789660352, 116.497157786) 7 | 8 | 9 | def test_baidu(): 10 | """ Expected result : 11 | http://api.map.baidu.com/geocoder/v2/?callback=renderOption&output=json&address=百度大厦&city=北京市&ak= 12 | """ 13 | g = geocoder.baidu(location, key='35d0b72b3e950e5d0b74b037262f8b41') 14 | assert g.ok 15 | osm_count, fields_count = g.debug()[0] 16 | assert osm_count == 0 17 | assert fields_count >= 7 18 | 19 | 20 | def test_baidu_reverse(): 21 | """ Expected result : 22 | http://api.map.baidu.com/geocoder/v2/?callback=renderReverse&location=39.9789660352,116.497157786&output=json&pois=1&ak= 23 | """ 24 | g = geocoder.baidu(place, method='reverse', key='35d0b72b3e950e5d0b74b037262f8b41') 25 | assert g.ok 26 | assert g.country == u'中国' 27 | assert g.state == u'北京市' 28 | assert g.city == u'北京市' 29 | assert g.street == u'酒仙桥路' 30 | -------------------------------------------------------------------------------- /docs/providers/Geocoder-ca.rst: -------------------------------------------------------------------------------- 1 | Geocoder.ca 2 | =========== 3 | 4 | Geocoder.ca - A Canadian and US location geocoder. 5 | Using Geocoder you can retrieve Geolytica's geocoded data from Geocoder.ca. 6 | 7 | Geocoding 8 | ~~~~~~~~~ 9 | 10 | .. code-block:: python 11 | 12 | >>> import geocoder 13 | >>> g = geocoder.geolytica('Ottawa, ON') 14 | >>> g.json 15 | ... 16 | 17 | Command Line Interface 18 | ---------------------- 19 | 20 | .. code-block:: bash 21 | 22 | $ geocode 'Ottawa, ON' --provider geolytica 23 | 24 | Parameters 25 | ---------- 26 | 27 | - `location`: Your search location you want geocoded. 28 | - `auth`: The authentication code for unthrottled service. 29 | - `strictmode`: Optionally you can prevent geocoder from making guesses on your input. 30 | - `strict`: Optional Parameter for enabling strict parsing of free form location input. 31 | - `method`: (default=geocode) Use the following: 32 | 33 | - geocode 34 | - `auth`: (optional) The authentication code for unthrottled service (premium API) 35 | 36 | References 37 | ---------- 38 | 39 | - `API Reference `_ 40 | -------------------------------------------------------------------------------- /geocoder/komoot_reverse.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # coding: utf8 3 | 4 | from __future__ import absolute_import 5 | 6 | import logging 7 | 8 | from geocoder.location import Location 9 | from geocoder.komoot import KomootResult, KomootQuery 10 | 11 | 12 | class KomootReverseResult(KomootResult): 13 | 14 | @property 15 | def ok(self): 16 | return bool(self.address) 17 | 18 | 19 | class KomootReverse(KomootQuery): 20 | """ 21 | Komoot REST API 22 | ======================= 23 | 24 | API Reference 25 | ------------- 26 | http://photon.komoot.de 27 | """ 28 | provider = 'komoot' 29 | method = 'reverse' 30 | 31 | _URL = 'https://photon.komoot.de/reverse' 32 | _RESULT_CLASS = KomootReverseResult 33 | 34 | def _build_params(self, location, provider_key, **kwargs): 35 | location = Location(location) 36 | return { 37 | 'lat': location.lat, 38 | 'lon': location.lng, 39 | } 40 | 41 | 42 | if __name__ == '__main__': 43 | logging.basicConfig(level=logging.INFO) 44 | g = KomootReverse("45.4 -75.7") 45 | g.debug() 46 | -------------------------------------------------------------------------------- /geocoder/osm_reverse.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # coding: utf8 3 | 4 | from __future__ import absolute_import 5 | from geocoder.osm import OsmQuery 6 | from geocoder.location import Location 7 | 8 | 9 | class OsmReverse(OsmQuery): 10 | """ 11 | Nominatim 12 | ========= 13 | Nominatim (from the Latin, 'by name') is a tool to search OSM data by name 14 | and address and to generate synthetic addresses of OSM points (reverse geocoding). 15 | 16 | API Reference 17 | ------------- 18 | http://wiki.openstreetmap.org/wiki/Nominatim 19 | """ 20 | provider = 'osm' 21 | method = 'reverse' 22 | 23 | def _build_params(self, location, provider_key, **kwargs): 24 | params = { 25 | 'q': str(Location(location)), 26 | 'format': 'jsonv2', 27 | 'addressdetails': 1, 28 | 'limit': kwargs.get('limit', 1) 29 | } 30 | if('lang_code' in kwargs): 31 | params['accept-language'] = kwargs.get('lang_code') 32 | return params 33 | 34 | 35 | if __name__ == '__main__': 36 | g = OsmReverse("45.3, -75.4") 37 | g.debug() 38 | -------------------------------------------------------------------------------- /tests/test_geocodefarm.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # coding: utf8 3 | 4 | import geocoder 5 | import requests_mock 6 | 7 | location = 'New York City' 8 | coordinates = [45.3, -75.4] 9 | 10 | 11 | def test_geocodefarm(): 12 | url = 'https://www.geocode.farm/v3/json/forward/?addr=New+York+City&lang=&country=&count=1' 13 | data_file = 'tests/results/geocodefarm.json' 14 | with requests_mock.Mocker() as mocker, open(data_file, 'r') as input: 15 | mocker.get(url, text=input.read()) 16 | result = geocoder.geocodefarm(location) 17 | assert result.ok 18 | osm_count, fields_count = result.debug()[0] 19 | assert osm_count >= 3 20 | assert fields_count >= 15 21 | 22 | 23 | def test_geocodefarm_reverse(): 24 | url = 'https://www.geocode.farm/v3/json/reverse/?lat=45.3&lon=-75.4&lang=&country=' 25 | data_file = 'tests/results/geocodefarm_reverse.json' 26 | with requests_mock.Mocker() as mocker, open(data_file, 'r') as input: 27 | mocker.get(url, text=input.read()) 28 | result = geocoder.geocodefarm(coordinates, method='reverse') 29 | assert result.ok 30 | -------------------------------------------------------------------------------- /docs/providers/FreeGeoIP.rst: -------------------------------------------------------------------------------- 1 | FreeGeoIP.net 2 | ============= 3 | freegeoip.net provides a public HTTP API for software developers to 4 | search the geolocation of IP addresses. It uses a database of IP addresses 5 | that are associated to cities along with other relevant information like 6 | time zone, latitude and longitude. 7 | 8 | You're allowed up to 10,000 queries per hour by default. Once this 9 | limit is reached, all of your requests will result in HTTP 403, 10 | forbidden, until your quota is cleared. 11 | 12 | Geocoding (IP Address) 13 | ~~~~~~~~~~~~~~~~~~~~~~ 14 | 15 | .. code-block:: python 16 | 17 | >>> import geocoder 18 | >>> g = geocoder.freegeoip('99.240.181.199') 19 | >>> g.json 20 | ... 21 | 22 | Command Line Interface 23 | ---------------------- 24 | 25 | .. code-block:: bash 26 | 27 | $ geocode '99.240.181.199' --provider freegeoip 28 | 29 | Parameters 30 | ---------- 31 | 32 | - `location`: Your search location you want geocoded. 33 | - `method`: (default=geocode) Use the following: 34 | 35 | - geocode 36 | 37 | References 38 | ---------- 39 | 40 | - `API Reference `_ 41 | -------------------------------------------------------------------------------- /tests/results/geonames_children.json: -------------------------------------------------------------------------------- 1 | { 2 | "totalResultsCount": 2, 3 | "geonames": [ 4 | { 5 | "adminCode1": "10", 6 | "lng": "-75.76583", 7 | "geonameId": 5901584, 8 | "toponymName": "Birch Manor", 9 | "countryId": "6251999", 10 | "fcl": "P", 11 | "population": 0, 12 | "countryCode": "CA", 13 | "name": "Birch Manor", 14 | "fclName": "city, village,...", 15 | "countryName": "Canada", 16 | "fcodeName": "section of populated place", 17 | "adminName1": "Quebec", 18 | "lat": "45.42472", 19 | "fcode": "PPLX" 20 | }, 21 | { 22 | "adminCode1": "10", 23 | "lng": "-75.58833", 24 | "geonameId": 6162703, 25 | "toponymName": "Templeton-Est", 26 | "countryId": "6251999", 27 | "fcl": "P", 28 | "population": 0, 29 | "countryCode": "CA", 30 | "name": "Templeton-Est", 31 | "fclName": "city, village,...", 32 | "countryName": "Canada", 33 | "fcodeName": "section of populated place", 34 | "adminName1": "Quebec", 35 | "lat": "45.49389", 36 | "fcode": "PPLX" 37 | } 38 | ] 39 | } -------------------------------------------------------------------------------- /tests/test_geocoder.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # coding: utf8 3 | 4 | import geocoder 5 | 6 | 7 | def test_entry_points(): 8 | geocoder.ip 9 | geocoder.osm 10 | geocoder.w3w 11 | geocoder.bing 12 | geocoder.here 13 | geocoder.tgos 14 | geocoder.baidu 15 | geocoder.gaode 16 | geocoder.yahoo 17 | geocoder.mapbox 18 | geocoder.google 19 | geocoder.yandex 20 | geocoder.tomtom 21 | geocoder.arcgis 22 | geocoder.ipinfo 23 | geocoder.mapzen 24 | geocoder.geonames 25 | geocoder.mapquest 26 | geocoder.timezone 27 | geocoder.maxmind 28 | geocoder.elevation 29 | geocoder.freegeoip 30 | geocoder.geolytica 31 | geocoder.timezone 32 | geocoder.opencage 33 | geocoder.places 34 | geocoder.canadapost 35 | geocoder.tamu 36 | geocoder.geocodefarm 37 | geocoder.uscensus 38 | 39 | 40 | def test_location(): 41 | g = geocoder.location('45.4215296, -75.6971931') 42 | assert g.ok 43 | g = geocoder.location({'lat': 45.4215296, 'lng': -75.6971931}) 44 | assert g.ok 45 | g = geocoder.location([45.4215296, -75.6971931]) 46 | assert g.ok 47 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013-15 Denis Carriere 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /docs/providers/Gaode.rst: -------------------------------------------------------------------------------- 1 | Gaode 2 | ===== 3 | 4 | Gaode(AMap) Maps Geocoding API is a free open the API, the default quota 5 | one 2000 times / day. 6 | 7 | This API only support china. 8 | 9 | Geocoding 10 | ~~~~~~~~~ 11 | 12 | .. code-block:: python 13 | 14 | >>> import geocoder # pip install geocoder 15 | >>> g = geocoder.gaode('方恒国际中心A座', key='') 16 | >>> g.json 17 | ... 18 | 19 | Command Line Interface 20 | ---------------------- 21 | 22 | .. code-block:: bash 23 | 24 | $ geocode '方恒国际中心A座' --provider gaode 25 | 26 | Environment Variables 27 | --------------------- 28 | 29 | To make sure your API key is store safely on your computer, you can define that API key using your system's environment variables. 30 | 31 | .. code-block:: bash 32 | 33 | $ export GAODE_API_KEY= 34 | 35 | Parameters 36 | ---------- 37 | 38 | - `location`: Your search location you want geocoded. 39 | - `key`: Gaode API key. 40 | - `method`: (default=geocode) Use the following: 41 | 42 | - geocode 43 | - reverse 44 | 45 | References 46 | ---------- 47 | 48 | - `API Reference `_ 49 | - `Get Gaode key `_ 50 | -------------------------------------------------------------------------------- /geocoder/locationiq.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # coding: utf8 3 | from __future__ import absolute_import 4 | 5 | import logging 6 | import json 7 | 8 | from geocoder.osm import OsmResult, OsmQuery 9 | from geocoder.keys import locationiq_key 10 | 11 | 12 | class LocationIQResult(OsmResult): 13 | pass 14 | 15 | 16 | class LocationIQQuery(OsmQuery): 17 | provider = 'locationiq' 18 | method = 'geocode' 19 | 20 | _URL = 'https://locationiq.org/v1/search.php' 21 | _RESULT_CLASS = LocationIQResult 22 | _KEY = locationiq_key 23 | _KEY_MANDATORY = True 24 | 25 | def _build_params(self, location, provider_key, **kwargs): 26 | if 'limit' in kwargs: 27 | kwargs['maxRows'] = kwargs['limit'] 28 | return { 29 | 'key': provider_key, 30 | 'q': location, 31 | 'format': 'json', 32 | 'addressdetails': 1, 33 | 'limit': kwargs.get('maxRows', 1), 34 | } 35 | 36 | 37 | if __name__ == '__main__': 38 | logging.basicConfig(level=logging.INFO) 39 | g = LocationIQQuery('Ottawa, Ontario') 40 | g.debug() 41 | g = LocationIQQuery('Ottawa, Ontario', maxRows=5) 42 | print(json.dumps(g.geojson, indent=4)) 43 | -------------------------------------------------------------------------------- /geocoder/google_reverse.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # coding: utf8 3 | 4 | from __future__ import absolute_import 5 | from geocoder.google import GoogleResult, GoogleQuery 6 | from geocoder.location import Location 7 | 8 | 9 | class GoogleReverseResult(GoogleResult): 10 | 11 | @property 12 | def ok(self): 13 | return bool(self.address) 14 | 15 | 16 | class GoogleReverse(GoogleQuery): 17 | """ 18 | Google Geocoding API 19 | ==================== 20 | Geocoding is the process of converting addresses (like "1600 Amphitheatre 21 | Parkway, Mountain View, CA") into geographic coordinates (like latitude 22 | 37.423021 and longitude -122.083739), which you can use to place markers or 23 | position the map. 24 | 25 | API Reference 26 | ------------- 27 | https://developers.google.com/maps/documentation/geocoding/ 28 | """ 29 | provider = 'google' 30 | method = 'reverse' 31 | 32 | def _location_init(self, location, **kwargs): 33 | return { 34 | 'latlng': str(Location(location)), 35 | 'sensor': 'false', 36 | } 37 | 38 | 39 | if __name__ == '__main__': 40 | g = GoogleReverse((45.4215296, -75.6971930)) 41 | g.debug() 42 | -------------------------------------------------------------------------------- /geocoder/gisgraphy_reverse.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # coding: utf8 3 | 4 | from __future__ import absolute_import 5 | 6 | import logging 7 | 8 | from geocoder.location import Location 9 | from geocoder.gisgraphy import GisgraphyResult, GisgraphyQuery 10 | 11 | 12 | class GisgraphyReverseResult(GisgraphyResult): 13 | 14 | @property 15 | def ok(self): 16 | return bool(self.address) 17 | 18 | 19 | class GisgraphyReverse(GisgraphyQuery): 20 | """ 21 | Gisgraphy REST API 22 | ======================= 23 | 24 | API Reference 25 | ------------- 26 | http://www.gisgraphy.com/documentation/user-guide.php 27 | """ 28 | provider = 'gisgraphy' 29 | method = 'reverse' 30 | 31 | _URL = 'https://services.gisgraphy.com/reversegeocoding/' 32 | _RESULT_CLASS = GisgraphyReverseResult 33 | 34 | def _build_params(self, location, provider_key, **kwargs): 35 | location = Location(location) 36 | return { 37 | 'lat': location.lat, 38 | 'lng': location.lng, 39 | 'format': 'json', 40 | } 41 | 42 | 43 | if __name__ == '__main__': 44 | logging.basicConfig(level=logging.INFO) 45 | g = GisgraphyReverse("45.4 -75.7") 46 | g.debug() 47 | -------------------------------------------------------------------------------- /tests/results/locationiq_reverse.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "place_id": "85985426", 4 | "licence": "API \u00a9 LocationIQ.org CC BY 4.0, Data \u00a9 OpenStreetMap contributors, ODbL 1.0", 5 | "osm_type": "way", 6 | "osm_id": "68588664", 7 | "boundingbox": [ 8 | "45.4201768", 9 | "45.4214404", 10 | "-75.6908211", 11 | "-75.6893108" 12 | ], 13 | "lat": "45.4208154", 14 | "lon": "-75.6901176990294", 15 | "display_name": "Ottawa City Hall, 110, Laurier Avenue West, Golden Triangle, Centretown, Somerset, Ottawa, Ontario, K2P 2K1, Canada", 16 | "class": "building", 17 | "type": "yes", 18 | "importance": 0.31303438301933, 19 | "address": { 20 | "building": "Ottawa City Hall", 21 | "house_number": "110", 22 | "road": "Laurier Avenue West", 23 | "neighbourhood": "Golden Triangle", 24 | "suburb": "Centretown", 25 | "city_district": "Somerset", 26 | "city": "Ottawa", 27 | "state": "Ontario", 28 | "postcode": "K2P 2K1", 29 | "country": "Canada", 30 | "country_code": "ca" 31 | } 32 | } 33 | ] 34 | -------------------------------------------------------------------------------- /tests/results/bing_batch_submission.json: -------------------------------------------------------------------------------- 1 | { 2 | "authenticationResultCode": "ValidCredentials", 3 | "brandLogoUri": "http:\/\/spatial.virtualearth.net\/Branding\/logo_powered_by.png", 4 | "copyright": "Copyright © 2018 Microsoft and its suppliers. All rights reserved. This API cannot be accessed and the content and any results may not be used, reproduced or transmitted in any manner without express written permission from Microsoft Corporation.", 5 | "resourceSets": [ 6 | { 7 | "estimatedTotal": 1, 8 | "resources": [ 9 | { 10 | "__type": "DataflowJob:http:\/\/schemas.microsoft.com\/search\/local\/ws\/rest\/v1", 11 | "id": "3bf1b729dddd498e9df45515cdb36130", 12 | "links": [ 13 | { 14 | "role": "self", 15 | "url": "https:\/\/spatial.virtualearth.net\/REST\/v1\/dataflows\/Geocode\/3bf1b729dddd498e9df45515cdb36130" 16 | } 17 | ], 18 | "createdDate": "Sat, 17 Feb 2018 22:41:49 GMT", 19 | "description": "Geocode", 20 | "failedEntityCount": 0, 21 | "processedEntityCount": 0, 22 | "status": "Pending", 23 | "totalEntityCount": 2 24 | } 25 | ] 26 | } 27 | ], 28 | "statusCode": 201, 29 | "statusDescription": "Created", 30 | "traceId": "cb30390bc3524eebb9a39baae7a31d9c|DB40060622|7.7.0.0|" 31 | } -------------------------------------------------------------------------------- /docs/providers/GeoOttawa.rst: -------------------------------------------------------------------------------- 1 | GeoOttawa 2 | ========= 3 | 4 | This data was collected in the field using GPS software on handheld computers. Not all information has been verified for accuracy and therefore should only be used in an advisory capacity. Forestry Services reserves the right to revise the data pursuant to further inspection/review. If you find any errors or omissions, please report them to 3-1-1. 5 | 6 | Geocoding 7 | ~~~~~~~~~ 8 | 9 | .. code-block:: python 10 | 11 | >>> import geocoder 12 | >>> g = geocoder.ottawa('453 Booth Street') 13 | >>> g.json 14 | ... 15 | 16 | This provider may return multiple results by setting the parameter `maxRows` to the desired number (1 by default). You can access those results as described in the page ':doc:`/results`'. 17 | 18 | Command Line Interface 19 | ---------------------- 20 | 21 | .. code-block:: bash 22 | 23 | $ geocode '453 Booth Street' --provider ottawa 24 | 25 | Parameters 26 | ---------- 27 | 28 | - `location`: Your search location you want geocoded. 29 | - `maxRows`: (default=1) Max number of results to fetch 30 | - `method`: (default=geocode) Use the following: 31 | 32 | - geocode 33 | 34 | References 35 | ---------- 36 | 37 | - `GeoOttawa Map `_ 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /docs/_themes/kr/layout.html: -------------------------------------------------------------------------------- 1 | {%- extends "basic/layout.html" %} 2 | {%- block extrahead %} 3 | {{ super() }} 4 | {% if theme_touch_icon %} 5 | 6 | {% endif %} 7 | 8 | {% endblock %} 9 | {%- block relbar2 %}{% endblock %} 10 | {%- block footer %} 11 | 14 | 15 | Fork me on GitHub 16 | 17 | 18 | 31 | 32 | 33 | 34 | {%- endblock %} 35 | -------------------------------------------------------------------------------- /docs/_themes/kr/static/small_flask.css: -------------------------------------------------------------------------------- 1 | /* 2 | * small_flask.css_t 3 | * ~~~~~~~~~~~~~~~~~ 4 | * 5 | * :copyright: Copyright 2010 by Armin Ronacher. 6 | * :license: Flask Design License, see LICENSE for details. 7 | */ 8 | 9 | body { 10 | margin: 0; 11 | padding: 20px 30px; 12 | } 13 | 14 | div.documentwrapper { 15 | float: none; 16 | background: white; 17 | } 18 | 19 | div.sphinxsidebar { 20 | display: block; 21 | float: none; 22 | width: 102.5%; 23 | margin: 50px -30px -20px -30px; 24 | padding: 10px 20px; 25 | background: #333; 26 | color: white; 27 | } 28 | 29 | div.sphinxsidebar h3, div.sphinxsidebar h4, div.sphinxsidebar p, 30 | div.sphinxsidebar h3 a { 31 | color: white; 32 | } 33 | 34 | div.sphinxsidebar a { 35 | color: #aaa; 36 | } 37 | 38 | div.sphinxsidebar p.logo { 39 | display: none; 40 | } 41 | 42 | div.document { 43 | width: 100%; 44 | margin: 0; 45 | } 46 | 47 | div.related { 48 | display: block; 49 | margin: 0; 50 | padding: 10px 0 20px 0; 51 | } 52 | 53 | div.related ul, 54 | div.related ul li { 55 | margin: 0; 56 | padding: 0; 57 | } 58 | 59 | div.footer { 60 | display: none; 61 | } 62 | 63 | div.bodywrapper { 64 | margin: 0; 65 | } 66 | 67 | div.body { 68 | min-height: 0; 69 | padding: 0; 70 | } 71 | -------------------------------------------------------------------------------- /geocoder/mapquest_reverse.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # coding: utf8 3 | 4 | from __future__ import absolute_import 5 | from geocoder.mapquest import MapquestResult, MapquestQuery 6 | from geocoder.location import Location 7 | 8 | 9 | class MapQuestReverseResult(MapquestResult): 10 | 11 | @property 12 | def ok(self): 13 | return bool(self.quality) 14 | 15 | 16 | class MapquestReverse(MapquestQuery): 17 | """ 18 | MapQuest 19 | ======== 20 | The geocoding service enables you to take an address and get the 21 | associated latitude and longitude. You can also use any latitude 22 | and longitude pair and get the associated address. Three types of 23 | geocoding are offered: address, reverse, and batch. 24 | 25 | API Reference 26 | ------------- 27 | http://www.mapquestapi.com/geocoding/ 28 | 29 | """ 30 | provider = 'mapquest' 31 | method = 'reverse' 32 | 33 | _URL = 'http://www.mapquestapi.com/geocoding/v1/reverse' 34 | 35 | def _build_params(self, location, provider_key, **kwargs): 36 | return { 37 | 'key': provider_key, 38 | 'location': str(Location(location)), 39 | 'maxResults': 1, 40 | 'outFormat': 'json', 41 | } 42 | 43 | 44 | if __name__ == '__main__': 45 | g = MapquestReverse([45.50, -76.05]) 46 | g.debug() 47 | -------------------------------------------------------------------------------- /tests/test_mapbox.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # coding: utf8 3 | 4 | import geocoder 5 | 6 | location = 'Ottawa, Ontario' 7 | city = 'Ottawa' 8 | ottawa = (45.4215296, -75.6971930) 9 | 10 | winnetka = 'Winnetka' 11 | winnetka_bbox = [-118.604794,34.172684,-118.500938,34.236144] 12 | 13 | 14 | def test_mapbox(): 15 | g = geocoder.mapbox(location) 16 | assert g.ok 17 | osm_count, fields_count = g.debug()[0] 18 | assert osm_count >= 2 19 | assert fields_count >= 11 20 | 21 | 22 | def test_mapbox_with_proximity(): 23 | g = geocoder.mapbox(location, proximity=ottawa) 24 | assert g.ok 25 | osm_count, fields_count = g.debug()[0] 26 | assert osm_count >= 2 27 | assert fields_count >= 11 28 | 29 | 30 | def test_mapbox_with_bbox(): 31 | g = geocoder.mapbox(winnetka, bbox=winnetka_bbox) 32 | assert g.ok 33 | osm_count, fields_count = g.debug()[0] 34 | assert osm_count >= 2 35 | assert fields_count >= 11 36 | 37 | for result in g: 38 | assert (result.lng >= winnetka_bbox[0]) and (result.lng <= winnetka_bbox[2]) 39 | assert (result.lat >= winnetka_bbox[1]) and (result.lat <= winnetka_bbox[3]) 40 | 41 | 42 | def test_mapbox_reverse(): 43 | g = geocoder.mapbox(ottawa, method='reverse') 44 | assert g.ok 45 | 46 | 47 | def test_multi_results(): 48 | g = geocoder.mapbox(location) 49 | assert len(g) == 5 50 | -------------------------------------------------------------------------------- /docs/providers/ArcGIS.rst: -------------------------------------------------------------------------------- 1 | ArcGIS 2 | ====== 3 | 4 | The World Geocoding Service finds addresses and places in all supported countries 5 | from a single endpoint. The service can find point locations of addresses, 6 | business names, and so on. The output points can be visualized on a map, 7 | inserted as stops for a route, or loaded as input for a spatial analysis. 8 | an address, retrieving imagery metadata, or creating a route. 9 | 10 | Geocoding 11 | ~~~~~~~~~ 12 | 13 | .. code-block:: python 14 | 15 | >>> import geocoder 16 | >>> g = geocoder.arcgis('Redlands, CA') 17 | >>> g.json 18 | ... 19 | 20 | This provider may return multiple results by setting the parameter `maxRows` to the desired number (1 by default). You can access those results as described in the page ':doc:`/results`'. 21 | 22 | Command Line Interface 23 | ---------------------- 24 | 25 | .. code-block:: bash 26 | 27 | $ geocode 'Redlands, CA' --provider arcgis 28 | 29 | Parameters 30 | ---------- 31 | 32 | - `location`: Your search location you want geocoded. 33 | - `maxRows`: (default=1) Max number of results to fetch 34 | - `limit`: *Deprecated*, same as maxRows 35 | - `method`: (default=geocode) Use the following: 36 | 37 | - geocode 38 | 39 | References 40 | ---------- 41 | 42 | - `ArcGIS Geocode API `_ 43 | -------------------------------------------------------------------------------- /docs/features/Command Line Interface.md: -------------------------------------------------------------------------------- 1 | # Command Line Interface 2 | 3 | The command line tool allows you to geocode one or many strings, either 4 | passed as an argument, passed via stdin, or contained in a referenced file. 5 | 6 | ```bash 7 | $ geocode "Ottawa" 8 | { 9 | "accuracy": "Rooftop", 10 | "quality": "PopulatedPlace", 11 | "lng": -75.68800354003906, 12 | "status": "OK", 13 | "locality": "Ottawa", 14 | "country": "Canada", 15 | "provider": "bing", 16 | "state": "ON", 17 | "location": "Ottawa", 18 | "address": "Ottawa, ON", 19 | "lat": 45.389198303222656 20 | } 21 | ``` 22 | 23 | Now, suppose you have a file with two lines, which you want to geocode. 24 | 25 | ```bash 26 | $ geocode "textfile.txt" 27 | {"status": "OK", "locality": "Ottawa", ...} 28 | {"status": "OK", "locality": "Boston", ...} 29 | ``` 30 | 31 | The output is, by default, sent to stdout, so it can be conveniently parsed 32 | by JSON parsing tools like `jq`. 33 | 34 | ```bash 35 | $ geocode "textfile.txt" | jq [.lat,.lng,.country] -c 36 | [45.389198303222656,-75.68800354003906,"Canada"] 37 | [42.35866165161133,-71.0567398071289,"United States"] 38 | ``` 39 | 40 | Parsing a batch geocode to CSV can also be done with `jq`. Build your headers first then run the `geocode` application. 41 | 42 | ```bash 43 | $ echo 'lat,lng,locality' > test.csv 44 | $ geocode cities.txt | jq [.lat,.lng,.locality] -c | jq -r '@csv' >> test.csv 45 | ``` 46 | -------------------------------------------------------------------------------- /docs/providers/IPInfo.rst: -------------------------------------------------------------------------------- 1 | IP Info.io 2 | ========== 3 | 4 | Use the IPInfo.io IP lookup API to quickly and simply integrate IP geolocation 5 | into your script or website. Save yourself the hassle of setting up local GeoIP 6 | libraries and having to remember to regularly update the data. 7 | 8 | Geocoding (IP Address) 9 | ~~~~~~~~~~~~~~~~~~~~~~ 10 | 11 | .. code-block:: python 12 | 13 | >>> import geocoder 14 | >>> g = geocoder.ipinfo('199.7.157.0') 15 | >>> g.latlng 16 | [45.413140, -75.656703] 17 | >>> g.city 18 | 'Toronto' 19 | >>> g.json 20 | ... 21 | 22 | Geocode your own IP 23 | ~~~~~~~~~~~~~~~~~~~ 24 | 25 | To retrieve your own IP address, simply have `''` or `'me'` as the input. 26 | 27 | .. code-block:: python 28 | 29 | >>> import geocoder 30 | >>> g = geocoder.ipinfo('me') 31 | >>> g.latlng 32 | [45.413140, -75.656703] 33 | >>> g.ip 34 | '199.7.157.0' 35 | >>> g.json 36 | ... 37 | 38 | Command Line Interface 39 | ---------------------- 40 | 41 | .. code-block:: bash 42 | 43 | $ geocode '199.7.157.0' --provider ipinfo | jq . 44 | 45 | Parameters 46 | ---------- 47 | 48 | - `location`: Your search location you want geocoded. 49 | - `location`: (optional) `''` will return your current IP address's location. 50 | - `method`: (default=geocode) Use the following: 51 | 52 | - geocode 53 | 54 | References 55 | ---------- 56 | 57 | - `IpinfoIo `_ -------------------------------------------------------------------------------- /geocoder/mapzen_reverse.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # coding: utf8 3 | 4 | from __future__ import absolute_import 5 | 6 | import logging 7 | 8 | from geocoder.mapzen import MapzenResult, MapzenQuery 9 | from geocoder.location import Location 10 | 11 | 12 | class MapzenReverseResult(MapzenResult): 13 | 14 | @property 15 | def ok(self): 16 | return bool(self.address) 17 | 18 | 19 | class MapzenReverse(MapzenQuery): 20 | """ 21 | Mapzen REST API 22 | ======================= 23 | 24 | API Reference 25 | ------------- 26 | https://mapzen.com/documentation/search/reverse/ 27 | """ 28 | provider = 'mapzen' 29 | method = 'reverse' 30 | 31 | _URL = 'https://search.mapzen.com/v1/reverse' 32 | _RESULT_CLASS = MapzenReverseResult 33 | 34 | def _build_params(self, location, provider_key, **kwargs): 35 | location = Location(location) 36 | return { 37 | 'point.lat': location.lat, 38 | 'point.lon': location.lng, 39 | 'size': kwargs.get('size', 1), 40 | 'layers': kwargs.get('layers'), 41 | 'source': kwargs.get('sources'), 42 | 'boundary.country': kwargs.get('country'), 43 | 'api_key': provider_key 44 | } 45 | 46 | 47 | if __name__ == '__main__': 48 | logging.basicConfig(level=logging.INFO) 49 | g = MapzenReverse("45.4049053 -75.7077965", key='search-un1M9Hk') 50 | g.debug() 51 | -------------------------------------------------------------------------------- /geocoder/bing_reverse.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # coding: utf8 3 | 4 | from __future__ import absolute_import 5 | from geocoder.bing import BingResult, BingQuery 6 | from geocoder.location import Location 7 | 8 | 9 | class BingReverseResult(BingResult): 10 | 11 | @property 12 | def ok(self): 13 | return bool(self.address) 14 | 15 | 16 | class BingReverse(BingQuery): 17 | """ 18 | Bing Maps REST Services 19 | ======================= 20 | The Bing™ Maps REST Services Application Programming Interface (API) 21 | provides a Representational State Transfer (REST) interface to 22 | perform tasks such as creating a static map with pushpins, geocoding 23 | an address, retrieving imagery metadata, or creating a route. 24 | 25 | API Reference 26 | ------------- 27 | http://msdn.microsoft.com/en-us/library/ff701714.aspx 28 | 29 | """ 30 | provider = 'bing' 31 | method = 'reverse' 32 | 33 | _URL = u'http://dev.virtualearth.net/REST/v1/Locations/{0}' 34 | 35 | def _build_params(self, location, provider_key, **kwargs): 36 | return { 37 | 'o': 'json', 38 | 'key': provider_key, 39 | 'maxResults': 1, 40 | } 41 | 42 | def _before_initialize(self, location, **kwargs): 43 | self.url = self.url.format(str(Location(location))) 44 | 45 | 46 | if __name__ == '__main__': 47 | g = BingReverse([45.4049053, -75.7077965], key=None) 48 | g.debug() 49 | -------------------------------------------------------------------------------- /geocoder/w3w_reverse.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # coding: utf8 3 | 4 | from __future__ import absolute_import 5 | 6 | from geocoder.w3w import W3WResult, W3WQuery 7 | 8 | 9 | class W3WReverseResult(W3WResult): 10 | 11 | @property 12 | def ok(self): 13 | return bool(self.words) 14 | 15 | 16 | class W3WReverse(W3WQuery): 17 | """ 18 | what3words 19 | ========== 20 | what3words is a global grid of 57 trillion 3mx3m squares. 21 | Each square has a 3 word address that can be communicated quickly, 22 | easily and with no ambiguity. 23 | 24 | Addressing the world 25 | 26 | Everyone and everywhere now has an address 27 | 28 | Params 29 | ------ 30 | :param location: Your search location you want geocoded. 31 | :param key: W3W API key. 32 | :param method: Chose a method (geocode, method) 33 | 34 | References 35 | ---------- 36 | API Reference: http://developer.what3words.com/ 37 | Get W3W key: http://developer.what3words.com/api-register/ 38 | """ 39 | provider = 'w3w' 40 | method = 'reverse' 41 | 42 | _URL = 'https://api.what3words.com/v2/reverse' 43 | _RESULT_CLASS = W3WReverseResult 44 | 45 | def _build_params(self, location, provider_key, **kwargs): 46 | return { 47 | 'coords': location, 48 | 'key': provider_key, 49 | } 50 | 51 | 52 | if __name__ == '__main__': 53 | g = W3WReverse([45.15, -75.14]) 54 | g.debug() 55 | -------------------------------------------------------------------------------- /geocoder/here_reverse.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # coding: utf8 3 | 4 | from __future__ import absolute_import 5 | 6 | from geocoder.location import Location 7 | from geocoder.here import HereResult, HereQuery 8 | 9 | 10 | class HereReverseResult(HereResult): 11 | 12 | @property 13 | def ok(self): 14 | return bool(self.address) 15 | 16 | 17 | class HereReverse(HereQuery): 18 | """ 19 | HERE Geocoding REST API 20 | ======================= 21 | Send a request to the geocode endpoint to find an address 22 | using a combination of country, state, county, city, 23 | postal code, district, street and house number. 24 | 25 | API Reference 26 | ------------- 27 | https://developer.here.com/rest-apis/documentation/geocoder 28 | """ 29 | provider = 'here' 30 | method = 'reverse' 31 | 32 | _RESULT_CLASS = HereReverseResult 33 | _URL = 'http://reverse.geocoder.cit.api.here.com/6.2/reversegeocode.json' 34 | 35 | def _build_params(self, location, provider_key, **kwargs): 36 | params = super(HereReverse, self)._build_params(location, provider_key, **kwargs) 37 | del params['searchtext'] 38 | 39 | location = str(Location(location)) 40 | params.update({ 41 | 'prox': location, 42 | 'mode': 'retrieveAddresses', 43 | 'gen': 8, 44 | }) 45 | return params 46 | 47 | 48 | if __name__ == '__main__': 49 | g = HereReverse([45.4049053, -75.7077965]) 50 | g.debug() 51 | -------------------------------------------------------------------------------- /geocoder/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # coding: utf8 3 | 4 | from __future__ import absolute_import 5 | 6 | """ 7 | Geocoder 8 | ~~~~~~~~ 9 | 10 | Simple and consistent geocoding library written in Python. 11 | 12 | Many online providers such as Google & Bing have geocoding services, 13 | these providers do not include Python libraries and have different 14 | JSON responses between each other. 15 | 16 | Consistant JSON responses from various providers. 17 | 18 | >>> g = geocoder.google('New York City') 19 | >>> g.latlng 20 | [40.7127837, -74.0059413] 21 | >>> g.state 22 | 'New York' 23 | >>> g.json 24 | ... 25 | 26 | """ 27 | 28 | __title__ = 'geocoder' 29 | __author__ = 'Denis Carriere' 30 | __author_email__ = 'carriere.denis@gmail.com' 31 | __version__ = '1.38.1' 32 | __license__ = 'MIT' 33 | __copyright__ = 'Copyright (c) 2013-2016 Denis Carriere' 34 | 35 | # CORE 36 | from geocoder.api import get, yahoo, bing, geonames, mapquest, google, mapbox # noqa 37 | from geocoder.api import nokia, osm, tomtom, geolytica, arcgis, opencage, locationiq # noqa 38 | from geocoder.api import maxmind, ipinfo, freegeoip, ottawa, here, baidu, gaode, w3w # noqa 39 | from geocoder.api import yandex, mapzen, komoot, tamu, geocodefarm, tgos, uscensus # noqa 40 | from geocoder.api import gisgraphy # noqa 41 | 42 | # EXTRAS 43 | from geocoder.api import timezone, elevation, places, ip, canadapost, reverse, distance, location # noqa 44 | 45 | # CLI 46 | from geocoder.cli import cli # noqa 47 | -------------------------------------------------------------------------------- /docs/examples/write to csv.md: -------------------------------------------------------------------------------- 1 | # Write to CSV 2 | 3 | ## Single Address 4 | 5 | ```python 6 | import geocoder 7 | import csv 8 | 9 | g = geocoder.bing('Avenida da Republica, Lisboa') 10 | 11 | with open('test.csv', 'wb') as f: 12 | writer = csv.DictWriter(f, fieldnames=g.fieldnames) 13 | writer.writeheader() 14 | writer.writerow(g.json) 15 | ``` 16 | **Note**: The `fieldnames` is new in 1.1.3, `attributes` in the earlier versions. 17 | 18 | ## Multiple Address 19 | 20 | The CSV file used for **locations.csv**. 21 | 22 | Using `delimiter` for parsing a CSV might include `<\t> <;> <|> <,>` 23 | 24 | 25 | | location | extra | 26 | |-------------|-----------| 27 | | Canada | best | 28 | | Australia | amazing | 29 | | Venezuela | awesome | 30 | 31 | ```python 32 | import geocoder 33 | import csv 34 | 35 | rows = [] 36 | fieldnames = ['location', 'extra', 'lat', 'lng', 'state', 'country'] 37 | 38 | with open('locations.csv') as f: 39 | reader = csv.DictReader(f, delimiter=';') 40 | for line in reader: 41 | g = geocoder.google(line['location']) 42 | 43 | # Add the CSV line data into the Geocoder JSON result 44 | result = g.json 45 | result.update(line) 46 | 47 | # Store Geocoder results in a list to save it later 48 | rows.append(result) 49 | 50 | with open('locations_new.csv', 'wb') as f: 51 | writer = csv.DictWriter(f, fieldnames=fieldnames, extrasaction='ignore') 52 | writer.writeheader() 53 | writer.writerows(rows) 54 | ``` -------------------------------------------------------------------------------- /tests/test_canadapost.py: -------------------------------------------------------------------------------- 1 | # coding: utf8 2 | 3 | import geocoder 4 | import requests_mock 5 | 6 | location = "453 Booth Street, ON" 7 | 8 | 9 | def test_canadapost(): 10 | url_1 = 'https://ws1.postescanada-canadapost.ca/AddressComplete/Interactive/Find/v2.10/json3ex.ws?Key=fake&LastId=&Country=ca&SearchFor=Everything&SearchTerm=453+Booth+Street%2C+ON&LanguagePreference=en&%24cache=true' 11 | url_2 = 'https://ws1.postescanada-canadapost.ca/AddressComplete/Interactive/Find/v2.10/json3ex.ws?Key=fake&LastId=CA%7CCP%7CENG%7CON-OTTAWA-BOOTH_ST-453&Country=ca&SearchFor=Everything&SearchTerm=453+Booth+Street%2C+ON&LanguagePreference=en&%24cache=true' 12 | url_3 = 'https://ws1.postescanada-canadapost.ca/AddressComplete/Interactive/RetrieveFormatted/v2.10/json3ex.ws?Key=fake&Id=CA%7CCP%7CB%7C80225509&Source=&MaxResults=3&cache=true' 13 | data_file_1 = 'tests/results/canadapost_find_1.json' 14 | data_file_2 = 'tests/results/canadapost_find_2.json' 15 | data_file_3 = 'tests/results/canadapost_retrieve.json' 16 | with requests_mock.Mocker() as mocker, open(data_file_1, 'r') as input_1, open(data_file_2, 'r') as input_2, open(data_file_3, 'r') as input_3: 17 | mocker.get(url_1, text=input_1.read()) 18 | mocker.get(url_2, text=input_2.read()) 19 | mocker.get(url_3, text=input_3.read()) 20 | g = geocoder.canadapost(location, key='fake', maxRows=3) 21 | assert g.ok 22 | osm_count, fields_count = g.debug()[0] 23 | assert osm_count >= 6 24 | assert fields_count >= 15 25 | -------------------------------------------------------------------------------- /tests/results/uscensus.json: -------------------------------------------------------------------------------- 1 | { 2 | "result": { 3 | "input": { 4 | "address": { 5 | "address": "4600 Silver Hill Road, Suitland, MD 20746" 6 | }, 7 | "benchmark": { 8 | "isDefault": false, 9 | "benchmarkName": "Public_AR_Census2010", 10 | "benchmarkDescription": "Public Address Ranges - Census 2010 Benchmark", 11 | "id": "9" 12 | } 13 | }, 14 | "addressMatches": [ 15 | { 16 | "matchedAddress": "4600 Silver Hill Rd, SUITLAND, MD, 20746", 17 | "coordinates": { 18 | "x": -76.92691, 19 | "y": 38.846542 20 | }, 21 | "tigerLine": { 22 | "tigerLineId": "613199520", 23 | "side": "L" 24 | }, 25 | "addressComponents": { 26 | "zip": "20746", 27 | "city": "SUITLAND", 28 | "suffixType": "Rd", 29 | "suffixDirection": "", 30 | "suffixQualifier": "", 31 | "fromAddress": "4600", 32 | "toAddress": "4712", 33 | "preQualifier": "", 34 | "preDirection": "", 35 | "preType": "", 36 | "streetName": "Silver Hill", 37 | "state": "MD" 38 | } 39 | } 40 | ] 41 | } 42 | } -------------------------------------------------------------------------------- /tests/results/bing_batch_confirmation.json: -------------------------------------------------------------------------------- 1 | { 2 | "authenticationResultCode": "ValidCredentials", 3 | "brandLogoUri": "http:\/\/spatial.virtualearth.net\/Branding\/logo_powered_by.png", 4 | "copyright": "Copyright © 2018 Microsoft and its suppliers. All rights reserved. This API cannot be accessed and the content and any results may not be used, reproduced or transmitted in any manner without express written permission from Microsoft Corporation.", 5 | "resourceSets": [ 6 | { 7 | "estimatedTotal": 1, 8 | "resources": [ 9 | { 10 | "__type": "DataflowJob:http:\/\/schemas.microsoft.com\/search\/local\/ws\/rest\/v1", 11 | "id": "3bf1b729dddd498e9df45515cdb36130", 12 | "links": [ 13 | { 14 | "role": "self", 15 | "url": "https:\/\/spatial.virtualearth.net\/REST\/v1\/dataflows\/Geocode\/3bf1b729dddd498e9df45515cdb36130" 16 | }, 17 | { 18 | "name": "succeeded", 19 | "role": "output", 20 | "url": "https:\/\/spatial.virtualearth.net\/REST\/v1\/dataflows\/Geocode\/3bf1b729dddd498e9df45515cdb36130\/output\/succeeded" 21 | } 22 | ], 23 | "completedDate": "Sat, 17 Feb 2018 22:41:52 GMT", 24 | "createdDate": "Sat, 17 Feb 2018 22:41:49 GMT", 25 | "description": "Geocode", 26 | "failedEntityCount": 0, 27 | "processedEntityCount": 2, 28 | "status": "Completed", 29 | "totalEntityCount": 2 30 | } 31 | ] 32 | } 33 | ], 34 | "statusCode": 200, 35 | "statusDescription": "OK", 36 | "traceId": "b89eae39c390459aa6c509a6b37f8b82|DB40060622|7.7.0.0|" 37 | } -------------------------------------------------------------------------------- /docs/_templates/side-primary.html: -------------------------------------------------------------------------------- 1 | 6 | 7 |

8 | 10 |

11 | 12 |

13 | Geocoder is a simple and consistent geocoding library written in Python. 14 | Dealing with multiple different geocoding provider such as Google, Bing, OSM & many more has never been easier. 15 |

16 | 17 | 18 |

Support

19 |

20 | If you are having issues we would love to hear from you. Just 21 | hit me up. You can alternatively raise an issue here on Github. 23 |

24 | 25 |

Stay Informed

26 | 27 |

29 | 30 |

31 |

-------------------------------------------------------------------------------- /docs/providers/MaxMind.rst: -------------------------------------------------------------------------------- 1 | MaxMind 2 | ======= 3 | 4 | MaxMind's GeoIP2 products enable you to identify the location, 5 | organization, connection speed, and user type of your Internet 6 | visitors. The GeoIP2 databases are among the most popular and 7 | accurate IP geolocation databases available. 8 | Using Geocoder you can retrieve Maxmind's geocoded data from MaxMind's GeoIP2. 9 | 10 | Geocoding (IP Address) 11 | ~~~~~~~~~~~~~~~~~~~~~~ 12 | 13 | .. code-block:: python 14 | 15 | >>> import geocoder 16 | >>> g = geocoder.maxmind('199.7.157.0') 17 | >>> g.latlng 18 | [45.413140, -75.656703] 19 | >>> g.city 20 | 'Toronto' 21 | >>> g.json 22 | ... 23 | 24 | Geocode your own IP 25 | ~~~~~~~~~~~~~~~~~~~ 26 | 27 | To retrieve your own IP address, simply have `''` or `'me'` as the input. 28 | 29 | .. code-block:: python 30 | 31 | >>> import geocoder 32 | >>> g = geocoder.maxmind('me') 33 | >>> g.latlng 34 | [45.413140, -75.656703] 35 | >>> g.ip 36 | '199.7.157.0' 37 | >>> g.json 38 | ... 39 | 40 | 41 | Command Line Interface 42 | ---------------------- 43 | 44 | .. code-block:: bash 45 | 46 | $ geocode '8.8.8.8' --provider maxmind | jq . 47 | 48 | Parameters 49 | ---------- 50 | 51 | - `location`: Your search IP Address you want geocoded. 52 | - `location`: (optional) `'me'` will return your current IP address's location. 53 | - `method`: (default=geocode) Use the following: 54 | 55 | - geocode 56 | 57 | References 58 | ---------- 59 | 60 | - `MaxMind's GeoIP2 `_ -------------------------------------------------------------------------------- /geocoder/opencage_reverse.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # coding: utf8 3 | 4 | from __future__ import absolute_import 5 | 6 | import logging 7 | 8 | from geocoder.opencage import OpenCageResult, OpenCageQuery 9 | from geocoder.location import Location 10 | 11 | 12 | class OpenCageReverseResult(OpenCageResult): 13 | 14 | @property 15 | def ok(self): 16 | return bool(self.address) 17 | 18 | 19 | class OpenCageReverse(OpenCageQuery): 20 | """ 21 | OpenCage Geocoding Services 22 | =========================== 23 | OpenCage Geocoder simple, easy, and open geocoding for the entire world 24 | Our API combines multiple geocoding systems in the background. 25 | Each is optimized for different parts of the world and types of requests. 26 | We aggregate the best results from open data sources and algorithms so you don't have to. 27 | Each is optimized for different parts of the world and types of requests. 28 | 29 | API Reference 30 | ------------- 31 | https://geocoder.opencagedata.com/api 32 | """ 33 | provider = 'opencage' 34 | method = 'reverse' 35 | 36 | _URL = 'http://api.opencagedata.com/geocode/v1/json' 37 | _RESULT_CLASS = OpenCageReverseResult 38 | 39 | def _build_params(self, location, provider_key, **kwargs): 40 | location = Location(location) 41 | return { 42 | 'query': location, 43 | 'key': provider_key, 44 | } 45 | 46 | if __name__ == '__main__': 47 | logging.basicConfig(level=logging.INFO) 48 | g = OpenCageReverse([45.4049053, -75.7077965]) 49 | g.debug() 50 | -------------------------------------------------------------------------------- /geocoder/mapbox_reverse.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # coding: utf8 3 | 4 | from __future__ import absolute_import 5 | from geocoder.mapbox import MapboxResult, MapboxQuery 6 | from geocoder.location import Location 7 | 8 | 9 | class MapboxReverseResult(MapboxResult): 10 | 11 | @property 12 | def ok(self): 13 | return bool(self.address) 14 | 15 | 16 | class MapboxReverse(MapboxQuery): 17 | """ 18 | Mapbox Reverse Geocoding 19 | ======================== 20 | Reverse geocoding lets you reverse this process, turning a 21 | pair of lat/lon coordinates into a meaningful place name 22 | (-77.036,38.897 → 1600 Pennsylvania Ave NW). 23 | 24 | API Reference 25 | ------------- 26 | https://www.mapbox.com/developers/api/geocoding/ 27 | 28 | Get Mapbox Access Token 29 | ----------------------- 30 | https://www.mapbox.com/account 31 | """ 32 | provider = 'mapbox' 33 | method = 'reverse' 34 | 35 | _URL = 'https://api.mapbox.com/geocoding/v5/mapbox.places/{lng},{lat}.json' 36 | 37 | def _build_params(self, location, provider_key, **kwargs): 38 | return { 39 | 'access_token': provider_key, 40 | 'country': kwargs.get('country'), 41 | 'types': kwargs.get('types'), 42 | } 43 | 44 | def _before_initialize(self, location, **kwargs): 45 | self.location = str(Location(location)) 46 | lat, lng = Location(location).latlng 47 | self.url = self.url.format(lng=lng, lat=lat) 48 | 49 | 50 | if __name__ == '__main__': 51 | g = MapboxReverse([45.4049053, -75.7077965]) 52 | g.debug() 53 | -------------------------------------------------------------------------------- /docs/features/Confidence Score.md: -------------------------------------------------------------------------------- 1 | # Confidence Score 2 | 3 | Based from [OpenCage API](https://geocoder.opencagedata.com/api#quickstart) 4 | 5 | ## Geocoding Confidence 6 | 7 | The OpenCage Geocoder will always attempt to find a match for as many parts of a query as it can, but this isn't always possible to do. Where a partial match is made, for example a street name can be matched but a specific house number on that street cannot be matched, the geocoder will still return a result but the granularity of the match will not be as high as if the house number was matched. 8 | 9 | The confidence that the geocoder has in a match returned in the confidence field. This contains a value between 0 and 10, where 0 reflects no confidence and 10 reflects high confidence. 10 | 11 | Confidence is calculated by measuring the distance in kilometres between the South West and North East corners of each results bounding box; a smaller distance represents a high confidence while a large distance represents a lower confidence. 12 | 13 | Please note, you can supply the optional min_confidence parameter (see below). 14 | 15 | 16 | |Score | Description | 17 | |:----:|:---------------------------| 18 | | 10 | less than 0.25 km distance | 19 | | 9 | less than 0.5 km distance | 20 | | 8 | less than 1 km distance | 21 | | 7 | less than 5 km distance | 22 | | 6 | less than 7.5 km distance | 23 | | 5 | less than 10 km distance | 24 | | 4 | less than 15 km distance | 25 | | 3 | less than 20 km distance | 26 | | 2 | less than 25 km distance | 27 | | 1 | 25 km or greater distance | 28 | | 0 | unable to determine a bounding box| -------------------------------------------------------------------------------- /docs/providers/What3Words.rst: -------------------------------------------------------------------------------- 1 | What3Words 2 | ========== 3 | 4 | What3Words is a global grid of 57 trillion 3mx3m squares. 5 | Each square has a unique 3 word address that people can find and communicate quickly, easily, and without ambiguity. 6 | 7 | **Addressing the world** 8 | 9 | Everyone and everywhere now has an address 10 | 11 | Geocoding (3 Words) 12 | ~~~~~~~~~~~~~~~~~~~ 13 | 14 | .. code-block:: python 15 | 16 | >>> import geocoder 17 | >>> g = geocoder.w3w('embedded.fizzled.trial') 18 | >>> g.json 19 | ... 20 | 21 | Reverse Geocoding 22 | ~~~~~~~~~~~~~~~~~ 23 | 24 | .. code-block:: python 25 | 26 | >>> import geocoder 27 | >>> g = geocoder.w3w([45.15, -75.14], method='reverse') 28 | >>> g.json 29 | ... 30 | 31 | Command Line Interface 32 | ---------------------- 33 | 34 | .. code-block:: bash 35 | 36 | $ geocode 'embedded.fizzled.trial' --provider w3w 37 | $ geocode '45.15, -75.14' --provider w3w --method reverse 38 | 39 | Environment Variables 40 | --------------------- 41 | 42 | For safe storage of your API key on your computer, you can define that API key using your system's environment variables. 43 | 44 | .. code-block:: bash 45 | 46 | $ export W3W_API_KEY= 47 | 48 | Parameters 49 | ---------- 50 | 51 | - `location`: Your search location you want geocoded. 52 | - `key`: use your own API Key from What3Words. 53 | - `method`: (default=geocode) Use the following: 54 | 55 | - geocode 56 | - reverse 57 | 58 | References 59 | ---------- 60 | 61 | - `API Reference `_ 62 | - `Get W3W key `_ 63 | -------------------------------------------------------------------------------- /docs/providers/Baidu.rst: -------------------------------------------------------------------------------- 1 | Baidu 2 | ===== 3 | 4 | Baidu Maps Geocoding API is a free open the API, the default quota 5 | one million times / day. 6 | 7 | Geocoding 8 | ~~~~~~~~~ 9 | 10 | .. code-block:: python 11 | 12 | >>> import geocoder # pip install geocoder 13 | >>> g = geocoder.baidu('中国', key='') 14 | >>> g.json 15 | ... 16 | 17 | 18 | Reverse Geocoding 19 | ~~~~~~~~~~~~~~~~~ 20 | 21 | .. code-block:: python 22 | 23 | >>> import geocoder 24 | >>> latlng = [45.3, -105.1] 25 | >>> g = geocoder.baidu(latlng, method='reverse', key='') 26 | >>> g.json 27 | ... 28 | 29 | 30 | Command Line Interface 31 | ---------------------- 32 | 33 | .. code-block:: bash 34 | 35 | $ geocode '中国' --provider baidu 36 | 37 | Environment Variables 38 | --------------------- 39 | 40 | To make sure your API key is store safely on your computer, you can define that API key using your system's environment variables. 41 | 42 | .. code-block:: bash 43 | 44 | $ export BAIDU_API_KEY= 45 | $ export BAIDU_SECURITY_KEY= 46 | 47 | Parameters 48 | ---------- 49 | 50 | - `location`: Your search location you want geocoded. 51 | - `key`: Baidu API key. 52 | - `sk`: Baidu API security key. Use with key. For Baidu developers. 53 | - `method`: (default=geocode) Use the following: 54 | 55 | - geocode 56 | - reverse 57 | 58 | References 59 | ---------- 60 | 61 | - `API Reference `_ 62 | - `Get Baidu key `_ 63 | - `Signature algorithm `_ 64 | -------------------------------------------------------------------------------- /tests/results/mapquest_batch.json: -------------------------------------------------------------------------------- 1 | {"info":{"statuscode":0,"copyright":{"text":"\u00A9 2018 MapQuest, Inc.","imageUrl":"http://api.mqcdn.com/res/mqlogo.gif","imageAltText":"\u00A9 2018 MapQuest, Inc."},"messages":[]},"options":{"maxResults":1,"thumbMaps":true,"ignoreLatLngInput":false},"results":[{"providedLocation":{"location":"Denver,CO"},"locations":[{"street":"","adminArea6":"","adminArea6Type":"Neighborhood","adminArea5":"Denver","adminArea5Type":"City","adminArea4":"Denver County","adminArea4Type":"County","adminArea3":"CO","adminArea3Type":"State","adminArea1":"US","adminArea1Type":"Country","postalCode":"","geocodeQualityCode":"A5XAX","geocodeQuality":"CITY","dragPoint":false,"sideOfStreet":"N","linkId":"282041090","unknownInput":"","type":"s","latLng":{"lat":39.738453,"lng":-104.984853},"displayLatLng":{"lat":39.738453,"lng":-104.984853},"mapUrl":"http://www.mapquestapi.com/staticmap/v5/map?key=apikey&type=map&size=225,160&locations=39.738453,-104.984853|marker-sm-50318A-1&scalebar=true&zoom=12&rand=524174944"}]},{"providedLocation":{"location":"Boulder,CO"},"locations":[{"street":"","adminArea6":"","adminArea6Type":"Neighborhood","adminArea5":"Boulder","adminArea5Type":"City","adminArea4":"Boulder County","adminArea4Type":"County","adminArea3":"CO","adminArea3Type":"State","adminArea1":"US","adminArea1Type":"Country","postalCode":"","geocodeQualityCode":"A5XAX","geocodeQuality":"CITY","dragPoint":false,"sideOfStreet":"N","linkId":"282039983","unknownInput":"","type":"s","latLng":{"lat":40.015831,"lng":-105.27927},"displayLatLng":{"lat":40.015831,"lng":-105.27927},"mapUrl":"http://www.mapquestapi.com/staticmap/v5/map?key=apikey&type=map&size=225,160&locations=40.015831,-105.27927|marker-sm-50318A-1&scalebar=true&zoom=12&rand=1140112238"}]}]} -------------------------------------------------------------------------------- /geocoder/mapquest_batch.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # coding: utf8 3 | 4 | from __future__ import absolute_import 5 | from geocoder.base import MultipleResultsQuery 6 | from geocoder.mapquest import MapquestResult 7 | from geocoder.keys import mapquest_key 8 | 9 | 10 | class MapQuestBatchResult(MapquestResult): 11 | 12 | @property 13 | def ok(self): 14 | return bool(self.quality) 15 | 16 | 17 | class MapquestBatch(MultipleResultsQuery): 18 | """ 19 | MapQuest 20 | ======== 21 | The geocoding service enables you to take an address and get the 22 | associated latitude and longitude. You can also use any latitude 23 | and longitude pair and get the associated address. Three types of 24 | geocoding are offered: address, reverse, and batch. 25 | 26 | API Reference 27 | ------------- 28 | http://www.mapquestapi.com/geocoding/ 29 | 30 | """ 31 | provider = 'mapquest' 32 | method = 'batch' 33 | 34 | _RESULT_CLASS = MapQuestBatchResult 35 | _URL = 'http://www.mapquestapi.com/geocoding/v1/batch' 36 | _TIMEOUT = 30 37 | _KEY = mapquest_key 38 | 39 | def _build_params(self, location, provider_key, **kwargs): 40 | self._TIMEOUT = kwargs.get('timeout', 30) 41 | 42 | return { 43 | 'key': provider_key, 44 | 'location': location, 45 | 'maxResults': 1, 46 | 'outFormat': 'json', 47 | } 48 | 49 | def _adapt_results(self, json_response): 50 | results = json_response.get('results', []) 51 | if results: 52 | return [result['locations'][0] for result in results] 53 | 54 | return [] 55 | 56 | 57 | if __name__ == '__main__': 58 | g = MapquestBatch(['Denver,CO', 'Boulder,CO']) 59 | g.debug() 60 | -------------------------------------------------------------------------------- /docs/features/GeoJSON.md: -------------------------------------------------------------------------------- 1 | # GeoJSON Support 2 | 3 | GeoJSON is a format for encoding a variety of geographic data structures. A complete GeoJSON data structure is always an object (in JSON terms). In GeoJSON, an object consists of a collection of name/value pairs -- also called members. For each member, the name is always a string. Member values are either a string, number, object, array or one of the literals: true, false, and null. 4 | 5 | [GeoJSON Specification](http://geojson.org/geojson-spec.html) 6 | 7 | ## Python Example 8 | 9 | ```python 10 | >>> import geocoder 11 | >>> g = geocoder.google("New York City") 12 | >>> g.geojson 13 | ... 14 | ``` 15 | 16 | ## GeoJSON Output 17 | 18 | The difference between the GeoJSON and JSON response is the `geometry` attribute is in accordance with GeoJSON specification; All attributes are nested in the `properties` attribute and the `bbox` (bounding box) is formatted to the GeoJSON spec. 19 | 20 | ```json 21 | { 22 | "geometry": { 23 | "type": "Point", 24 | "coordinates": [ 25 | -74.0059413, 26 | 40.7127837 27 | ] 28 | }, 29 | "type": "Feature", 30 | "properties": { 31 | "status": "OK", 32 | "city": "New York", 33 | "confidence": 1, 34 | "ok": true, 35 | "country": "United States", 36 | "provider": "google", 37 | "location": "New York City", 38 | "state": "New York", 39 | "address": "New York, NY, USA", 40 | "lat": 40.7127837, 41 | "lng": -74.0059413, 42 | "quality": "locality", 43 | "accuracy": "APPROXIMATE" 44 | }, 45 | "bbox": [ 46 | -74.25908989999999, 47 | 40.4913686, 48 | -73.70027209999999, 49 | 40.91525559999999 50 | ] 51 | } 52 | ``` 53 | -------------------------------------------------------------------------------- /tests/test_mapquest.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # coding: utf8 3 | import requests_mock 4 | import geocoder 5 | 6 | location = 'Ottawa' 7 | city = 'Ottawa' 8 | ottawa = (45.50, -76.05) 9 | locations = ['Denver,CO', 'Boulder,CO'] 10 | 11 | winnetka = 'Winnetka' 12 | winnetka_bbox = [-118.604794,34.172684,-118.500938,34.236144] 13 | 14 | 15 | def test_mapquest(): 16 | g = geocoder.mapquest(location, timeout=10) 17 | assert g.ok 18 | osm_count, fields_count = g.debug()[0] 19 | assert osm_count >= 3 20 | assert fields_count >= 10 21 | 22 | 23 | def test_mapquest_with_bbox(): 24 | g = geocoder.mapquest(winnetka, bbox=winnetka_bbox) 25 | assert g.ok 26 | osm_count, fields_count = g.debug()[0] 27 | assert osm_count >= 2 28 | assert fields_count >= 11 29 | 30 | for result in g: 31 | assert (result.lng >= winnetka_bbox[0]) and (result.lng <= winnetka_bbox[2]) 32 | assert (result.lat >= winnetka_bbox[1]) and (result.lat <= winnetka_bbox[3]) 33 | 34 | def test_mapquest_reverse(): 35 | g = geocoder.mapquest(ottawa, method='reverse', timeout=10) 36 | assert g.ok 37 | 38 | def test_mapquest_batch(): 39 | url = 'http://www.mapquestapi.com/geocoding/v1/batch' 40 | data_file = 'tests/results/mapquest_batch.json' 41 | with requests_mock.Mocker() as mocker, open(data_file, 'r') as input: 42 | mocker.get(url, text=input.read()) 43 | g = geocoder.mapquest(locations, method='batch', timeout=10) 44 | assert g.ok 45 | expected_results = [ 46 | [39.738453, -104.984853], 47 | [40.015831, -105.27927] 48 | ] 49 | 50 | assert [result.latlng for result in g] == expected_results 51 | 52 | 53 | def test_multi_results(): 54 | g = geocoder.mapquest(location, maxRows=3, timeout=10) 55 | assert len(g) == 3 56 | -------------------------------------------------------------------------------- /tests/results/geonames.geo.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "FeatureCollection", 3 | "features": [ 4 | { 5 | "type": "Feature", 6 | "properties": { 7 | "address": "Ottawa", 8 | "class_description": "city, village,...", 9 | "code": "PPLC", 10 | "country": "Canada", 11 | "country_code": "CA", 12 | "description": "capital of a political entity", 13 | "feature_class": "P", 14 | "geonames_id": 6094817, 15 | "lat": "45.41117", 16 | "lng": "-75.69812", 17 | "ok": true, 18 | "population": 812129, 19 | "raw": { 20 | "adminCode1": "08", 21 | "lng": "-75.69812", 22 | "geonameId": 6094817, 23 | "toponymName": "Ottawa", 24 | "countryId": "6251999", 25 | "fcl": "P", 26 | "population": 812129, 27 | "countryCode": "CA", 28 | "name": "Ottawa", 29 | "fclName": "city, village,...", 30 | "countryName": "Canada", 31 | "fcodeName": "capital of a political entity", 32 | "adminName1": "Ontario", 33 | "lat": "45.41117", 34 | "fcode": "PPLC" 35 | }, 36 | "state": "Ontario", 37 | "state_code": "08", 38 | "status": "OK" 39 | }, 40 | "geometry": { 41 | "type": "Point", 42 | "coordinates": [ 43 | "-75.69812", 44 | "45.41117" 45 | ] 46 | } 47 | } 48 | ] 49 | } -------------------------------------------------------------------------------- /docs/examples/using iPython.md: -------------------------------------------------------------------------------- 1 | # Using iPython 2 | 3 | ```bash 4 | $ pip install ipython 5 | $ ipython 6 | ``` 7 | 8 | Using the **TAB** key after entering '.' you will see all the available **providers**. 9 | 10 | ```python 11 | >>> import geocoder 12 | >>> g = geocoder. 13 | geocoder.api geocoder.geolytica geocoder.mapquest 14 | geocoder.arcgis geocoder.geonames geocoder.nokia 15 | geocoder.base geocoder.get geocoder.osm 16 | geocoder.bing geocoder.google geocoder.timezone 17 | geocoder.canadapost geocoder.ip geocoder.yahoo 18 | geocoder.cli geocoder.keys geocoder.tomtom 19 | geocoder.elevation geocoder.location geocoder.places 20 | ... 21 | ``` 22 | 23 | Using the **TAB** key again, you can see all the available **attributes**. 24 | 25 | ```python 26 | >>> g = geocoder.google('Ottawa') 27 | >>> g. 28 | g.accuracy g.latlng g.south 29 | g.address g.lng g.southeast 30 | g.api g.locality g.southwest 31 | g.attributes g.location g.state 32 | g.bbox g.neighborhood g.status 33 | g.content g.north g.status_code 34 | g.country g.northeast g.status_description 35 | g.county g.northwest g.street_number 36 | g.debug g.ok g.sublocality 37 | g.east g.params g.subpremise 38 | g.error g.parse g.url 39 | g.geometry g.postal g.west 40 | g.headers g.provider g.wkt 41 | g.help g.quality g.x 42 | g.json g.route g.y 43 | g.lat g.short_name 44 | ... 45 | ``` -------------------------------------------------------------------------------- /docs/providers/CanadaPost.rst: -------------------------------------------------------------------------------- 1 | CanadaPost 2 | ========== 3 | 4 | The next generation of address finders, AddressComplete uses intelligent, fast 5 | searching to improve data accuracy and relevancy. Simply start typing a business 6 | name, address or Postal Code and AddressComplete will suggest results as you go. 7 | Using Geocoder you can retrieve CanadaPost's geocoded data from Addres Complete API. 8 | 9 | Geocoding (Postal Code) 10 | ~~~~~~~~~~~~~~~~~~~~~~~ 11 | 12 | .. code-block:: python 13 | 14 | >>> import geocoder 15 | >>> g = geocoder.canadapost('453 Booth Street, Ottawa', key='') 16 | >>> g.postal 17 | 'K1R 7K9' 18 | >>> g.json 19 | ... 20 | 21 | This provider may return multiple results by setting the parameter `maxRows` to the desired number (1 by default). You can access those results as described in the page ':doc:`/results`'. 22 | 23 | Command Line Interface 24 | ---------------------- 25 | 26 | .. code-block:: bash 27 | 28 | $ geocode '453 Booth Street, Ottawa' --provider canadapost | jq .postal 29 | 30 | Environment Variables 31 | --------------------- 32 | 33 | To make sure your API key is store safely on your computer, you can define that API key using your system's environment variables. 34 | 35 | .. code-block:: bash 36 | 37 | $ export CANADAPOST_API_KEY= 38 | 39 | Parameters 40 | ---------- 41 | 42 | - `location`: Your search location you want geocoded. 43 | - `key`: (optional) API Key from CanadaPost Address Complete. 44 | - `language`: (default=en) Output language preference. 45 | - `country`: (default=ca) Geofenced query by country. 46 | - `maxRows`: (default=1) Max number of results to fetch 47 | - `method`: (default=geocode) Use the following: 48 | 49 | - geocode 50 | 51 | References 52 | ---------- 53 | 54 | - `Addres Complete API `_ 55 | -------------------------------------------------------------------------------- /tests/test_uscensus.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # coding: utf8 3 | 4 | import geocoder 5 | import requests_mock 6 | 7 | us_address = '595 Market St' 8 | us_city = 'San Francisco' 9 | us_state = 'CA' 10 | us_zipcode = '94105' 11 | us_locations = ['4650 Silver Hill Road, Suitland, MD 20746', '42 Chapel Street, New Haven'] 12 | 13 | def test_uscensus(): 14 | url = 'https://geocoding.geo.census.gov/geocoder/locations/onelineaddress?address=595+Market+St+San+Francisco+CA+94105&benchmark=4&format=json' 15 | data_file = 'tests/results/uscensus.json' 16 | with requests_mock.Mocker() as mocker, open(data_file, 'r') as input: 17 | mocker.get(url, text=input.read()) 18 | g = geocoder.uscensus(' '.join([us_address, us_city, us_state, us_zipcode]), timeout=10) 19 | assert g.ok 20 | 21 | 22 | def test_uscensus_reverse(): 23 | url = 'https://geocoding.geo.census.gov/geocoder/geographies/coordinates?x=-77.016389&y=38.904722&benchmark=4&vintage=4&format=json' 24 | data_file = 'tests/results/uscensus_reverse.json' 25 | with requests_mock.Mocker() as mocker, open(data_file, 'r') as input: 26 | mocker.get(url, text=input.read()) 27 | g = geocoder.uscensus((38.904722, -77.016389), method='reverse', timeout=10) 28 | assert g.ok 29 | 30 | 31 | def test_uscensus_reverse(): 32 | url = 'https://geocoding.geo.census.gov/geocoder/locations/addressbatch' 33 | data_file = 'tests/results/uscensus_batch.csv' 34 | with requests_mock.Mocker() as mocker, open(data_file, 'r') as input: 35 | mocker.post(url, text=input.read()) 36 | g = geocoder.uscensus(us_locations, benchmark=9, method='batch') 37 | assert g.ok 38 | expected_results = [ 39 | [38.846638, -76.92681], 40 | [41.30435, -72.89422] 41 | ] 42 | 43 | assert [result.latlng for result in g] == expected_results 44 | -------------------------------------------------------------------------------- /tests/results/google.json: -------------------------------------------------------------------------------- 1 | { 2 | "results": [ 3 | { 4 | "address_components": [ 5 | { 6 | "long_name": "Ottawa", 7 | "short_name": "Ottawa", 8 | "types": [ 9 | "locality", 10 | "political" 11 | ] 12 | }, 13 | { 14 | "long_name": "Ottawa Division", 15 | "short_name": "Ottawa Division", 16 | "types": [ 17 | "administrative_area_level_2", 18 | "political" 19 | ] 20 | }, 21 | { 22 | "long_name": "Ontario", 23 | "short_name": "ON", 24 | "types": [ 25 | "administrative_area_level_1", 26 | "political" 27 | ] 28 | }, 29 | { 30 | "long_name": "Canada", 31 | "short_name": "CA", 32 | "types": [ 33 | "country", 34 | "political" 35 | ] 36 | } 37 | ], 38 | "formatted_address": "Ottawa, ON, Canada", 39 | "geometry": { 40 | "bounds": { 41 | "northeast": { 42 | "lat": 45.5375801, 43 | "lng": -75.2465979 44 | }, 45 | "southwest": { 46 | "lat": 44.962733, 47 | "lng": -76.3539158 48 | } 49 | }, 50 | "location": { 51 | "lat": 45.4215296, 52 | "lng": -75.69719309999999 53 | }, 54 | "location_type": "APPROXIMATE", 55 | "viewport": { 56 | "northeast": { 57 | "lat": 45.5375801, 58 | "lng": -75.2465979 59 | }, 60 | "southwest": { 61 | "lat": 44.962733, 62 | "lng": -76.3539158 63 | } 64 | } 65 | }, 66 | "place_id": "ChIJrxNRX7IFzkwR7RXdMeFRaoo", 67 | "types": [ 68 | "locality", 69 | "political" 70 | ] 71 | } 72 | ], 73 | "status": "OK" 74 | } -------------------------------------------------------------------------------- /docs/providers/LocationIQ.rst: -------------------------------------------------------------------------------- 1 | LocationIQ 2 | =========== 3 | 4 | `LocationIQ`_ provides geocoding based on OpenStreetMap's `Nominatim`_. It is fully compatible 5 | with OSM except for the requirement of an API Key. Please refer to the :doc:`./OpenStreetMap` docs 6 | for more details. You can signup for a free API Key `here `. 7 | 8 | Geocoding 9 | ~~~~~~~~~ 10 | 11 | .. code-block:: python 12 | 13 | >>> import geocoder 14 | >>> g = geocoder.locationiq('New York city', key='...') 15 | >>> g.json 16 | ... 17 | 18 | This provider may return multiple results by setting the parameter `maxRows` to the desired number (1 by default). You can access those results as described in the page ':doc:`/results`'. 19 | 20 | Reverse Geocoding 21 | ~~~~~~~~~~~~~~~~~~ 22 | 23 | .. code-block:: python 24 | 25 | >>> import geocoder 26 | >>> g = geocoder.locationiq([45.15, -75.14], key='...', method='reverse') 27 | >>> g.json 28 | ... 29 | 30 | Environment Variables 31 | --------------------- 32 | 33 | To make sure your API key is store safely on your computer, you can define that API key using your system's environment variables. 34 | 35 | .. code-block:: bash 36 | 37 | $ export LOCATIONIQ_API_KEY= 38 | 39 | Command Line Interface 40 | ---------------------- 41 | 42 | .. code-block:: bash 43 | 44 | $ geocode 'New York city' --provider locationiq --key --output geojson | jq . 45 | $ geocode 'New York City' --provider locationiq --key --output osm 46 | 47 | Parameters 48 | ---------- 49 | 50 | - `location`: Your search location you want geocoded. 51 | - `url`: Custom OSM Server (ex: localhost) 52 | - `maxRows`: (default=1) Max number of results to fetch 53 | - `limit`: *Deprecated*, same as maxRows 54 | - `method`: (default=geocode) Use the following: 55 | 56 | - geocode 57 | 58 | References 59 | ---------- 60 | 61 | - `LocationIQ `_ 62 | - `Nominatim `_ 63 | -------------------------------------------------------------------------------- /docs/features/Caching.md: -------------------------------------------------------------------------------- 1 | ## Caching 2 | 3 | Caching feature in the Geocoder. 4 | 5 | The CLI would look something like this: 6 | 7 | **Simple Case** 8 | 9 | ```bash 10 | $ geocode "Ottawa ON" --cache 11 | ``` 12 | 13 | ```python 14 | >>> import geocoder 15 | >>> g = geocoder.google("Ottawa ON", cache="") 16 | >>> g.json 17 | {...} 18 | ``` 19 | 20 | **Batch geocode** 21 | 22 | ```bash 23 | # Linux 24 | $ cat "foo.txt" | geocode --cache 25 | ``` 26 | 27 | ```bash 28 | # Windows 29 | C:\> type "foo.txt" | geocode --cache 30 | ``` 31 | 32 | 33 | **Extra parameters** 34 | 35 | ```bash 36 | $ geocode "Ottawa ON" --cache "" \ 37 | --username "" \ 38 | --password "" \ 39 | --host "" \ 40 | --port 28015 41 | ``` 42 | 43 | ```python 44 | >>> g = geocoder.google("Ottawa ON", 45 | cache="", 46 | username="", 47 | password="", 48 | host="", 49 | port=28015) 50 | ``` 51 | 52 | ### Parameters 53 | 54 | |Params |Description |Default | 55 | |:--------|:-----------------|:------------------| 56 | |db |SQLAlchemy DB |sqlite:///:memory: | 57 | |location |Query Location | | 58 | |provider |Geocoder Provider |bing | 59 | |method |Geocoder Method |geocode | 60 | |output |json/geojson/osm |json | 61 | 62 | ### Using Cache.py 63 | 64 | ```python 65 | # User Variables 66 | location = 'Orleans, Ottawa' 67 | 68 | # Geocode Address 69 | g = geocoder.bing(location) 70 | 71 | # Create Cache Databse 72 | cache = Cache('sqlite:///:memory:') 73 | 74 | # Insert into Database 75 | values = { 76 | 'location': location, 77 | 'provider': 'bing', 78 | 'lat': 45.34, 79 | 'lng': -75.123 80 | } 81 | cache.insert(values) 82 | 83 | # Find results with a Query 84 | print(cache.find(location)) 85 | ``` 86 | -------------------------------------------------------------------------------- /docs/providers/OpenCage.rst: -------------------------------------------------------------------------------- 1 | Opencage 2 | ======== 3 | 4 | OpenCage Geocoder simple, easy, and open geocoding for the entire world 5 | Our API combines multiple geocoding systems in the background. 6 | Each is optimized for different parts of the world and types of requests.We aggregate the best results from open data sources and algorithms so you don't have to. 7 | Each is optimized for different parts of the world and types of requests. 8 | Using Geocoder you can retrieve OpenCage's geocoded data from OpenCage Geocoding Services. 9 | 10 | Geocoding 11 | ~~~~~~~~~ 12 | 13 | .. code-block:: python 14 | 15 | >>> import geocoder 16 | >>> g = geocoder.opencage('San Francisco, CA', key='') 17 | >>> g.json 18 | ... 19 | 20 | This provider may return multiple results by setting the parameter `maxRows` to the desired number (1 by default). You can access those results as described in the page ':doc:`/results`'. 21 | 22 | Reverse Geocoding 23 | ~~~~~~~~~~~~~~~~~ 24 | 25 | .. code-block:: python 26 | 27 | >>> import geocoder 28 | >>> g = geocoder.opencage([45.15, -75.14], method='reverse') 29 | >>> g.json 30 | ... 31 | 32 | Command Line Interface 33 | ---------------------- 34 | 35 | .. code-block:: bash 36 | 37 | $ geocode 'San Francisco, CA' --provider opencage --out geojson --key '' | jq . 38 | 39 | Environment Variables 40 | --------------------- 41 | 42 | To make sure your API key is store safely on your computer, you can define that API key using your system's environment variables. 43 | 44 | .. code-block:: bash 45 | 46 | $ export OPENCAGE_API_KEY= 47 | 48 | Parameters 49 | ---------- 50 | 51 | - `location`: Your search location you want geocoded. 52 | - `key`: (optional) use your own API Key from OpenCage. 53 | - `maxRows`: (default=1) Max number of results to fetch 54 | - `method`: (default=geocode) Use the following: 55 | 56 | - geocode 57 | 58 | References 59 | ---------- 60 | 61 | - `OpenCage Geocoding Services `_ 62 | 63 | -------------------------------------------------------------------------------- /docs/_themes/LICENSE: -------------------------------------------------------------------------------- 1 | Modifications: 2 | 3 | Copyright (c) 2010 Kenneth Reitz. 4 | 5 | 6 | Original Project: 7 | 8 | Copyright (c) 2010 by Armin Ronacher. 9 | 10 | 11 | Some rights reserved. 12 | 13 | Redistribution and use in source and binary forms of the theme, with or 14 | without modification, are permitted provided that the following conditions 15 | are met: 16 | 17 | * Redistributions of source code must retain the above copyright 18 | notice, this list of conditions and the following disclaimer. 19 | 20 | * Redistributions in binary form must reproduce the above 21 | copyright notice, this list of conditions and the following 22 | disclaimer in the documentation and/or other materials provided 23 | with the distribution. 24 | 25 | * The names of the contributors may not be used to endorse or 26 | promote products derived from this software without specific 27 | prior written permission. 28 | 29 | We kindly ask you to only use these themes in an unmodified manner just 30 | for Flask and Flask-related products, not for unrelated projects. If you 31 | like the visual style and want to use it for your own projects, please 32 | consider making some larger changes to the themes (such as changing 33 | font faces, sizes, colors or margins). 34 | 35 | THIS THEME IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 36 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 37 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 38 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 39 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 40 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 41 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 42 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 43 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 44 | ARISING IN ANY WAY OUT OF THE USE OF THIS THEME, EVEN IF ADVISED OF THE 45 | POSSIBILITY OF SUCH DAMAGE. 46 | -------------------------------------------------------------------------------- /docs/providers/Yandex.rst: -------------------------------------------------------------------------------- 1 | Yandex 2 | ====== 3 | 4 | Yandex (Russian: Яндекс) is a Russian Internet company which operates the 5 | largest search engine in Russia with about 60% market share in that country. 6 | 7 | The Yandex home page has been rated as the most popular website in Russia. 8 | 9 | Geocoding 10 | ~~~~~~~~~ 11 | 12 | .. code-block:: python 13 | 14 | >>> import geocoder 15 | >>> g = geocoder.yandex('Moscow Russia') 16 | >>> g.json 17 | ... 18 | 19 | This provider may return multiple results by setting the parameter `maxRows` to the desired number (1 by default). You can access those results as described in the page ':doc:`/results`'. 20 | 21 | Reverse Geocoding 22 | ~~~~~~~~~~~~~~~~~ 23 | 24 | .. code-block:: python 25 | 26 | >>> import geocoder 27 | >>> g = geocoder.yandex([55.95, 37.96], method='reverse') 28 | >>> g.json 29 | ... 30 | 31 | Command Line Interface 32 | ---------------------- 33 | 34 | .. code-block:: bash 35 | 36 | $ geocode 'Moscow Russia' --provider yandex --out geojson 37 | $ geocode '55.95, 37.96' --provider yandex --method reverse 38 | 39 | Parameters 40 | ---------- 41 | 42 | - `location`: Your search location you want geocoded. 43 | - `maxRows`: (default=1) Max number of results to fetch 44 | - `lang`: Chose the following language: 45 | 46 | - **ru-RU** — Russian (by default) 47 | - **uk-UA** — Ukrainian 48 | - **be-BY** — Belarusian 49 | - **en-US** — American English 50 | - **en-BR** — British English 51 | - **tr-TR** — Turkish (only for maps of Turkey) 52 | 53 | - `kind`: Type of toponym (only for reverse geocoding): 54 | 55 | - **house** — house or building 56 | - **street** — street 57 | - **metro** — subway station 58 | - **district** — city district 59 | - **locality** — locality (city, town, village, etc.) 60 | 61 | - `method`: (default=geocode) Use the following: 62 | 63 | - geocode 64 | - reverse 65 | 66 | References 67 | ---------- 68 | 69 | - `Yandex API Reference `_ 70 | -------------------------------------------------------------------------------- /geocoder/google_timezone.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # coding: utf8 3 | 4 | from __future__ import absolute_import 5 | import time 6 | from geocoder.base import OneResult, MultipleResultsQuery 7 | from geocoder.keys import google_key 8 | from geocoder.location import Location 9 | 10 | 11 | class TimezoneResult(OneResult): 12 | 13 | def __repr__(self): 14 | return u'<[{}] [{}]>'.format(self.status, self.timeZoneName) 15 | 16 | @property 17 | def ok(self): 18 | return bool(self.timeZoneName) 19 | 20 | @property 21 | def timeZoneId(self): 22 | return self.raw.get('timeZoneId') 23 | 24 | @property 25 | def timeZoneName(self): 26 | return self.raw.get('timeZoneName') 27 | 28 | @property 29 | def rawOffset(self): 30 | return self.raw.get('rawOffset') 31 | 32 | @property 33 | def dstOffset(self): 34 | return self.raw.get('dstOffset') 35 | 36 | 37 | class TimezoneQuery(MultipleResultsQuery): 38 | """ 39 | Google Time Zone API 40 | ==================== 41 | The Time Zone API provides time offset data for locations on the surface of the earth. 42 | Requesting the time zone information for a specific Latitude/Longitude pair will 43 | return the name of that time zone, the time offset from UTC, and the Daylight Savings offset. 44 | 45 | API Reference 46 | ------------- 47 | https://developers.google.com/maps/documentation/timezone/ 48 | """ 49 | provider = 'google' 50 | method = 'timezone' 51 | 52 | _URL = 'https://maps.googleapis.com/maps/api/timezone/json' 53 | _RESULT_CLASS = TimezoneResult 54 | _KEY = google_key 55 | 56 | def _build_params(self, location, provider_key, **kwargs): 57 | return { 58 | 'location': str(Location(location)), 59 | 'timestamp': kwargs.get('timestamp', time.time()), 60 | } 61 | 62 | def _adapt_results(self, json_response): 63 | return [json_response] 64 | 65 | 66 | if __name__ == '__main__': 67 | g = TimezoneQuery([45.5375801, -75.2465979]) 68 | g.debug() 69 | -------------------------------------------------------------------------------- /geocoder/w3w.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # coding: utf8 3 | from __future__ import absolute_import 4 | 5 | import logging 6 | 7 | from geocoder.base import OneResult, MultipleResultsQuery 8 | from geocoder.keys import w3w_key 9 | 10 | 11 | class W3WResult(OneResult): 12 | 13 | @property 14 | def lat(self): 15 | position = self.raw.get('geometry') 16 | if position: 17 | return position['lat'] 18 | 19 | @property 20 | def lng(self): 21 | position = self.raw.get('geometry') 22 | if position: 23 | return position['lng'] 24 | 25 | @property 26 | def language(self): 27 | return self.raw.get('language') 28 | 29 | @property 30 | def words(self): 31 | return self.raw.get('words') 32 | 33 | 34 | class W3WQuery(MultipleResultsQuery): 35 | """ 36 | What3Words 37 | ========== 38 | What3Words is a global grid of 57 trillion 3mx3m squares. 39 | Each square has a 3 word address that can be communicated quickly, 40 | easily and with no ambiguity. 41 | 42 | Addressing the world 43 | 44 | Everyone and everywhere now has an address 45 | 46 | Params 47 | ------ 48 | :param location: Your search location you want geocoded. 49 | :param key: W3W API key. 50 | :param method: Chose a method (geocode, method) 51 | 52 | References 53 | ---------- 54 | API Reference: https://docs.what3words.com/api/v2/ 55 | Get W3W key: https://map.what3words.com/register?dev=true 56 | """ 57 | provider = 'w3w' 58 | method = 'geocode' 59 | 60 | _URL = 'https://api.what3words.com/v2/forward' 61 | _RESULT_CLASS = W3WResult 62 | _KEY = w3w_key 63 | 64 | def _build_params(self, location, provider_key, **kwargs): 65 | return { 66 | 'addr': location, 67 | 'key': provider_key, 68 | } 69 | 70 | def _adapt_results(self, json_response): 71 | return [json_response] 72 | 73 | if __name__ == '__main__': 74 | logging.basicConfig(level=logging.INFO) 75 | g = W3WQuery('embedded.fizzled.trial') 76 | g.debug() 77 | -------------------------------------------------------------------------------- /tests/test_locations.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from geocoder.location import BBox 4 | 5 | 6 | class TestBBox(object): 7 | 8 | def test_factory_bounds_dict(self): 9 | bbox = BBox.factory({'southwest': [43.0, -80.5], 'northeast': ["43.6", "-80.0"]}) 10 | assert bbox.latlng == [43.3, -80.25] 11 | 12 | def test_factory_bbox_dict(self): 13 | bbox = BBox.factory({'bbox': [-80.5, "43.0", "-80.0", 43.6]}) 14 | assert bbox.latlng == [43.3, -80.25] 15 | 16 | def test_factory_latlng_dict(self): 17 | bbox = BBox.factory({'lat': 43.0, 'lng': "-80.0"}) 18 | assert BBox.DEGREES_TOLERANCE == 0.5 19 | assert bbox.south == 42.5 20 | assert bbox.north == 43.5 21 | assert bbox.west == -80.5 22 | assert bbox.east == -79.5 23 | assert bbox.latlng == [43.0, -80.0] 24 | 25 | def test_factory_coordinates_dict(self): 26 | bbox = BBox.factory({'south': "43.0", 'west': -80.5, 'north': "43.6", 'east': -80.0}) 27 | assert bbox.latlng == [43.3, -80.25] 28 | 29 | def test_factory_error_dict(self): 30 | with pytest.raises(ValueError): 31 | BBox.factory({'dummy': 43.0}) 32 | 33 | def test_factory_bounds_list(self): 34 | bbox = BBox.factory([-80.5, "43.0", "-80.0", 43.6]) 35 | assert bbox.latlng == [43.3, -80.25] 36 | 37 | def test_factory_latlng_list(self): 38 | bbox = BBox.factory(["-80.0", "43.0"]) 39 | assert bbox.latlng == [-80.0, 43.0] 40 | 41 | def test_factory_error_list(self): 42 | with pytest.raises(ValueError): 43 | BBox.factory([1, 2, 3]) 44 | 45 | def test_side_attributes(self): 46 | bbox = BBox.factory([-80.0, 43.0]) 47 | assert bbox.lat == -80.0 48 | assert bbox.lng == 43.0 49 | assert bbox.latitude == -80.0 50 | assert bbox.longitude == 43.0 51 | assert bbox.latlng == [-80.0, 43.0] 52 | assert bbox.xy == [43.0, -80.0] 53 | 54 | def test_dict_output(self): 55 | bbox = BBox.factory({'bbox': [-80.5, 43.0, -80.0, 43.6]}) 56 | assert bbox.as_dict == { 57 | 'northeast': [43.6, -80.0], 58 | 'southwest': [43.0, -80.5] 59 | } 60 | -------------------------------------------------------------------------------- /tests/results/geonames_hierarchy.json: -------------------------------------------------------------------------------- 1 | { 2 | "geonames": [ 3 | { 4 | "lng": "0", 5 | "geonameId": 6295630, 6 | "name": "Earth", 7 | "fclName": "parks,area, ...", 8 | "toponymName": "Earth", 9 | "fcodeName": "area", 10 | "adminName1": "", 11 | "lat": "0", 12 | "fcl": "L", 13 | "fcode": "AREA", 14 | "population": 6814400000 15 | }, 16 | { 17 | "lng": "-100.54688", 18 | "geonameId": 6255149, 19 | "name": "North America", 20 | "fclName": "parks,area, ...", 21 | "toponymName": "North America", 22 | "fcodeName": "continent", 23 | "adminName1": "", 24 | "lat": "46.07323", 25 | "fcl": "L", 26 | "fcode": "CONT", 27 | "population": 0 28 | }, 29 | { 30 | "adminCode1": "00", 31 | "lng": "-113.64258", 32 | "geonameId": 6251999, 33 | "toponymName": "Canada", 34 | "countryId": "6251999", 35 | "fcl": "A", 36 | "population": 33679000, 37 | "countryCode": "CA", 38 | "name": "Canada", 39 | "fclName": "country, state, region,...", 40 | "countryName": "Canada", 41 | "fcodeName": "independent political entity", 42 | "adminName1": "", 43 | "lat": "60.10867", 44 | "fcode": "PCLI" 45 | }, 46 | { 47 | "adminCode1": "08", 48 | "lng": "-84.49983", 49 | "geonameId": 6093943, 50 | "toponymName": "Ontario", 51 | "countryId": "6251999", 52 | "fcl": "A", 53 | "population": 12861940, 54 | "countryCode": "CA", 55 | "name": "Ontario", 56 | "fclName": "country, state, region,...", 57 | "countryName": "Canada", 58 | "fcodeName": "first-order administrative division", 59 | "adminName1": "Ontario", 60 | "lat": "49.25014", 61 | "fcode": "ADM1" 62 | }, 63 | { 64 | "adminCode1": "08", 65 | "lng": "-75.69812", 66 | "geonameId": 6094817, 67 | "toponymName": "Ottawa", 68 | "countryId": "6251999", 69 | "fcl": "P", 70 | "population": 812129, 71 | "countryCode": "CA", 72 | "name": "Ottawa", 73 | "fclName": "city, village,...", 74 | "countryName": "Canada", 75 | "fcodeName": "capital of a political entity", 76 | "adminName1": "Ontario", 77 | "lat": "45.41117", 78 | "fcode": "PPLC" 79 | } 80 | ] 81 | } -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # coding: utf8 3 | 4 | from codecs import open 5 | import re 6 | 7 | try: 8 | from setuptools import setup 9 | except ImportError: 10 | from distutils.core import setup 11 | 12 | with open('geocoder/__init__.py', 'r') as fd: 13 | version = re.search(r'^__version__\s*=\s*[\'"]([^\'"]*)[\'"]', 14 | fd.read(), re.MULTILINE).group(1) 15 | 16 | if not version: 17 | raise RuntimeError('Cannot find version information') 18 | 19 | with open('README.md', 'r', 'utf-8') as f: 20 | readme = f.read() 21 | 22 | requires = ['requests', 'ratelim', 'click', 'six', 'future'] 23 | 24 | setup( 25 | name='geocoder', 26 | version=version, 27 | description="Geocoder is a simple and consistent geocoding library.", 28 | long_description=readme, 29 | author='Denis Carriere', 30 | author_email='carriere.denis@gmail.com', 31 | url='https://github.com/DenisCarriere/geocoder', 32 | download_url='https://github.com/DenisCarriere/geocoder', 33 | license="The MIT License", 34 | entry_points=''' 35 | [console_scripts] 36 | geocode=geocoder.cli:cli 37 | ''', 38 | packages=['geocoder'], 39 | package_data={'': ['LICENSE', 'README.md']}, 40 | package_dir={'geocoder': 'geocoder'}, 41 | include_package_data=True, 42 | install_requires=requires, 43 | zip_safe=False, 44 | keywords='geocoder arcgis tomtom opencage google bing here', 45 | classifiers=[ 46 | 'Development Status :: 5 - Production/Stable', 47 | 'Intended Audience :: Developers', 48 | 'Intended Audience :: Science/Research', 49 | 'License :: OSI Approved :: Apache Software License', 50 | 'Natural Language :: English', 51 | 'Operating System :: OS Independent', 52 | 'Programming Language :: Python :: 2.7', 53 | 'Programming Language :: Python :: 3.3', 54 | 'Programming Language :: Python :: 3.4', 55 | 'Programming Language :: Python :: 3.5', 56 | 'Topic :: Internet', 57 | 'Topic :: Internet :: WWW/HTTP', 58 | 'Topic :: Scientific/Engineering :: GIS', 59 | 'Topic :: Software Development :: Libraries :: Python Modules', 60 | ], 61 | ) 62 | -------------------------------------------------------------------------------- /tests/results/geocodefarm.json: -------------------------------------------------------------------------------- 1 | { 2 | "geocoding_results": { 3 | "LEGAL_COPYRIGHT": { 4 | "copyright_notice": "Copyright (c) 2017 Geocode.Farm - All Rights Reserved.", 5 | "copyright_logo": "https:\/\/www.geocode.farm\/images\/logo.png", 6 | "terms_of_service": "https:\/\/www.geocode.farm\/policies\/terms-of-service\/", 7 | "privacy_policy": "https:\/\/www.geocode.farm\/policies\/privacy-policy\/" 8 | }, 9 | "STATUS": { 10 | "access": "FREE_USER, ACCESS_GRANTED", 11 | "status": "SUCCESS", 12 | "address_provided": "New York City", 13 | "result_count": 1 14 | }, 15 | "ACCOUNT": { 16 | "ip_address": "84.227.193.86", 17 | "distribution_license": "NONE, UNLICENSED", 18 | "usage_limit": "250", 19 | "used_today": "10", 20 | "used_total": "37", 21 | "first_used": "02 Sep 2017" 22 | }, 23 | "RESULTS": [ 24 | { 25 | "result_number": 1, 26 | "formatted_address": "New York, NY, USA", 27 | "accuracy": "UNKNOWN_ACCURACY", 28 | "ADDRESS": { 29 | "locality": "New York", 30 | "admin_1": "New York", 31 | "country": "United States" 32 | }, 33 | "LOCATION_DETAILS": { 34 | "elevation": "UNAVAILABLE", 35 | "timezone_long": "UNAVAILABLE", 36 | "timezone_short": "America\/New_York" 37 | }, 38 | "COORDINATES": { 39 | "latitude": "40.7127866703824", 40 | "longitude": "-74.0059412125133" 41 | }, 42 | "BOUNDARIES": { 43 | "northeast_latitude": "40.7127866703824", 44 | "northeast_longitude": "-74.0059412125133", 45 | "southwest_latitude": "40.4773966318170", 46 | "southwest_longitude": "-74.2590812166609" 47 | } 48 | } 49 | ], 50 | "STATISTICS": { 51 | "https_ssl": "ENABLED, SECURE" 52 | } 53 | } 54 | } -------------------------------------------------------------------------------- /geocoder/google_elevation.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # coding: utf8 3 | 4 | from __future__ import absolute_import 5 | from geocoder.base import OneResult, MultipleResultsQuery 6 | from geocoder.keys import google_key 7 | from geocoder.location import Location 8 | 9 | 10 | class ElevationResult(OneResult): 11 | 12 | @property 13 | def status(self): 14 | if self.elevation: 15 | return 'OK' 16 | else: 17 | return 'ERROR - No Elevation found' 18 | 19 | @property 20 | def ok(self): 21 | return bool(self.elevation) 22 | 23 | @property 24 | def meters(self): 25 | if self.elevation: 26 | return round(self.elevation, 1) 27 | 28 | @property 29 | def feet(self): 30 | if self.elevation: 31 | return round(self.elevation * 3.28084, 1) 32 | 33 | @property 34 | def elevation(self): 35 | return self.raw.get('elevation') 36 | 37 | @property 38 | def resolution(self): 39 | return self.raw.get('resolution') 40 | 41 | 42 | class ElevationQuery(MultipleResultsQuery): 43 | """ 44 | Google Elevation API 45 | ==================== 46 | The Elevation API provides elevation data for all locations on the surface of the 47 | earth, including depth locations on the ocean floor (which return negative values). 48 | In those cases where Google does not possess exact elevation measurements at the 49 | precise location you request, the service will interpolate and return an averaged 50 | value using the four nearest locations. 51 | 52 | API Reference 53 | ------------- 54 | https://developers.google.com/maps/documentation/elevation/ 55 | """ 56 | provider = 'google' 57 | method = 'elevation' 58 | 59 | _URL = 'https://maps.googleapis.com/maps/api/elevation/json' 60 | _RESULT_CLASS = ElevationResult 61 | _KEY = google_key 62 | 63 | def _build_params(self, location, provider_key, **kwargs): 64 | return { 65 | 'locations': str(Location(location)), 66 | } 67 | 68 | def _adapt_results(self, json_response): 69 | return json_response['results'] 70 | 71 | 72 | if __name__ == '__main__': 73 | g = ElevationQuery([45.123, -76.123]) 74 | g.debug() 75 | -------------------------------------------------------------------------------- /geocoder/yandex_reverse.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # coding: utf8 3 | 4 | from __future__ import absolute_import 5 | 6 | import logging 7 | 8 | from geocoder.yandex import YandexResult, YandexQuery 9 | from geocoder.location import Location 10 | 11 | 12 | class YandexReverseResult(YandexResult): 13 | 14 | @property 15 | def ok(self): 16 | return bool(self.address) 17 | 18 | 19 | class YandexReverse(YandexQuery): 20 | """ 21 | Yandex 22 | ====== 23 | Yandex (Russian: Яндекс) is a Russian Internet company 24 | which operates the largest search engine in Russia with 25 | about 60% market share in that country. 26 | The Yandex home page has been rated as the most popular website in Russia. 27 | Params 28 | ------ 29 | :param location: Your search location you want geocoded. 30 | :param lang: Chose the following language: 31 | > ru-RU — Russian (by default) 32 | > uk-UA — Ukrainian 33 | > be-BY — Belarusian 34 | > en-US — American English 35 | > en-BR — British English 36 | > tr-TR — Turkish (only for maps of Turkey) 37 | :param kind: Type of toponym (only for reverse geocoding): 38 | > house - house or building 39 | > street - street 40 | > metro - subway station 41 | > district - city district 42 | > locality - locality (city, town, village, etc.) 43 | References 44 | ---------- 45 | API Reference: http://api.yandex.com/maps/doc/geocoder/ 46 | desc/concepts/input_params.xml 47 | """ 48 | provider = 'yandex' 49 | method = 'reverse' 50 | 51 | _RESULT_CLASS = YandexReverseResult 52 | 53 | def _build_params(self, location, provider_key, **kwargs): 54 | x, y = Location(location).xy 55 | self.location = u'{}, {}'.format(x, y) 56 | return { 57 | 'geocode': self.location, 58 | 'lang': kwargs.get('lang', 'en-US'), 59 | 'kind': kwargs.get('kind', ''), 60 | 'format': 'json', 61 | 'results': kwargs.get('maxRows', 1), 62 | } 63 | 64 | 65 | if __name__ == '__main__': 66 | logging.basicConfig(level=logging.INFO) 67 | g = YandexReverse({'lat': 41.005407, 'lng': 28.978349}) 68 | g.debug() 69 | -------------------------------------------------------------------------------- /geocoder/gisgraphy.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # coding: utf8 3 | 4 | from __future__ import absolute_import 5 | 6 | import logging 7 | 8 | from geocoder.base import OneResult, MultipleResultsQuery 9 | 10 | 11 | class GisgraphyResult(OneResult): 12 | 13 | @property 14 | def lat(self): 15 | return self.raw.get('lat') 16 | 17 | @property 18 | def lng(self): 19 | return self.raw.get('lng') 20 | 21 | @property 22 | def address(self): 23 | return self.raw.get('formatedFull', '') 24 | 25 | @property 26 | def country(self): 27 | return self.raw.get('countryCode', '') 28 | 29 | @property 30 | def state(self): 31 | return self.raw.get('state', '') 32 | 33 | @property 34 | def city(self): 35 | return self.raw.get('city', '') 36 | 37 | @property 38 | def street(self): 39 | return self.raw.get('streetName', '') 40 | 41 | @property 42 | def housenumber(self): 43 | return self.raw.get('houseNumber', '') 44 | 45 | @property 46 | def postal(self): 47 | return self.raw.get('zipCode', '') 48 | 49 | 50 | class GisgraphyQuery(MultipleResultsQuery): 51 | """ 52 | Gisgraphy REST API 53 | ======================= 54 | 55 | API Reference 56 | ------------- 57 | http://www.gisgraphy.com/documentation/user-guide.php 58 | """ 59 | provider = 'gisgraphy' 60 | method = 'geocode' 61 | 62 | _URL = 'https://services.gisgraphy.com/geocoding/' 63 | _RESULT_CLASS = GisgraphyResult 64 | _KEY_MANDATORY = False 65 | 66 | def _build_headers(self, provider_key, **kwargs): 67 | return { 68 | 'Referer': "https://services.gisgraphy.com", 69 | 'User-agent': 'geocoder-converter' 70 | } 71 | 72 | def _build_params(self, location, provider_key, **kwargs): 73 | return { 74 | 'address': location, 75 | 'limitnbresult': kwargs.get('maxRows', 1), 76 | 'format': 'json', 77 | } 78 | 79 | def _adapt_results(self, json_response): 80 | return json_response['result'] 81 | 82 | if __name__ == '__main__': 83 | logging.basicConfig(level=logging.INFO) 84 | g = GisgraphyQuery('Ottawa Ontario', maxRows=3) 85 | g.debug() 86 | -------------------------------------------------------------------------------- /tests/test_locationiq.py: -------------------------------------------------------------------------------- 1 | # coding: utf8 2 | 3 | import json 4 | import geocoder 5 | import requests_mock 6 | 7 | location = 'Ottawa, Ontario' 8 | city = 'Ottawa' 9 | country = 'Canada' 10 | ottawa = (45.421106, -75.690308) 11 | 12 | 13 | def test_locationiq(): 14 | url = 'https://locationiq.org/v1/search.php?q=Ottawa%2C+Ontario&format=json&key=TEST_KEY' 15 | data_file = 'tests/results/locationiq.json' 16 | with requests_mock.Mocker() as mocker, open(data_file, 'r') as ip: 17 | mocker.get(url, text=ip.read()) 18 | g = geocoder.locationiq(location, key='TEST_KEY') 19 | assert g.ok 20 | assert g[0].lat == ottawa[0] 21 | assert g[0].lng == ottawa[1] 22 | 23 | 24 | def test_locationiq_single_result(): 25 | url = 'https://locationiq.org/v1/search.php?q=Ottawa%2C+Ontario&format=json&limit=1&key=TEST_KEY' 26 | data_file = 'tests/results/locationiq.json' 27 | with requests_mock.Mocker() as mocker, open(data_file, 'r') as ip: 28 | mock_result = json.loads(ip.read()) 29 | single_mock_result = json.dumps(mock_result[0:1]) 30 | mocker.get(url, text=single_mock_result) 31 | g = geocoder.locationiq(location, key='TEST_KEY', maxRows=1) 32 | assert g.ok 33 | assert len(g) == 1 34 | 35 | 36 | def test_locationiq_multi_result(): 37 | url = 'https://locationiq.org/v1/search.php?q=Ottawa%2C+Ontario&format=json&key=TEST_KEY' 38 | data_file = 'tests/results/locationiq.json' 39 | with requests_mock.Mocker() as mocker, open(data_file, 'r') as ip: 40 | mocker.get(url, text=ip.read()) 41 | g = geocoder.locationiq(location, key='TEST_KEY') 42 | assert g.ok 43 | assert len(g) > 1 44 | 45 | 46 | def test_locationiq_reverse(): 47 | url = 'https://locationiq.org/v1/search.php?q=45.421106%2C+-75.690308&format=json&addressdetails=1&key=TEST_KEY' 48 | data_file = 'tests/results/locationiq_reverse.json' 49 | with requests_mock.Mocker() as mocker, open(data_file, 'r') as ip: 50 | mocker.get(url, text=ip.read()) 51 | g = geocoder.locationiq( 52 | '{}, {}'.format(ottawa[0], ottawa[1]), 53 | key='TEST_KEY', 54 | method='reverse' 55 | ) 56 | assert g.ok 57 | assert g.city == city 58 | assert g.country == country 59 | -------------------------------------------------------------------------------- /docs/providers/TomTom.rst: -------------------------------------------------------------------------------- 1 | TomTom 2 | ====== 3 | 4 | The Geocoding API gives developers access to TomTom’s first class geocoding service. 5 | Developers may call this service through either a single or batch geocoding request. 6 | This service supports global coverage, with house number level matching in over 50 countries, 7 | and address point matching where available. 8 | Using Geocoder you can retrieve TomTom's geocoded data from Geocoding API. 9 | 10 | Geocoding 11 | ~~~~~~~~~ 12 | 13 | .. code-block:: python 14 | 15 | >>> import geocoder 16 | >>> g = geocoder.tomtom('San Francisco, CA', key='') 17 | >>> g.json 18 | ... 19 | 20 | This provider may return multiple results by setting the parameter `maxRows` to the desired number (1 by default). You can access those results as described in the page ':doc:`/results`'. 21 | 22 | Command Line Interface 23 | ---------------------- 24 | 25 | .. code-block:: bash 26 | 27 | $ geocode 'San Francisco, CA' --provider tomtom --out geojson 28 | 29 | Environment Variables 30 | --------------------- 31 | 32 | To make sure your API key is store safely on your computer, you can define that API key using your system's environment variables. 33 | 34 | .. code-block:: bash 35 | 36 | $ export TOMTOM_API_KEY= 37 | 38 | Parameters 39 | ---------- 40 | 41 | - `location`: Your search location you want geocoded. 42 | - `key`: Use your own API Key from TomTom. 43 | - `maxRows`: (default=1) Max number of results to fetch 44 | - `countrySet`: Comma separated string of country codes (e.g. FR,ES). This will limit the search to the specified countries 45 | - `lon`: Longitude e.g. lon=-121.89 lat./lon. where results should be biased (supplying a lat./lon. without a radius will only bias the search results to that area) 46 | - `lat`: Latitude e.g.lat=37.337 lat./lon. where results should be biased (supplying a lat./lon. without a radius will only bias the search results to that area) 47 | - `radius`: If radius and position are set, the results will be constrained to the defined area. The radius parameter is specified in meters. 48 | - `method`: (default=geocode) Use the following: 49 | 50 | - geocode 51 | 52 | References 53 | ---------- 54 | 55 | - `TomTom Geocoding API `_ 56 | -------------------------------------------------------------------------------- /geocoder/geocodefarm_reverse.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # coding: utf8 3 | from __future__ import absolute_import 4 | 5 | import logging 6 | 7 | from geocoder.location import Location 8 | from geocoder.geocodefarm import GeocodeFarmQuery 9 | 10 | 11 | class GeocodeFarmReverse(GeocodeFarmQuery): 12 | """ 13 | Geocode.Farm 14 | ======================= 15 | Geocode.Farm is one of the few providers that provide this highly 16 | specialized service for free. We also have affordable paid plans, of 17 | course, but our free services are of the same quality and provide the same 18 | results. The major difference between our affordable paid plans and our 19 | free API service is the limitations. On one of our affordable paid plans 20 | your limit is set based on the plan you signed up for, starting at 25,000 21 | query requests per day (API calls). On our free API offering, you are 22 | limited to 250 query requests per day (API calls). 23 | 24 | Params 25 | ------ 26 | :param lat: The numerical latitude value for which you wish to obtain the closest, human-readable address. 27 | :param lon: The numerical longitude value for which you wish to obtain the closest, human-readable address. 28 | :param key: (optional) API Key. Only Required for Paid Users. 29 | :param lang: (optional) 2 digit lanuage code to return results in. Currently only "en"(English) or "de"(German) supported. 30 | :param country: (optional) The country to return results in. Used for biasing purposes and may not fully filter results to this specific country. 31 | 32 | API Reference 33 | ------------- 34 | https://geocode.farm/geocoding/free-api-documentation/ 35 | """ 36 | provider = 'geocodefarm' 37 | method = 'reverse' 38 | 39 | _URL = 'https://www.geocode.farm/v3/json/reverse/' 40 | 41 | def _build_params(self, location, provider_key, **kwargs): 42 | location = Location(location) 43 | return { 44 | 'lat': location.latitude, 45 | 'lon': location.longitude, 46 | 'key': provider_key, 47 | 'lang': kwargs.get('lang', ''), 48 | 'country': kwargs.get('country', ''), 49 | } 50 | 51 | 52 | if __name__ == '__main__': 53 | logging.basicConfig(level=logging.INFO) 54 | g = GeocodeFarmReverse([45.3, -75.4]) 55 | g.debug() 56 | -------------------------------------------------------------------------------- /geocoder/ipinfo.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # coding: utf8 3 | 4 | from __future__ import absolute_import 5 | 6 | import logging 7 | 8 | from geocoder.base import OneResult, MultipleResultsQuery 9 | from geocoder.location import Location 10 | 11 | 12 | class IpinfoResult(OneResult): 13 | 14 | @property 15 | def lat(self): 16 | loc = self.raw.get('loc') 17 | if loc: 18 | return Location(loc).lat 19 | 20 | @property 21 | def lng(self): 22 | loc = self.raw.get('loc') 23 | if loc: 24 | return Location(loc).lng 25 | 26 | @property 27 | def address(self): 28 | if self.city: 29 | return u'{0}, {1}, {2}'.format(self.city, self.state, self.country) 30 | elif self.state: 31 | return u'{0}, {1}'.format(self.state, self.country) 32 | elif self.country: 33 | return u'{0}'.format(self.country) 34 | else: 35 | return u'' 36 | 37 | @property 38 | def postal(self): 39 | return self.raw.get('postal') 40 | 41 | @property 42 | def city(self): 43 | return self.raw.get('city') 44 | 45 | @property 46 | def state(self): 47 | return self.raw.get('region') 48 | 49 | @property 50 | def country(self): 51 | return self.raw.get('country') 52 | 53 | @property 54 | def hostname(self): 55 | return self.raw.get('hostname') 56 | 57 | @property 58 | def ip(self): 59 | return self.raw.get('ip') 60 | 61 | @property 62 | def org(self): 63 | return self.raw.get('org') 64 | 65 | 66 | class IpinfoQuery(MultipleResultsQuery): 67 | """ 68 | API Reference 69 | ------------- 70 | https://ipinfo.io 71 | """ 72 | provider = 'ipinfo' 73 | method = 'geocode' 74 | 75 | _URL = 'http://ipinfo.io/json' 76 | _RESULT_CLASS = IpinfoResult 77 | _KEY_MANDATORY = False 78 | 79 | def _before_initialize(self, location, **kwargs): 80 | if location.lower() == 'me' or location == '': 81 | self.url = 'http://ipinfo.io/json' 82 | else: 83 | self.url = 'http://ipinfo.io/{0}/json'.format(self.location) 84 | 85 | def _adapt_results(self, json_response): 86 | return [json_response] 87 | 88 | 89 | if __name__ == '__main__': 90 | logging.basicConfig(level=logging.INFO) 91 | g = IpinfoQuery('8.8.8.8') 92 | g.debug() 93 | -------------------------------------------------------------------------------- /geocoder/cli.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # coding: utf8 3 | 4 | from __future__ import absolute_import 5 | 6 | import click 7 | import json 8 | import geocoder 9 | import os 10 | import fileinput 11 | 12 | from geocoder.api import options 13 | 14 | 15 | providers = sorted(options.keys()) 16 | methods = ['geocode', 'reverse', 'elevation', 'timezone', 'places'] 17 | outputs = ['json', 'osm', 'geojson', 'wkt'] 18 | units = ['kilometers', 'miles', 'feet', 'meters'] 19 | 20 | 21 | @click.command() 22 | @click.argument('location', nargs=-1) 23 | @click.option('--provider', '-p', default='osm', type=click.Choice(providers)) 24 | @click.option('--method', '-m', default='geocode', type=click.Choice(methods)) 25 | @click.option('--output', '-o', default='json', type=click.Choice(outputs)) 26 | @click.option('--units', '-u', default='kilometers', type=click.Choice(units)) 27 | @click.option('--timeout', '-t', default=5.0) 28 | @click.option('--distance', is_flag=True) 29 | @click.option('--language', default='') 30 | @click.option('--url', default='') 31 | @click.option('--proxies') 32 | @click.option('--key') 33 | # following are for Tamu provider 34 | @click.option('--city', '-c', default='') 35 | @click.option('--state', '-s', default='') 36 | @click.option('--zipcode', '-z', default='') 37 | def cli(location, **kwargs): 38 | """Geocode an arbitrary number of strings from Command Line.""" 39 | 40 | locations = [] 41 | 42 | # Read Standard Input 43 | # $ cat foo.txt | geocode 44 | try: 45 | for line in fileinput.input(): 46 | locations.append(line.strip()) 47 | except: 48 | pass 49 | 50 | # Read multiple files & user input location 51 | for item in location: 52 | if os.path.exists(item): 53 | with open(item, 'rb') as f: 54 | locations += f.read().splitlines() 55 | else: 56 | locations.append(item) 57 | 58 | # Distance calculation 59 | if kwargs['distance']: 60 | d = geocoder.distance(locations, **kwargs) 61 | click.echo(d) 62 | return 63 | 64 | # Geocode results from user input 65 | for location in locations: 66 | g = geocoder.get(location.strip(), **kwargs) 67 | try: 68 | click.echo(json.dumps(getattr(g, kwargs['output']))) 69 | except IOError: 70 | # When invalid command is entered a broken pipe error occurs 71 | return 72 | 73 | 74 | if __name__ == '__main__': 75 | cli() 76 | -------------------------------------------------------------------------------- /docs/providers/GeocodeFarm.rst: -------------------------------------------------------------------------------- 1 | GeocodeFarm 2 | =========== 3 | 4 | Geocode.Farm is one of the few providers that provide this highly 5 | specialized service for free. We also have affordable paid plans, of 6 | course, but our free services are of the same quality and provide the same 7 | results. The major difference between our affordable paid plans and our 8 | free API service is the limitations. On one of our affordable paid plans 9 | your limit is set based on the plan you signed up for, starting at 25,000 10 | query requests per day (API calls). On our free API offering, you are 11 | limited to 250 query requests per day (API calls). 12 | 13 | Geocoding 14 | ~~~~~~~~~ 15 | 16 | .. code-block:: python 17 | 18 | >>> import geocoder 19 | >>> g = geocoder.geocodefarm('Mountain View, CA') 20 | >>> g.json 21 | ... 22 | 23 | This provider may return multiple results. You can access those results as described in the page ':doc:`/results`'. 24 | 25 | Reverse Geocoding 26 | ~~~~~~~~~~~~~~~~~ 27 | 28 | .. code-block:: python 29 | 30 | >>> import geocoder 31 | >>> g = geocoder.geocodefarm([45.15, -75.14], method='reverse') 32 | >>> g.json 33 | ... 34 | 35 | Command Line Interface 36 | ---------------------- 37 | 38 | .. code-block:: bash 39 | 40 | $ geocode 'Mountain View, CA' --provider geocodefarm 41 | $ geocode '45.15, -75.14' --provider geocodefarm --method reverse 42 | 43 | Environment Variables 44 | --------------------- 45 | 46 | To make sure your API key is store safely on your computer, you can define that API key using your system's environment variables. 47 | 48 | .. code-block:: bash 49 | 50 | $ export GEOCODEFARM_API_KEY= 51 | 52 | Parameters 53 | ---------- 54 | 55 | - `location`: The string to search for. Usually a street address. If reverse then should be a latitude/longitude. 56 | - `key`: (optional) API Key. Only Required for Paid Users. 57 | - `lang`: (optional) 2 digit lanuage code to return results in. Currently only "en"(English) or "de"(German) supported. 58 | - `country`: (optional) The country to return results in. Used for biasing purposes and may not fully filter results to this specific country. 59 | - `maxRows`: (default=1) Max number of results to fetch 60 | - `method`: (default=geocode) Use the following: 61 | 62 | - geocode 63 | - reverse 64 | 65 | References 66 | ---------- 67 | 68 | - `GeocodeFarm API Documentation `_ 69 | -------------------------------------------------------------------------------- /geocoder/bing_batch_forward.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # coding: utf8 3 | 4 | from __future__ import absolute_import, print_function 5 | from geocoder.bing_batch import BingBatch, BingBatchResult 6 | 7 | import io 8 | import csv 9 | import sys 10 | 11 | PY2 = sys.version_info < (3, 0) 12 | csv_io = io.BytesIO if PY2 else io.StringIO 13 | csv_encode = (lambda input: input) if PY2 else (lambda input: input.encode('utf-8')) 14 | csv_decode = (lambda input: input) if PY2 else (lambda input: input.decode('utf-8')) 15 | 16 | 17 | class BingBatchForwardResult(BingBatchResult): 18 | 19 | @property 20 | def lat(self): 21 | coord = self._content 22 | if coord: 23 | return float(coord[0]) 24 | 25 | @property 26 | def lng(self): 27 | coord = self._content 28 | if coord: 29 | return float(coord[1]) 30 | 31 | @property 32 | def ok(self): 33 | return bool(self._content) 34 | 35 | def debug(self, verbose=True): 36 | with csv_io() as output: 37 | print('\n', file=output) 38 | print('Bing Batch result\n', file=output) 39 | print('-----------\n', file=output) 40 | print(self._content, file=output) 41 | 42 | if verbose: 43 | print(output.getvalue()) 44 | 45 | return [None, None] 46 | 47 | 48 | class BingBatchForward(BingBatch): 49 | method = 'batch' 50 | _RESULT_CLASS = BingBatchForwardResult 51 | 52 | def generate_batch(self, addresses): 53 | out = csv_io() 54 | writer = csv.writer(out) 55 | writer.writerow([ 56 | 'Id', 57 | 'GeocodeRequest/Query', 58 | 'GeocodeResponse/Point/Latitude', 59 | 'GeocodeResponse/Point/Longitude' 60 | ]) 61 | 62 | for idx, address in enumerate(addresses): 63 | writer.writerow([idx, address, None, None]) 64 | 65 | return csv_encode("Bing Spatial Data Services, 2.0\n{}".format(out.getvalue())) 66 | 67 | def _adapt_results(self, response): 68 | result = csv_io(csv_decode(response)) 69 | # Skipping first line with Bing header 70 | next(result) 71 | 72 | rows = {} 73 | for row in csv.DictReader(result): 74 | rows[row['Id']] = [row['GeocodeResponse/Point/Latitude'], row['GeocodeResponse/Point/Longitude']] 75 | 76 | return rows 77 | 78 | 79 | if __name__ == '__main__': 80 | g = BingBatchForward(['Denver,CO', 'Boulder,CO'], key=None) 81 | g.debug() 82 | -------------------------------------------------------------------------------- /geocoder/keys.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # coding: utf8 3 | import os 4 | import re 5 | import requests 6 | 7 | 8 | bing_key = os.environ.get('BING_API_KEY') 9 | tomtom_key = os.environ.get('TOMTOM_API_KEY') 10 | here_app_id = os.environ.get('HERE_APP_ID') 11 | here_app_code = os.environ.get('HERE_APP_CODE') 12 | geonames_username = os.environ.get('GEONAMES_USERNAME') 13 | opencage_key = os.environ.get('OPENCAGE_API_KEY') 14 | mapquest_key = os.environ.get('MAPQUEST_API_KEY') 15 | baidu_key = os.environ.get('BAIDU_API_KEY') 16 | baidu_security_key = os.environ.get('BAIDU_SECURITY_KEY') 17 | gaode_key = os.environ.get('GAODE_API_KEY') 18 | w3w_key = os.environ.get('W3W_API_KEY') 19 | mapbox_access_token = os.environ.get('MAPBOX_ACCESS_TOKEN') 20 | google_key = os.environ.get('GOOGLE_API_KEY') 21 | google_client = os.environ.get('GOOGLE_CLIENT') 22 | google_client_secret = os.environ.get('GOOGLE_CLIENT_SECRET') 23 | mapzen_key = os.environ.get('MAPZEN_API_KEY') 24 | tamu_key = os.environ.get('TAMU_API_KEY') 25 | geocodefarm_key = os.environ.get('GEOCODEFARM_API_KEY') 26 | tgos_key = os.environ.get('TGOS_API_KEY') 27 | locationiq_key = os.environ.get('LOCATIONIQ_API_KEY') 28 | 29 | 30 | class CanadapostKeyLazySingleton(object): 31 | 32 | CANADAPOST_KEY_REGEX = re.compile(r"'(....-....-....-....)';") 33 | 34 | def __init__(self): 35 | self._key = None 36 | 37 | def __call__(self, **kwargs): 38 | if self._key is None: 39 | self._key = self.retrieve_key(**kwargs) 40 | return self._key 41 | 42 | @classmethod 43 | def retrieve_key(cls, **kwargs): 44 | # get key with traditionnal mechanism 45 | key = kwargs.get('key') 46 | canadapost_key = os.environ.get('CANADAPOST_API_KEY') 47 | if key or canadapost_key: 48 | return key if key else canadapost_key 49 | 50 | # fallback 51 | try: 52 | url = 'http://www.canadapost.ca/cpo/mc/personal/postalcode/fpc.jsf' 53 | timeout = kwargs.get('timeout', 5.0) 54 | proxies = kwargs.get('proxies', '') 55 | r = requests.get(url, timeout=timeout, proxies=proxies) 56 | match = cls.CANADAPOST_KEY_REGEX.search(r.text) 57 | if match: 58 | return match.group(1) 59 | else: 60 | raise ValueError('No API Key found') 61 | except Exception as err: 62 | raise ValueError('Could not retrieve API Key: %s' % err) 63 | 64 | 65 | canadapost_key_getter = CanadapostKeyLazySingleton() 66 | -------------------------------------------------------------------------------- /tests/test_google.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # coding: utf8 3 | 4 | import geocoder 5 | 6 | import requests_mock 7 | 8 | location = 'Ottawa, Ontario' 9 | city = 'Ottawa' 10 | ottawa = (45.4215296, -75.6971930) 11 | place = 'rail station, Ottawa' 12 | 13 | 14 | def test_google(): 15 | urls = [ 16 | # when testing locally 17 | 'https://maps.googleapis.com/maps/api/geocode/json?language=&address=Ottawa,%20Ontario&bounds=&components=®ion=&key=mock', 18 | # when building in Travis (secured connection implies ordered parameters) 19 | 'https://maps.googleapis.com/maps/api/geocode/json?client=[secure]&latlng=45.4215296%2C+-75.697193&sensor=false&signature=iXbq6odmrYN0XgcfB5EPcgEvR-I%3D' 20 | ] 21 | data_file = 'tests/results/google.json' 22 | with requests_mock.Mocker() as mocker, open(data_file, 'r') as input: 23 | for url in urls: 24 | mocker.get(url, text=input.read()) 25 | g = geocoder.google(location, client=None, key='mock') 26 | assert g.ok 27 | assert g.accuracy == 'APPROXIMATE' 28 | assert str(g.city) == city 29 | osm_count, fields_count = g.debug()[0] 30 | assert osm_count >= 3 31 | assert fields_count >= 15 32 | 33 | 34 | def test_issue_294(): 35 | g = geocoder.google("Cerro Torre Mountain") 36 | assert g.ok 37 | 38 | 39 | def test_google_reverse(): 40 | g = geocoder.google(ottawa, method='reverse') 41 | assert g.ok 42 | assert len(g) >= 10 43 | 44 | 45 | def test_google_places(): 46 | g = geocoder.google(place, method='places') 47 | assert g.ok 48 | assert g.address == '200 Tremblay Rd, Ottawa, ON K1G 3H5, Canada' 49 | 50 | 51 | def test_google_timezone(): 52 | url = 'https://maps.googleapis.com/maps/api/timezone/json?location=45.4215296%2C+-75.697193×tamp=1500000000' 53 | data_file = 'tests/results/google_timezone.json' 54 | with requests_mock.Mocker() as mocker, open(data_file, 'r') as input: 55 | mocker.get(url, text=input.read()) 56 | g = geocoder.google(ottawa, method='timezone', timestamp=1500000000) 57 | assert g.ok 58 | 59 | 60 | def test_google_elevation(): 61 | url = 'https://maps.googleapis.com/maps/api/elevation/json?locations=45.4215296%2C+-75.697193' 62 | data_file = 'tests/results/google_elevation.json' 63 | with requests_mock.Mocker() as mocker, open(data_file, 'r') as input: 64 | mocker.get(url, text=input.read()) 65 | g = geocoder.google(ottawa, method='elevation') 66 | assert g.ok 67 | -------------------------------------------------------------------------------- /AUTHORS.rst: -------------------------------------------------------------------------------- 1 | Authors 2 | ======= 3 | 4 | Lead Developer 5 | -------------- 6 | 7 | - `Denis Carriere`_ - Creator of Python's Geocoder 8 | 9 | Contributors 10 | ------------ 11 | 12 | A big thanks to all the people that help contribute: 13 | 14 | - `Virus Warnning`_ - Implemented TGOS provider 15 | - `Kevin Brolly`_ - Implemented GeocodeFarm provider 16 | - `Michael R. Okun`_ - Implemented Tamu provider 17 | - `Palo Dravecky`_ - Added Google for Work. 18 | - `Dunice Vadimh`_ - Added IPInfo provider. 19 | - `Yed Podtrzitko`_ - Cleaned up code & Added Six 20 | - `Thomas Gratier`_ - Wrote an article about `Geocoder vs. Geopy`_ 21 | - `Max Arnold`_ - Submitted Github Issue 22 | - `Thanh Ha`_ - Cleaned up code & Unit Testing 23 | - `Mahdi Yusuf`_ - Promoted by `Pycoders Weekly`_, `Issue #155 Nimoy`_ 24 | - `Alex Pilon`_ - Cleaned up code 25 | - `Philip Hubertus`_ - Provided HERE improvements & documentation 26 | - `Antonio Lima`_ - Improved code quality and introduced Rate Limits 27 | - `Alexander Lukanin`_ - Improved Python 3 compatibilty 28 | - flebel_ - Submitted Github Issues 29 | - patrickyan_ - Submitted Github Issues 30 | - esy_ - Submitted Github Issues 31 | - Sergei Grabalin (Сергей Грабалин) - Fixed Python2 Unicode Issues 32 | - `Matthieu Rigal`_ - Added session support 33 | 34 | .. _`Virus Warnning`: https://github.com/virus-warnning 35 | .. _`Kevin Brolly`: https://twitter.com/KevinBrolly 36 | .. _`Michael R. Okun`: https://github.com/ac6y 37 | .. _`Yed Podtrzitko`: https://github.com/yedpodtrzitko 38 | .. _`Palo Dravecky`: https://github.com/Chartres 39 | .. _`Dunice Vadimh`: https://github.com/dunice-vadimh 40 | .. _`Denis Carriere`: https://twitter.com/DenisCarriere 41 | .. _`Issue #155 Nimoy`: http://us4.campaign-archive2.com/?u=9735795484d2e4c204da82a29&id=2776ce7284 42 | .. _`Geocoder vs. Geopy`: http://webgeodatavore.com/python-geocoders-clients-comparison.html 43 | .. _`Thomas Gratier`: https://twitter.com/ThomasG77 44 | .. _`Max Arnold`: https://github.com/max-arnold 45 | .. _`Thanh Ha`: https://twitter.com/zxiiro 46 | .. _`Alex Pilon`: http://alexpilon.ca 47 | .. _`Mahdi Yusuf`: https://twitter.com/myusuf3 48 | .. _`Pycoders Weekly`: https://twitter.com/pycoders 49 | .. _`Philip Hubertus`: https://twitter.com/philiphubs 50 | .. _`Antonio Lima`: https://twitter.com/themiurgo 51 | .. _`Alexander Lukanin`: https://github.com/alexanderlukanin13 52 | .. _flebel: https://github.com/flebel 53 | .. _patrickyan: https://github.com/patrickyan 54 | .. _esy: https://github.com/lambda-conspiracy 55 | .. _Matthieu Rigal: https://github.com/MRigal 56 | -------------------------------------------------------------------------------- /geocoder/baidu_reverse.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # coding: utf8 3 | from __future__ import absolute_import 4 | 5 | import logging 6 | 7 | from geocoder.location import Location 8 | from geocoder.base import OneResult 9 | from geocoder.baidu import BaiduQuery 10 | 11 | 12 | class BaiduReverseResult(OneResult): 13 | @property 14 | def ok(self): 15 | return bool(self.address) 16 | 17 | @property 18 | def address(self): 19 | return self.raw['formatted_address'] 20 | 21 | @property 22 | def country(self): 23 | return self.raw['addressComponent']['country'] 24 | 25 | @property 26 | def province(self): 27 | return self.raw['addressComponent']['province'] 28 | 29 | @property 30 | def state(self): 31 | return self.raw['addressComponent']['province'] 32 | 33 | @property 34 | def city(self): 35 | return self.raw['addressComponent']['city'] 36 | 37 | @property 38 | def district(self): 39 | return self.raw['addressComponent']['district'] 40 | 41 | @property 42 | def street(self): 43 | return self.raw['addressComponent']['street'] 44 | 45 | @property 46 | def housenumber(self): 47 | return self.raw['addressComponent']['street_number'] 48 | 49 | 50 | class BaiduReverse(BaiduQuery): 51 | """ 52 | Baidu Geocoding API 53 | =================== 54 | Baidu Maps Geocoding API is a free open the API, the default quota 55 | one million times / day. 56 | 57 | Params 58 | ------ 59 | :param location: Your search location you want geocoded. 60 | :param key: Baidu API key. 61 | :param referer: Baidu API referer website. 62 | 63 | References 64 | ---------- 65 | API Documentation: http://developer.baidu.com/map 66 | Get Baidu Key: http://lbsyun.baidu.com/apiconsole/key 67 | """ 68 | provider = 'baidu' 69 | method = 'reverse' 70 | 71 | _URL = 'http://api.map.baidu.com/geocoder/v2/' 72 | _RESULT_CLASS = BaiduReverseResult 73 | 74 | def _build_params(self, location, provider_key, **kwargs): 75 | location = Location(location) 76 | params = { 77 | 'location': str(location), 78 | 'ret_coordtype': kwargs.get('coordtype', 'wgs84ll'), 79 | 'output': 'json', 80 | 'ak': provider_key 81 | } 82 | if ('lang_code' in kwargs): 83 | params['accept-language'] = kwargs['lang_code'] 84 | 85 | return params 86 | 87 | 88 | if __name__ == '__main__': 89 | logging.basicConfig(level=logging.INFO) 90 | g = BaiduReverse("39.983424,116.32298", key='') 91 | g.debug() 92 | -------------------------------------------------------------------------------- /docs/providers/Tamu.rst: -------------------------------------------------------------------------------- 1 | Tamu 2 | ==== 3 | The Texas A&M Geoservices Geocoding API provides output including Lat and Lon 4 | and numerous census data values. 5 | 6 | An API key linked to an account with Texas A&M is required. 7 | 8 | Tamu's API differs from the other geocoders in this package in that it 9 | requires the street address, city, state, and US zipcode to be passed in 10 | separately, rather than as a single string. Because of this requirement, 11 | the "location", "city", "state", and "zipcode" parameters are all required 12 | when using the Tamu provider. The "location" parameter should contain only 13 | the street address of the location. 14 | 15 | Geocoding 16 | ~~~~~~~~~ 17 | 18 | .. code-block:: python 19 | 20 | >>> import geocoder 21 | >>> g = geocoder.tamu( 22 | '595 Market St', 23 | city='San Francisco', 24 | state='California', 25 | zipcode='94105', 26 | key='demo') 27 | >>> g.json 28 | ... 29 | 30 | Command Line Interface 31 | ---------------------- 32 | 33 | .. code-block:: bash 34 | 35 | $ geocode '595 Market St' --provider tamu --city San Francisco --state CA --zipcode 94105 --key 36 | 37 | Environment Variables 38 | --------------------- 39 | 40 | To make sure your API key is store safely on your computer, you can define that API key using your system's environment variables. 41 | 42 | .. code-block:: bash 43 | 44 | $ export TAMU_API_KEY= 45 | 46 | Parameters 47 | ---------- 48 | 49 | - `location`: The street address of the location you want geocoded. 50 | - `city`: The city of the location to geocode. 51 | - `state`: The state of the location to geocode. 52 | - `zipcode`: The zipcode of the location to geocode. 53 | - `key`: use your own API Key from Tamu. 54 | - `method`: (default=geocode) Use the following: 55 | 56 | - geocode 57 | 58 | Census Output Fields 59 | -------------------- 60 | Note: "FIPS" stands for "Federal Information Processing System" 61 | 62 | - `census_block`: Census Block value for location 63 | - `census_tract`: Census Tract value for location 64 | - `census_county_fips`: Census County FIPS value 65 | - `census_cbsa_fips`: Census Core Base Statistical Area FIPS value 66 | - `census_mcd_fips`: Census Minor Civil Division FIPS value 67 | - `census_msa_fips`: Census Metropolitan Statistical Area FIPS value 68 | - `census_place_fips`: Census Place FIPS value 69 | - `census_state_fips`: Census State FIPS value 70 | - `census_year`: Census Year from which these values originated 71 | 72 | 73 | References 74 | ---------- 75 | - `Tamu Geocoding API `_ 76 | -------------------------------------------------------------------------------- /docs/providers/OpenStreetMap.rst: -------------------------------------------------------------------------------- 1 | OpenStreetMap 2 | ============= 3 | 4 | Nominatim (from the Latin, 'by name') is a tool to search OSM data by name 5 | and address and to generate synthetic addresses of OSM points (reverse geocoding). 6 | Using Geocoder you can retrieve OSM's geocoded data from Nominatim. 7 | 8 | Geocoding 9 | ~~~~~~~~~ 10 | 11 | .. code-block:: python 12 | 13 | >>> import geocoder 14 | >>> g = geocoder.osm('New York city') 15 | >>> g.json 16 | ... 17 | 18 | This provider may return multiple results by setting the parameter `maxRows` to the desired number (1 by default). You can access those results as described in the page ':doc:`/results`'. 19 | 20 | Nominatim Server 21 | ~~~~~~~~~~~~~~~~ 22 | 23 | Setting up your own offline Nominatim server is possible, using Ubuntu 14.04 as your OS and following the `Nominatim Install`_ instructions. This enables you to request as much geocoding as your little heart desires! 24 | 25 | .. code-block:: python 26 | 27 | >>> url = 'http://localhost/nominatim/' 28 | >>> url = 'localhost' 29 | >>> g = geocoder.osm("New York City", url=url) 30 | >>> g.json 31 | ... 32 | 33 | OSM Addresses 34 | ~~~~~~~~~~~~~ 35 | 36 | The `addr tag`_ is the prefix for several `addr:*` keys to describe addresses. 37 | 38 | This format is meant to be saved as a CSV and imported into JOSM. 39 | 40 | .. code-block:: python 41 | 42 | >>> g = geocoder.osm('11 Wall Street, New York') 43 | >>> g.osm 44 | { 45 | "x": -74.010865, 46 | "y": 40.7071407, 47 | "addr:country": "United States of America", 48 | "addr:state": "New York", 49 | "addr:housenumber": "11", 50 | "addr:postal": "10005", 51 | "addr:city": "NYC", 52 | "addr:street": "Wall Street" 53 | } 54 | 55 | 56 | Command Line Interface 57 | ---------------------- 58 | 59 | .. code-block:: bash 60 | 61 | $ geocode 'New York city' --provider osm --out geojson | jq . 62 | $ geocode 'New York city' -p osm -o osm 63 | $ geocode 'New York city' -p osm --url localhost 64 | 65 | Parameters 66 | ---------- 67 | 68 | - `location`: Your search location you want geocoded. 69 | - `url`: Custom OSM Server (ex: localhost) 70 | - `maxRows`: (default=1) Max number of results to fetch 71 | - `limit`: *Deprecated*, same as maxRows 72 | - `method`: (default=geocode) Use the following: 73 | 74 | - geocode 75 | 76 | References 77 | ---------- 78 | 79 | - `Nominatim `_ 80 | - `Nominatim Install`_ 81 | - `addr tag`_ 82 | 83 | 84 | .. _addr tag: http://wiki.openstreetmap.org/wiki/Key:addr 85 | .. _Nominatim Install: http://wiki.openstreetmap.org/wiki/Nominatim/Installation 86 | 87 | -------------------------------------------------------------------------------- /docs/features/Distance.md: -------------------------------------------------------------------------------- 1 | # Distance Tool 2 | 3 | The distance tool measures the Great Circle distance between the surface of the earth between two or multiple points. 4 | 5 | ![Distance Tool](https://pbs.twimg.com/media/CAbDTPKW8AAQ68l.png:large) 6 | 7 | *** 8 | 9 | ## Examples 10 | 11 | ### Python & CLI 12 | 13 | Simply add as many locations into the `distance` function, to change the units of measurement include the `units` parameter. 14 | 15 | When entering a location string it will geocode it automatically using the given `provider` parameter. Some warning errors might occur when trying to geocode too many string locations, this is a combination of rate limits or a lost URL connection. 16 | 17 | When using the CLI, simply raise the `--distance` flag to use the distance tool. 18 | 19 | #### Simple use 20 | 21 | ```python 22 | >>> from geocoder import distance 23 | >>> d = distance("Ottawa, ON", "Toronto, ON") 24 | >>> print(d) 25 | 353.80 26 | >>> type(d) 27 | float 28 | ``` 29 | 30 | ```bash 31 | $ geocode "Ottawa, ON", "Toronto, ON" --distance 32 | 353.80 33 | ``` 34 | 35 | #### Select a Geocoder provider 36 | 37 | ```python 38 | # Default provider="bing" 39 | >>> distance("Ottawa, ON", "Toronto, ON", provider="google") 40 | 353.80 41 | ``` 42 | 43 | ```bash 44 | $ geocode "Ottawa, ON", "Toronto, ON" --distance --provider="google" 45 | 353.80 46 | ``` 47 | 48 | #### Define Units of measurements 49 | 50 | ```python 51 | # Default units='kilometers' 52 | # Ex: kilometers, miles, feet, meters 53 | >>> distance("Ottawa, ON", "Toronto, ON", units="miles") 54 | 219.84 55 | ``` 56 | 57 | ```bash 58 | $ geocode "Ottawa, ON", "Toronto, ON" --distance --units="miles" 59 | 219.84 60 | ``` 61 | 62 | #### Using LatLng strings or lists 63 | 64 | ```python 65 | >>> distance([45.07, -75.49], "43.30, -80.15") 66 | 351.94 67 | ``` 68 | 69 | ```bash 70 | $ geocode "[45.07, -76.49]", "43.30, -80.15" --distance 71 | 351.94 72 | ``` 73 | 74 | #### 3 or more locations 75 | 76 | ```python 77 | >>> distance("Ottawa, ON", "Toronto, ON", "Montreal, QC") 78 | 521.18 79 | ``` 80 | 81 | ```bash 82 | $ geocode "Ottawa, ON", "Toronto, ON", "Montreal, QC" --distance 83 | 521.18 84 | ``` 85 | 86 | #### Input Geocoder objects 87 | 88 | ```python 89 | >>> import geocoder 90 | >>> point1 = geocoder.google("Ottawa, ON") 91 | >>> point2 = geocoder.bing("Toronto, ON") 92 | >>> geocoder.distance(point1, point2) 93 | 353.80 94 | ``` 95 | 96 | ## Parameters 97 | 98 | - `location` : Your search locations you want geocoded. (min 2x locations) 99 | - `units` : Unit of measurement. (default=kilometers) 100 | - kilometers 101 | - miles 102 | - feet 103 | - meters -------------------------------------------------------------------------------- /geocoder/gaode.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # coding: utf8 3 | 4 | from __future__ import absolute_import 5 | 6 | import logging 7 | 8 | from geocoder.base import OneResult, MultipleResultsQuery 9 | from geocoder.keys import gaode_key 10 | 11 | 12 | class GaodeResult(OneResult): 13 | 14 | @property 15 | def lat(self): 16 | return float(self.raw.get('location', '0,0').replace("'", '').split(',')[1]) 17 | 18 | @property 19 | def lng(self): 20 | return float(self.raw.get('location', '0,0').replace("'", '').split(',')[0]) 21 | 22 | @property 23 | def quality(self): 24 | return self.raw.get('level') 25 | 26 | @property 27 | def address(self): 28 | return self.raw.get('formatted_address') 29 | 30 | @property 31 | def country(self): 32 | return '中国' 33 | 34 | @property 35 | def province(self): 36 | return self.raw.get('province') 37 | 38 | @property 39 | def state(self): 40 | return self.raw.get('province') 41 | 42 | @property 43 | def city(self): 44 | return self.raw.get('city') 45 | 46 | @property 47 | def district(self): 48 | return self.raw.get('district') 49 | 50 | @property 51 | def street(self): 52 | return self.raw.get('street') 53 | 54 | @property 55 | def adcode(self): 56 | return self.raw.get('adcode') 57 | 58 | @property 59 | def housenumber(self): 60 | return self.raw.get('number') 61 | 62 | 63 | class GaodeQuery(MultipleResultsQuery): 64 | """ 65 | Gaode AMap Geocoding API 66 | =================== 67 | Gaode Maps Geocoding API is a free open the API, the default quota 68 | 2000 times / day. 69 | 70 | Params 71 | ------ 72 | :param location: Your search location you want geocoded. 73 | :param key: Gaode API key. 74 | 75 | References 76 | ---------- 77 | API Documentation: http://lbs.amap.com/api/webservice/guide/api/georegeo 78 | Get AMap Key: http://lbs.amap.com/dev/ 79 | """ 80 | provider = 'gaode' 81 | method = 'geocode' 82 | 83 | _URL = 'http://restapi.amap.com/v3/geocode/geo' 84 | _RESULT_CLASS = GaodeResult 85 | _KEY = gaode_key 86 | 87 | def _build_params(self, location, provider_key, **kwargs): 88 | return { 89 | 'address': location, 90 | 'output': 'JSON', 91 | 'key': provider_key, 92 | } 93 | 94 | def _build_headers(self, provider_key, **kwargs): 95 | return {'Referer': kwargs.get('referer', '')} 96 | 97 | def _adapt_results(self, json_response): 98 | return json_response['geocodes'] 99 | 100 | 101 | if __name__ == '__main__': 102 | logging.basicConfig(level=logging.INFO) 103 | g = GaodeQuery('将台路') 104 | g.debug() 105 | -------------------------------------------------------------------------------- /geocoder/geolytica.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # coding: utf8 3 | from __future__ import absolute_import 4 | 5 | import logging 6 | 7 | from geocoder.base import OneResult, MultipleResultsQuery 8 | 9 | 10 | class GeolyticaResult(OneResult): 11 | 12 | def __init__(self, json_content): 13 | # create safe shortcuts 14 | self._standard = json_content.get('standard', {}) 15 | 16 | # proceed with super.__init__ 17 | super(GeolyticaResult, self).__init__(json_content) 18 | 19 | @property 20 | def lat(self): 21 | lat = self.raw.get('latt', '').strip() 22 | if lat: 23 | return float(lat) 24 | 25 | @property 26 | def lng(self): 27 | lng = self.raw.get('longt', '').strip() 28 | if lng: 29 | return float(lng) 30 | 31 | @property 32 | def postal(self): 33 | return self.raw.get('postal', '').strip() 34 | 35 | @property 36 | def housenumber(self): 37 | return self._standard.get('stnumber', '').strip() 38 | 39 | @property 40 | def street(self): 41 | return self._standard.get('staddress', '').strip() 42 | 43 | @property 44 | def city(self): 45 | return self._standard.get('city', '').strip() 46 | 47 | @property 48 | def state(self): 49 | return self._standard.get('prov', '').strip() 50 | 51 | @property 52 | def address(self): 53 | if self.street_number: 54 | return u'{0} {1}, {2}'.format(self.street_number, self.route, self.locality) 55 | elif self.route and self.route != 'un-known': 56 | return u'{0}, {1}'.format(self.route, self.locality) 57 | else: 58 | return self.locality 59 | 60 | 61 | class GeolyticaQuery(MultipleResultsQuery): 62 | """ 63 | Geocoder.ca 64 | =========== 65 | A Canadian and US location geocoder. 66 | 67 | API Reference 68 | ------------- 69 | http://geocoder.ca/?api=1 70 | """ 71 | provider = 'geolytica' 72 | method = 'geocode' 73 | 74 | _URL = 'http://geocoder.ca' 75 | _RESULT_CLASS = GeolyticaResult 76 | _KEY_MANDATORY = False 77 | 78 | def _build_params(self, location, provider_key, **kwargs): 79 | params = { 80 | 'json': 1, 81 | 'locate': location, 82 | 'geoit': 'xml' 83 | } 84 | if 'strictmode' in kwargs: 85 | params.update({'strictmode': kwargs.pop('strictmode')}) 86 | if 'strict' in kwargs: 87 | params.update({'strict': kwargs.pop('strict')}) 88 | if 'auth' in kwargs: 89 | params.update({'auth': kwargs.pop('auth')}) 90 | return params 91 | 92 | def _adapt_results(self, json_response): 93 | return [json_response] 94 | 95 | if __name__ == '__main__': 96 | logging.basicConfig(level=logging.INFO) 97 | g = GeolyticaQuery('1552 Payette dr., Ottawa') 98 | g.debug() 99 | -------------------------------------------------------------------------------- /docs/providers/HERE.rst: -------------------------------------------------------------------------------- 1 | HERE 2 | ==== 3 | 4 | Send a request to the geocode endpoint to find an address using a combination of 5 | country, state, county, city, postal code, district, street and house number. 6 | Using Geocoder you can retrieve geocoded data from the HERE Geocoder REST API. 7 | 8 | Geocoding 9 | ~~~~~~~~~ 10 | 11 | .. code-block:: python 12 | 13 | >>> import geocoder 14 | >>> g = geocoder.here('Espoo, Finland') 15 | >>> g.json 16 | ... 17 | 18 | This provider may return multiple results by setting the parameter `maxRows` to the desired number (1 by default). You can access those results as described in the page ':doc:`/results`'. 19 | 20 | A bounding box can be supplied as an array of the form [minX, minY, maxX, maxY] to restrict results. 21 | 22 | .. code-block:: python 23 | 24 | >>> import geocoder 25 | >>> bbox = [-118.604794, 34.172684, -118.500938, 34.236144] 26 | >>> g = geocoder.here("Winnetka", bbox=bbox) 27 | >>> g.address 28 | "Winnetka, CA, United States" 29 | >>> g = geocoder.here("Winnetka") 30 | >>> g.address 31 | "Winnetka, IL, United States" 32 | ... 33 | 34 | Please refer to :ref:`this section ` for more details. 35 | Reverse Geocoding 36 | ~~~~~~~~~~~~~~~~~ 37 | 38 | .. code-block:: python 39 | 40 | >>> import geocoder 41 | >>> g = geocoder.google([45.15, -75.14], method='reverse') 42 | >>> g.json 43 | ... 44 | 45 | Using API Key 46 | ------------- 47 | 48 | If you want to use your own `app_id` & `app_code`, you must register an app 49 | at the `HERE Developer `_. 50 | 51 | .. code-block:: python 52 | 53 | >>> g = geocoder.here('Espoo, Finland', 54 | app_id='', 55 | app_code='') 56 | 57 | 58 | Command Line Interface 59 | ---------------------- 60 | 61 | .. code-block:: bash 62 | 63 | $ geocode 'Espoo, Finland' --provider here 64 | $ geocode '45.15, -75.14' --provider here --method reverse 65 | 66 | Environment Variables 67 | --------------------- 68 | 69 | To make sure your API key is store safely on your computer, you can define that API key using your system's environment variables. 70 | 71 | .. code-block:: bash 72 | 73 | $ export HERE_APP_ID= 74 | $ export HERE_APP_CODE= 75 | 76 | Parameters 77 | ---------- 78 | 79 | - `location`: Your search location you want geocoded. 80 | - `app_code`: (optional) use your own Application Code from HERE. 81 | - `app_id`: (optional) use your own Application ID from HERE. 82 | - `bbox`: Search within a bounding box [minX, minY, maxX, maxY]. Pass as an array. 83 | - `maxRows`: (default=1) Max number of results to fetch 84 | - `method`: (default=geocode) Use the following: 85 | 86 | - geocode 87 | - reverse 88 | 89 | References 90 | ---------- 91 | 92 | - `HERE Geocoder REST API `_ 93 | -------------------------------------------------------------------------------- /docs/providers/MapQuest.rst: -------------------------------------------------------------------------------- 1 | MapQuest 2 | ======== 3 | 4 | The geocoding service enables you to take an address and get the 5 | associated latitude and longitude. You can also use any latitude 6 | and longitude pair and get the associated address. Three types of 7 | geocoding are offered: address, reverse, and batch. 8 | Using Geocoder you can retrieve MapQuest's geocoded data from Geocoding Service. 9 | 10 | Geocoding 11 | ~~~~~~~~~ 12 | 13 | .. code-block:: python 14 | 15 | >>> import geocoder 16 | >>> g = geocoder.mapquest('San Francisco, CA', key='') 17 | >>> g.json 18 | ... 19 | 20 | This provider may return multiple results by setting the parameter `maxRows` to the desired number (1 by default). You can access those results as described in the page ':doc:`/results`'. 21 | 22 | A bounding box can be supplied as an array of the form [minX, minY, maxX, maxY] to bump results within a the bounding box to the top. 23 | 24 | .. code-block:: python 25 | 26 | >>> import geocoder 27 | >>> bbox = [-118.604794, 34.172684, -118.500938, 34.236144] 28 | >>> g = geocoder.here("Winnetka", bbox=bbox) 29 | >>> g.lng, g.lat 30 | (-118.571098, 34.213299) 31 | >>> g = geocoder.here("Winnetka") 32 | >>> g.lng, g.lat 33 | (-87.734719, 42.107106) 34 | ... 35 | 36 | This provider gives access to batch geocoding services that allow you to geocode up to 100 addresses at the same time. 37 | 38 | .. code-block:: python 39 | 40 | >>> import geocoder 41 | >>> g = geocoder.mapquest(['Mountain View, CA', 'Boulder, Co'], method='batch') 42 | >>> for result in g: 43 | ... print(result.address, result.latlng) 44 | ... 45 | ('Mountain View', [37.39008, -122.08139]) 46 | ('Boulder', [40.015831, -105.27927]) 47 | ... 48 | 49 | Reverse Geocoding 50 | ~~~~~~~~~~~~~~~~~ 51 | 52 | .. code-block:: python 53 | 54 | >>> import geocoder 55 | >>> g = geocoder.mapquest([45.15, -75.14], method='reverse', key='') 56 | >>> g.json 57 | ... 58 | 59 | Command Line Interface 60 | ---------------------- 61 | 62 | .. code-block:: bash 63 | 64 | $ geocode 'San Francisco, CA' --provider mapquest --out geojson 65 | 66 | Environment Variables 67 | --------------------- 68 | 69 | To make sure your API key is store safely on your computer, you can define that API key using your system's environment variables. 70 | 71 | .. code-block:: bash 72 | 73 | $ export MAPQUEST_API_KEY= 74 | 75 | Parameters 76 | ---------- 77 | 78 | - `location`: Your search location you want geocoded. 79 | - `maxRows`: (default=1) Max number of results to fetch 80 | - `bbox`: Search within a bounding box [minX, minY, maxX, maxY]. Pass as an array. 81 | - `method`: (default=geocode) Use the following: 82 | 83 | - geocode 84 | - batch 85 | 86 | References 87 | ---------- 88 | 89 | - `Mapquest Geocoding Service `_ 90 | - `Get Free API Key `_ 91 | -------------------------------------------------------------------------------- /geocoder/arcgis_reverse.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # coding: utf8 3 | from __future__ import absolute_import 4 | 5 | import logging 6 | 7 | from geocoder.base import OneResult 8 | from geocoder.arcgis import ArcgisQuery 9 | from geocoder.location import Location 10 | 11 | 12 | class ArcgisReverseResult(OneResult): 13 | 14 | @property 15 | def ok(self): 16 | return bool(self.address) 17 | 18 | @property 19 | def lat(self): 20 | return self.raw['location'].get('y') 21 | 22 | @property 23 | def lng(self): 24 | return self.raw['location'].get('x') 25 | 26 | @property 27 | def address(self): 28 | return self.raw['address'].get('Match_addr') 29 | 30 | @property 31 | def city(self): 32 | return self.raw['address'].get('City') 33 | 34 | @property 35 | def neighborhood(self): 36 | return self.raw['address'].get('Neighbourhood') 37 | 38 | @property 39 | def region(self): 40 | return self.raw['address'].get('Region') 41 | 42 | @property 43 | def country(self): 44 | return self.raw['address'].get('CountryCode') 45 | 46 | @property 47 | def postal(self): 48 | return self.raw['address'].get('Postal') 49 | 50 | @property 51 | def state(self): 52 | return self.raw['address'].get('Region') 53 | 54 | 55 | class ArcgisReverse(ArcgisQuery): 56 | """ 57 | ArcGIS REST API 58 | ======================= 59 | The World Geocoding Service finds addresses and places in all supported countries 60 | from a single endpoint. The service can find point locations of addresses, 61 | business names, and so on. The output points can be visualized on a map, 62 | inserted as stops for a route, or loaded as input for a spatial analysis. 63 | an address, retrieving imagery metadata, or creating a route. 64 | 65 | API Reference 66 | ------------- 67 | https://developers.arcgis.com/rest/geocode/api-reference/geocoding-reverse-geocode.htm 68 | """ 69 | provider = 'arcgis' 70 | method = 'reverse' 71 | 72 | _URL = 'https://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer/reverseGeocode' 73 | _RESULT_CLASS = ArcgisReverseResult 74 | 75 | def _build_params(self, location, provider_key, **kwargs): 76 | location = Location(location) 77 | return { 78 | 'location': u'{}, {}'.format(location.lng, location.lat), 79 | 'f': 'pjson', 80 | 'distance': kwargs.get('distance', 50000), 81 | 'outSR': kwargs.get('outSR', '') 82 | } 83 | 84 | def _adapt_results(self, json_response): 85 | return [json_response] 86 | 87 | def _catch_errors(self, json_response): 88 | error = json_response.get('error', None) 89 | if error: 90 | self.error = error['message'] 91 | 92 | return self.error 93 | 94 | 95 | if __name__ == '__main__': 96 | logging.basicConfig(level=logging.INFO) 97 | g = ArcgisReverse("45.404702, -75.704150") 98 | g.debug() 99 | -------------------------------------------------------------------------------- /geocoder/distance.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # coding: utf8 3 | 4 | from __future__ import absolute_import 5 | from math import radians, cos, sin, asin, sqrt 6 | from geocoder.location import Location 7 | 8 | AVG_EARTH_RADIUS = 6371 # in km 9 | 10 | 11 | def Distance(*args, **kwargs): 12 | total = 0.0 13 | last = None 14 | 15 | if len(args) == 1 and isinstance(args, (list, tuple)): 16 | args = args[0] 17 | 18 | if len(args) <= 1: 19 | raise ValueError("Distance needs at least two locations") 20 | 21 | for location in args: 22 | if last: 23 | distance = haversine(Location(last), Location(location), **kwargs) 24 | if distance: 25 | total += distance 26 | last = location 27 | 28 | return total 29 | 30 | 31 | def haversine(point1, point2, **kwargs): 32 | """ Calculate the great-circle distance bewteen two points on the Earth surface. 33 | 34 | :input: two 2-tuples, containing the latitude and longitude of each point 35 | in decimal degrees. 36 | 37 | Example: haversine((45.7597, 4.8422), (48.8567, 2.3508)) 38 | 39 | :output: Returns the distance bewteen the two points. 40 | The default unit is kilometers. Miles can be returned 41 | if the ``miles`` parameter is set to True. 42 | 43 | """ 44 | 45 | lookup_units = { 46 | 'miles': 'miles', 47 | 'mile': 'miles', 48 | 'mi': 'miles', 49 | 'ml': 'miles', 50 | 'kilometers': 'kilometers', 51 | 'kilometres': 'kilometers', 52 | 'kilometer': 'kilometers', 53 | 'kilometre': 'kilometers', 54 | 'km': 'kilometers', 55 | 'meters': 'meters', 56 | 'metres': 'meters', 57 | 'meter': 'meters', 58 | 'metre': 'meters', 59 | 'm': 'meters', 60 | 'feet': 'feet', 61 | 'f': 'feet', 62 | 'ft': 'feet', 63 | } 64 | 65 | if point1.ok and point2.ok: 66 | # convert all latitudes/longitudes from decimal degrees to radians 67 | lat1, lng1, lat2, lng2 = list(map(radians, point1.latlng + point2.latlng)) 68 | 69 | # calculate haversine 70 | lat = lat2 - lat1 71 | lng = lng2 - lng1 72 | d = sin(lat / 2) ** 2 + cos(lat1) * cos(lat2) * sin(lng / 2) ** 2 73 | h = 2 * AVG_EARTH_RADIUS * asin(sqrt(d)) 74 | 75 | # Measurements 76 | units = kwargs.get('units', 'kilometers').lower() 77 | units_calculation = { 78 | 'miles': h * 0.621371, 79 | 'feet': h * 0.621371 * 5280, 80 | 'meters': h * 1000, 81 | 'kilometers': h, 82 | } 83 | 84 | if units in lookup_units: 85 | return units_calculation[lookup_units[units]] 86 | else: 87 | raise ValueError("Unknown units of measurement") 88 | 89 | else: 90 | print(u'[WARNING] Error calculating the following two locations.\n' 91 | 'Points: {0} to {1}'.format(point1.location, point2.location)) 92 | 93 | if __name__ == '__main__': 94 | d = Distance('Ottawa, ON', 'Toronto, ON', 'Montreal, QC') 95 | print(d) 96 | -------------------------------------------------------------------------------- /geocoder/mapzen.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # coding: utf8 3 | 4 | from __future__ import absolute_import 5 | 6 | import logging 7 | 8 | from geocoder.location import BBox 9 | from geocoder.base import OneResult, MultipleResultsQuery 10 | from geocoder.keys import mapzen_key 11 | 12 | 13 | class MapzenResult(OneResult): 14 | 15 | def __init__(self, json_content): 16 | # create safe shortcuts 17 | self._geometry = json_content.get('geometry', {}) 18 | self._properties = json_content.get('properties', {}) 19 | 20 | # proceed with super.__init__ 21 | super(MapzenResult, self).__init__(json_content) 22 | 23 | @property 24 | def lat(self): 25 | return self._geometry['coordinates'][1] 26 | 27 | @property 28 | def lng(self): 29 | return self._geometry['coordinates'][0] 30 | 31 | @property 32 | def bbox(self): 33 | return BBox.factory(self.latlng).as_dict 34 | 35 | @property 36 | def address(self): 37 | return self._properties.get('label') 38 | 39 | @property 40 | def housenumber(self): 41 | return self._properties.get('housenumber') 42 | 43 | @property 44 | def street(self): 45 | return self._properties.get('street') 46 | 47 | @property 48 | def neighbourhood(self): 49 | return self._properties.get('neighbourhood') 50 | 51 | @property 52 | def city(self): 53 | return self._properties.get('locality') 54 | 55 | @property 56 | def state(self): 57 | return self._properties.get('region') 58 | 59 | @property 60 | def country(self): 61 | return self._properties.get('country') 62 | 63 | @property 64 | def postal(self): 65 | return self._properties.get('postalcode') 66 | 67 | @property 68 | def gid(self): 69 | return self._properties.get('gid') 70 | 71 | @property 72 | def id(self): 73 | return self._properties.get('id') 74 | 75 | 76 | class MapzenQuery(MultipleResultsQuery): 77 | """ 78 | Mapzen REST API 79 | ======================= 80 | 81 | API Reference 82 | ------------- 83 | https://mapzen.com/documentation/search/search/ 84 | """ 85 | provider = 'mapzen' 86 | method = 'geocode' 87 | 88 | _URL = 'https://search.mapzen.com/v1/search' 89 | _RESULT_CLASS = MapzenResult 90 | _KEY = mapzen_key 91 | 92 | def __init__(self, *args, **kwargs): 93 | raise DeprecationWarning('MapZen shut down as of January 2018: https://mapzen.com/blog/shutdown') 94 | 95 | def _build_params(self, location, provider_key, **kwargs): 96 | return { 97 | 'text': location, 98 | 'api_key': provider_key, 99 | 'size': kwargs.get('maxRows', 1) 100 | } 101 | 102 | def _adapt_results(self, json_response): 103 | return json_response['features'] 104 | 105 | 106 | if __name__ == '__main__': 107 | logging.basicConfig(level=logging.INFO) 108 | g = MapzenQuery('201 Spear Street, San Francisco') 109 | g.debug() 110 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | Geocoder: Simple, Consistent 2 | ============================ 3 | 4 | Release v\ |version|. (:ref:`Installation `) 5 | 6 | Simple and consistent geocoding library written in Python. 7 | 8 | Many online providers such as Google & Bing have geocoding services, 9 | these providers do not include Python libraries and have different 10 | JSON responses between each other. 11 | 12 | It can be very difficult sometimes to parse a particular geocoding provider 13 | since each one of them have their own JSON schema. 14 | 15 | Here is a typical example of retrieving a Lat & Lng from Google using Python, 16 | things shouldn't be this hard. 17 | 18 | .. code-block:: python 19 | 20 | >>> import requests 21 | >>> url = 'https://maps.googleapis.com/maps/api/geocode/json' 22 | >>> params = {'sensor': 'false', 'address': 'Mountain View, CA'} 23 | >>> r = requests.get(url, params=params) 24 | >>> results = r.json()['results'] 25 | >>> location = results[0]['geometry']['location'] 26 | >>> location['lat'], location['lng'] 27 | (37.3860517, -122.0838511) 28 | 29 | Now lets use Geocoder to do the same task. 30 | 31 | .. code-block:: python 32 | 33 | >>> import geocoder 34 | >>> g = geocoder.google('Mountain View, CA') 35 | >>> g.latlng 36 | (37.3860517, -122.0838511) 37 | 38 | Testimonials 39 | ------------ 40 | 41 | **Tobias Siebenlist** 42 | Geocoder: great geocoding library by @DenisCarriere. 43 | 44 | **mcbetz** 45 | Very good companion for Geocoder. Glad to see Python getting more geo libraries for Non-GIS users. 46 | 47 | 48 | API Documentation 49 | ----------------- 50 | 51 | If you are looking for information on a specific function, class or method, 52 | this part of the documentation is for you. 53 | 54 | .. toctree:: 55 | :maxdepth: 3 56 | 57 | api 58 | results 59 | wip_guide 60 | examples/QGISFieldCalculator.rst 61 | 62 | 63 | Providers 64 | --------- 65 | 66 | Detailed information about each individual provider that are within Geocoder. 67 | 68 | .. toctree:: 69 | :maxdepth: 2 70 | 71 | providers/ArcGIS.rst 72 | providers/Baidu.rst 73 | providers/Bing.rst 74 | providers/CanadaPost.rst 75 | providers/FreeGeoIP.rst 76 | providers/Gaode.rst 77 | providers/GeocodeFarm.rst 78 | providers/Geocoder-ca.rst 79 | providers/GeoNames.rst 80 | providers/GeoOttawa.rst 81 | providers/Google.rst 82 | providers/HERE.rst 83 | providers/IPInfo.rst 84 | providers/LocationIQ.rst 85 | providers/Mapbox.rst 86 | providers/MapQuest.rst 87 | providers/MaxMind.rst 88 | providers/OpenCage.rst 89 | providers/OpenStreetMap.rst 90 | providers/Tamu.rst 91 | providers/TomTom.rst 92 | providers/What3Words.rst 93 | providers/Yahoo.rst 94 | providers/Yandex.rst 95 | providers/TGOS.rst 96 | 97 | 98 | Contributor Guide 99 | ----------------- 100 | 101 | If you want to contribute to the project, this part of the documentation is for 102 | you. 103 | 104 | .. toctree:: 105 | :maxdepth: 1 106 | 107 | authors 108 | -------------------------------------------------------------------------------- /geocoder/gaode_reverse.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # coding: utf8 3 | 4 | from __future__ import absolute_import 5 | 6 | import logging 7 | 8 | from geocoder.location import Location 9 | from geocoder.base import OneResult 10 | from geocoder.gaode import GaodeQuery 11 | 12 | 13 | class GaodeReverseResult(OneResult): 14 | 15 | @property 16 | def ok(self): 17 | return bool(self.address) 18 | 19 | @property 20 | def address(self): 21 | return self.raw['formatted_address'] 22 | 23 | @property 24 | def country(self): 25 | return self.raw['addressComponent']['country'] 26 | 27 | @property 28 | def province(self): 29 | return self.raw['addressComponent']['province'] 30 | 31 | @property 32 | def state(self): 33 | return self.raw['addressComponent']['province'] 34 | 35 | @property 36 | def city(self): 37 | if len(self.raw['addressComponent']['city']) == 0: 38 | return self.raw['addressComponent']['province'] 39 | else: 40 | return self.raw['addressComponent']['city'] 41 | 42 | @property 43 | def district(self): 44 | return self.raw['addressComponent']['district'] 45 | 46 | @property 47 | def street(self): 48 | return self.raw['addressComponent']['streetNumber']['street'] 49 | 50 | @property 51 | def adcode(self): 52 | return self.raw['addressComponent']['adcode'] 53 | 54 | @property 55 | def township(self): 56 | return self.raw['addressComponent']['township'] 57 | 58 | @property 59 | def towncode(self): 60 | return self.raw['addressComponent']['towncode'] 61 | 62 | @property 63 | def housenumber(self): 64 | return self.raw['addressComponent']['streetNumber']['number'] 65 | 66 | 67 | class GaodeReverse(GaodeQuery): 68 | """ 69 | Gaode GeoReverse API 70 | =================== 71 | Gaode Maps GeoReverse API is a free open the API, the default quota 72 | 2000 times / day. 73 | 74 | Params 75 | ------ 76 | :param location: Your search location you want geocoded. 77 | :param key: Gaode API key. 78 | :param referer: Gaode API referer website. 79 | 80 | References 81 | ---------- 82 | API Documentation: http://lbs.amap.com/api/webservice/guide/api/georegeo 83 | Get Gaode AMap Key: http://lbs.amap.com/dev/ 84 | """ 85 | provider = 'gaode' 86 | method = 'reverse' 87 | 88 | _URL = 'http://restapi.amap.com/v3/geocode/regeo' 89 | _RESULT_CLASS = GaodeReverseResult 90 | 91 | def _build_params(self, location, provider_key, **kwargs): 92 | location = Location(location) 93 | return { 94 | 'location': str(location.lng) + ',' + str(location.lat), 95 | 'output': 'json', 96 | 'key': provider_key, 97 | } 98 | 99 | def _adapt_results(self, json_response): 100 | return [json_response['regeocode']] 101 | 102 | 103 | if __name__ == '__main__': 104 | logging.basicConfig(level=logging.INFO) 105 | g = GaodeReverse("39.971577, 116.506142") 106 | g.debug() 107 | -------------------------------------------------------------------------------- /docs/providers/Mapbox.rst: -------------------------------------------------------------------------------- 1 | Mapbox 2 | ====== 3 | 4 | The Mapbox Geocoding API lets you convert location text into 5 | geographic coordinates (1600 Pennsylvania Ave NW → -77.0366,38.8971). 6 | 7 | Geocoding 8 | ~~~~~~~~~ 9 | 10 | .. code-block:: python 11 | 12 | >>> import geocoder 13 | >>> g = geocoder.mapbox('San Francisco, CA', key='') 14 | >>> g.json 15 | ... 16 | 17 | This provider may return multiple results. You can access those results as described in the page ':doc:`/results`'. 18 | 19 | Request feature data that best matches input and is biased to the given {latitude} and {longitude} coordinates. In the above example, a query of "200 Queen Street" returns a subset of all relevant addresses in the world. By adding the proximity option, this subset can be biased towards a given area, returning a more relevant set of results. In addition, a bounding box can be supplied to restrict results. 20 | 21 | .. code-block:: python 22 | 23 | >>> import geocoder 24 | >>> latlng = [45.3, -66.1] 25 | >>> g = geocoder.mapbox("200 Queen Street", proximity=latlng) 26 | >>> g.address 27 | "200 Queen St W, Saint John, New Brunswick E2M 2C8, Canada" 28 | >>> g = geocoder.mapbox("200 Queen Street") 29 | >>> g.address 30 | "200 Queen Street, Colac, Victoria 3250, Australia" 31 | >>> bbox = [-118.604794, 34.172684, -118.500938, 34.236144] 32 | >>> g = geocoder.mapbox("Winnetka", bbox=bbox) 33 | >>> g.address 34 | "Winnetka, Winnetka, California 91306, United States" 35 | >>> g = geocoder.mapbox("Winnetka") 36 | >>> g.address 37 | "Winnetka Heights, Dallas, Texas 75211, United States" 38 | ... 39 | 40 | Please refer to :ref:`this section ` for more details. 41 | 42 | Reverse Geocoding 43 | ~~~~~~~~~~~~~~~~~ 44 | 45 | .. code-block:: python 46 | 47 | >>> import geocoder 48 | >>> latlng = [45.3, -105.1] 49 | >>> g = geocoder.mapbox(latlng, method='reverse') 50 | >>> g.json 51 | ... 52 | 53 | Command Line Interface 54 | ---------------------- 55 | 56 | .. code-block:: bash 57 | 58 | $ geocode 'San Francisco, CA' --provider mapbox --out geojson 59 | $ geocode '45.15, -75.14' --provider mapbox --method reverse 60 | 61 | Environment Variables 62 | --------------------- 63 | 64 | To make sure your API key is store safely on your computer, you can define that API key using your system's environment variables. 65 | 66 | .. code-block:: bash 67 | 68 | $ export MAPBOX_ACCESS_TOKEN= 69 | 70 | Parameters 71 | ---------- 72 | 73 | - `location`: Your search location you want geocoded. 74 | - `proximity`: Search nearby [lat, lng]. 75 | - `bbox`: Search within a bounding box [minX, minY, maxX, maxY]. Pass as an array. 76 | - `key`: Use your own access token from Mapbox. 77 | - `country`: Filtering by country code {cc} ISO 3166 alpha 2. 78 | - `proximity`: Search within given area (bbox, bounds, or around latlng) 79 | - `method`: (default=geocode) Use the following: 80 | 81 | - geocode 82 | - reverse 83 | 84 | References 85 | ---------- 86 | 87 | - `Mapbox Geocoding API `_ 88 | - `Get Mapbox Access Token `_ 89 | -------------------------------------------------------------------------------- /geocoder/yahoo.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # coding: utf8 3 | from __future__ import absolute_import 4 | 5 | import logging 6 | 7 | from geocoder.base import OneResult, MultipleResultsQuery 8 | 9 | 10 | class YahooResult(OneResult): 11 | 12 | @property 13 | def lat(self): 14 | return self.raw.get('latitude') 15 | 16 | @property 17 | def lng(self): 18 | return self.raw.get('longitude') 19 | 20 | @property 21 | def address(self): 22 | line1 = self.raw.get('line1') 23 | line2 = self.raw.get('line2') 24 | if line1: 25 | return ', '.join([line1, line2]) 26 | else: 27 | return line2 28 | 29 | @property 30 | def housenumber(self): 31 | return self.raw.get('house') 32 | 33 | @property 34 | def street(self): 35 | return self.raw.get('street') 36 | 37 | @property 38 | def neighborhood(self): 39 | return self.raw.get('neighborhood') 40 | 41 | @property 42 | def city(self): 43 | return self.raw.get('city') 44 | 45 | @property 46 | def county(self): 47 | return self.raw.get('county') 48 | 49 | @property 50 | def state(self): 51 | return self.raw.get('state') 52 | 53 | @property 54 | def country(self): 55 | return self.raw.get('country') 56 | 57 | @property 58 | def hash(self): 59 | return self.raw.get('hash') 60 | 61 | @property 62 | def quality(self): 63 | return self.raw.get('addressMatchType') 64 | 65 | @property 66 | def postal(self): 67 | postal = self.raw.get('postal') 68 | if postal: 69 | return postal 70 | else: 71 | return self.raw.get('uzip') 72 | 73 | 74 | class YahooQuery(MultipleResultsQuery): 75 | """ 76 | Yahoo BOSS Geo Services 77 | ======================= 78 | Yahoo PlaceFinder is a geocoding Web service that helps developers make 79 | their applications location-aware by converting street addresses or 80 | place names into geographic coordinates (and vice versa). 81 | 82 | API Reference 83 | ------------- 84 | https://developer.yahoo.com/boss/geo/ 85 | """ 86 | provider = 'yahoo' 87 | method = 'geocode' 88 | 89 | _URL = 'https://sgws2.maps.yahoo.com/FindLocation' 90 | _RESULT_CLASS = YahooResult 91 | _KEY_MANDATORY = False 92 | 93 | def _build_params(self, location, provider_key, **kwargs): 94 | return{ 95 | 'q': location, 96 | 'flags': 'J', 97 | 'locale': kwargs.get('locale', 'en-CA'), 98 | } 99 | 100 | def _catch_errors(self, json_response): 101 | status = json_response['statusDescription'] 102 | if status: 103 | if not status == 'OK': 104 | self.error = status 105 | 106 | return self.error 107 | 108 | def _adapt_results(self, json_response): 109 | return [json_response['Result']] 110 | 111 | 112 | if __name__ == '__main__': 113 | logging.basicConfig(level=logging.INFO) 114 | g = YahooQuery('1552 Payette dr., Ottawa, ON') 115 | g.debug() 116 | -------------------------------------------------------------------------------- /geocoder/ottawa.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # coding: utf8 3 | 4 | from __future__ import absolute_import 5 | 6 | import logging 7 | import re 8 | 9 | from geocoder.base import OneResult, MultipleResultsQuery 10 | 11 | 12 | class OttawaResult(OneResult): 13 | 14 | @property 15 | def lat(self): 16 | return self.raw.get('location', {}).get('y') 17 | 18 | @property 19 | def lng(self): 20 | return self.raw.get('location', {}).get('x') 21 | 22 | @property 23 | def postal(self): 24 | if self.address: 25 | expression = r'([ABCEGHJKLMNPRSTVXY]{1}\d{1}[A-Z]{1}( *\d{1}[A-Z]{1}\d{1})?)' 26 | pattern = re.compile(expression) 27 | match = pattern.search(self.address.upper()) 28 | if match: 29 | return match.group(0) 30 | 31 | @property 32 | def housenumber(self): 33 | if self.address: 34 | expression = r'\d+' 35 | pattern = re.compile(expression) 36 | match = pattern.search(self.address) 37 | if match: 38 | return int(match.group(0)) 39 | 40 | @property 41 | def city(self): 42 | return 'Ottawa' 43 | 44 | @property 45 | def state(self): 46 | return 'Ontario' 47 | 48 | @property 49 | def country(self): 50 | return 'Canada' 51 | 52 | @property 53 | def address(self): 54 | return self.raw.get('address') 55 | 56 | @property 57 | def accuracy(self): 58 | return self.raw.get('score') 59 | 60 | 61 | class OttawaQuery(MultipleResultsQuery): 62 | """ 63 | Ottawa ArcGIS REST Services 64 | =========================== 65 | Geocoding is the process of assigning a location, usually in the form of 66 | coordinate values (points), to an address by comparing the descriptive 67 | location elements in the address to those present in the reference 68 | material. Addresses come in many forms, ranging from the common address 69 | format of a house number followed by the street name and succeeding 70 | information to other location descriptions such as postal zone or census 71 | tract. An address includes any type of information that distinguishes 72 | a place. 73 | 74 | API Reference 75 | ------------- 76 | http://maps.ottawa.ca/ArcGIS/rest/services/compositeLocator/GeocodeServer/findAddressCandidates 77 | """ 78 | provider = 'ottawa' 79 | method = 'geocode' 80 | 81 | _URL = 'http://maps.ottawa.ca/ArcGIS/rest/services/compositeLocator/GeocodeServer/findAddressCandidates' 82 | _RESULT_CLASS = OttawaResult 83 | _KEY_MANDATORY = False 84 | 85 | def _build_params(self, location, provider_key, **kwargs): 86 | return { 87 | 'SingleLine': location.replace(', Ottawa, ON', ''), 88 | 'f': 'json', 89 | 'outSR': 4326, 90 | 'maxLocations': kwargs.get('maxRows', 1) 91 | } 92 | 93 | def _adapt_results(self, json_response): 94 | return json_response.get('candidates', []) 95 | 96 | if __name__ == '__main__': 97 | logging.basicConfig(level=logging.INFO) 98 | g = OttawaQuery('1552 Payette dr.') 99 | g.debug() 100 | -------------------------------------------------------------------------------- /tests/test_opencage.py: -------------------------------------------------------------------------------- 1 | # coding: utf8 2 | 3 | import os 4 | import geocoder 5 | import requests_mock 6 | 7 | address = 'The Happy Goat, Ottawa' 8 | location = 'Ottawa, Ontario' 9 | city = 'Ottawa' 10 | ottawa = (45.4215296, -75.6971930) 11 | 12 | 13 | def test_opencage(): 14 | """ Expected result : 15 | https://api.opencagedata.com/geocode/v1/json?q=Ottawa,Ontario&key=YOUR-API-KEY 16 | """ 17 | g = geocoder.opencage(location) 18 | assert g.ok 19 | assert len(g) == 1 20 | assert g.country_code == 'ca' 21 | assert g.state == 'Ontario' 22 | assert g.state_code == 'ON' 23 | assert g.city == 'Ottawa' 24 | assert g.town == 'Ottawa' 25 | osm_count, fields_count = g.debug()[0] 26 | assert osm_count >= 3 27 | assert fields_count >= 23 28 | 29 | 30 | def test_issue_292(): 31 | g = geocoder.opencage('AirportClinic M - MediCare Flughafen München Medizinisches Zentrum', countrycode='DE', language='de', no_annotations=1) 32 | assert g.ok 33 | 34 | def test_opencage_no_language_param(): 35 | """ Expected result : 36 | https://api.opencagedata.com/geocode/v1/json=Ottawa,Ontario&key=YOUR-API-KEY 37 | """ 38 | g = geocoder.opencage(location) 39 | assert 'language' not in g.url 40 | 41 | def test_opencage_language_param(): 42 | """ Expected result : 43 | https://api.opencagedata.com/geocode/v1/json=Ottawa,Ontario&key=YOUR-API-KEY&language=de 44 | """ 45 | g = geocoder.opencage(location, language='de') 46 | assert 'language=de' in g.url.split('&') 47 | 48 | def test_opencage_multi_result(): 49 | g = geocoder.opencage(location, maxRows=5) 50 | assert len(g) > 1 51 | 52 | 53 | def test_opencage_address(): 54 | """ Expected result : 55 | https://api.opencagedata.com/geocode/v1/json?q=The+Happy+Goat,+Ottawa&key=YOUR-API-KEY 56 | """ 57 | g = geocoder.opencage(address) 58 | assert g.ok 59 | assert g.country == 'Canada' 60 | assert g.state == 'Ontario' 61 | assert g.state_code == 'ON' 62 | assert g.city == 'Ottawa' 63 | assert g.street == 'Wilbrod Street' 64 | assert g.housenumber == '317' 65 | assert g.postal.startswith('K1N') 66 | assert (g.remaining_api_calls > 0 and g.remaining_api_calls != 999999) 67 | assert (g.limit_api_calls > 0 and g.remaining_api_calls != 999999) 68 | 69 | def test_opencage_paid(): 70 | # Paid API keys can be set to unlimited and have rate limit information ommitted from the response 71 | url = 'http://api.opencagedata.com/geocode/v1/json?query=The+Happy+Goat%2C+Ottawa&limit=1&key=' + os.environ.get('OPENCAGE_API_KEY') 72 | data_file = 'tests/results/opencagedata_paid.json' 73 | with requests_mock.Mocker() as mocker, open(data_file, 'r') as input: 74 | mocker.get(url, text=input.read()) 75 | result = geocoder.opencage(address) 76 | assert result.ok 77 | osm_count, fields_count = result.debug()[0] 78 | assert osm_count >= 3 79 | assert fields_count >= 15 80 | assert result.remaining_api_calls == 999999 81 | assert result.limit_api_calls == 999999 82 | 83 | 84 | 85 | 86 | def test_opencage_reverse(): 87 | """ Expected result : 88 | https://api.opencagedata.com/geocode/v1/json?q=45.4215296,-75.6971930&key=YOUR-API-KEY 89 | """ 90 | g = geocoder.opencage(ottawa, method='reverse') 91 | assert g.ok 92 | -------------------------------------------------------------------------------- /geocoder/arcgis.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # coding: utf8 3 | from __future__ import absolute_import 4 | 5 | import logging 6 | import json 7 | 8 | from geocoder.base import OneResult, MultipleResultsQuery 9 | 10 | 11 | class ArcgisResult(OneResult): 12 | 13 | def __init__(self, json_content): 14 | # create safe shortcuts 15 | self._feature = json_content.get('feature', {}) 16 | 17 | # proceed with super.__init__ 18 | super(ArcgisResult, self).__init__(json_content) 19 | 20 | @property 21 | def address(self): 22 | return self.raw.get('name', '') 23 | 24 | @property 25 | def lat(self): 26 | return self._feature.get('geometry', {}).get('y') 27 | 28 | @property 29 | def lng(self): 30 | return self._feature.get('geometry', {}).get('x') 31 | 32 | @property 33 | def score(self): 34 | return self._feature.get('attributes', {}).get('Score', '') 35 | 36 | @property 37 | def quality(self): 38 | return self._feature.get('attributes', {}).get('Addr_Type', '') 39 | 40 | @property 41 | def bbox(self): 42 | _extent = self.raw.get('extent') 43 | if _extent: 44 | south = _extent.get('ymin') 45 | west = _extent.get('xmin') 46 | north = _extent.get('ymax') 47 | east = _extent.get('xmax') 48 | return self._get_bbox(south, west, north, east) 49 | 50 | 51 | class ArcgisQuery(MultipleResultsQuery): 52 | """ 53 | ArcGIS REST API 54 | ======================= 55 | The World Geocoding Service finds addresses and places in all supported countries 56 | from a single endpoint. The service can find point locations of addresses, 57 | business names, and so on. The output points can be visualized on a map, 58 | inserted as stops for a route, or loaded as input for a spatial analysis. 59 | an address, retrieving imagery metadata, or creating a route. 60 | 61 | API Reference 62 | ------------- 63 | https://developers.arcgis.com/rest/geocode/api-reference/geocoding-find.htm 64 | """ 65 | provider = 'arcgis' 66 | method = 'geocode' 67 | 68 | _URL = 'https://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer/find' 69 | _RESULT_CLASS = ArcgisResult 70 | _KEY_MANDATORY = False 71 | 72 | def _build_params(self, location, provider_key, **kwargs): 73 | # backward compatitibility for 'limit' (now maxRows) 74 | if 'limit' in kwargs: 75 | logging.warning( 76 | "argument 'limit' in OSM is deprecated and should be replaced with maxRows") 77 | kwargs['maxRows'] = kwargs['limit'] 78 | # build params 79 | return { 80 | 'f': 'json', 81 | 'text': location, 82 | 'maxLocations': kwargs.get('maxRows', 1), 83 | } 84 | 85 | def _adapt_results(self, json_response): 86 | return json_response['locations'] 87 | 88 | def _catch_errors(self, json_response): 89 | status = json_response.get('error') 90 | if status: 91 | self.error = status.get('code') 92 | self.message = status.get('message') 93 | self.details = status.get('details') 94 | 95 | return self.error 96 | 97 | 98 | if __name__ == '__main__': 99 | logging.basicConfig(level=logging.INFO) 100 | g = ArcgisQuery('Toronto') 101 | g.debug() 102 | g = ArcgisQuery('Ottawa, Ontario', maxRows=5) 103 | print(json.dumps(g.geojson, indent=4)) 104 | print([result.address for result in g][:3]) 105 | -------------------------------------------------------------------------------- /geocoder/bing_batch_reverse.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # coding: utf8 3 | 4 | from __future__ import absolute_import, print_function 5 | from geocoder.bing_batch import BingBatch, BingBatchResult 6 | 7 | import io 8 | import csv 9 | import sys 10 | 11 | PY2 = sys.version_info < (3, 0) 12 | csv_io = io.BytesIO if PY2 else io.StringIO 13 | csv_encode = (lambda input: input) if PY2 else (lambda input: input.encode('utf-8')) 14 | csv_decode = (lambda input: input) if PY2 else (lambda input: input.decode('utf-8')) 15 | 16 | 17 | class BingBatchReverseResult(BingBatchResult): 18 | 19 | @property 20 | def address(self): 21 | address = self._content 22 | if address: 23 | return address[0] 24 | 25 | @property 26 | def city(self): 27 | city = self._content 28 | if city: 29 | return city[1] 30 | 31 | @property 32 | def postal(self): 33 | postal = self._content 34 | if postal: 35 | return postal[2] 36 | 37 | @property 38 | def state(self): 39 | state = self._content 40 | if state: 41 | return state[3] 42 | 43 | @property 44 | def country(self): 45 | country = self._content 46 | if country: 47 | return country[4] 48 | 49 | @property 50 | def ok(self): 51 | return bool(self._content) 52 | 53 | def debug(self, verbose=True): 54 | with csv_io() as output: 55 | print('\n', file=output) 56 | print('Bing Batch result\n', file=output) 57 | print('-----------\n', file=output) 58 | print(self._content, file=output) 59 | 60 | if verbose: 61 | print(output.getvalue()) 62 | 63 | return [None, None] 64 | 65 | 66 | class BingBatchReverse(BingBatch): 67 | 68 | method = 'batch_reverse' 69 | _RESULT_CLASS = BingBatchReverseResult 70 | 71 | def generate_batch(self, locations): 72 | out = csv_io() 73 | writer = csv.writer(out) 74 | writer.writerow([ 75 | 'Id', 76 | 'ReverseGeocodeRequest/Location/Latitude', 77 | 'ReverseGeocodeRequest/Location/Longitude', 78 | 'GeocodeResponse/Address/FormattedAddress', 79 | 'GeocodeResponse/Address/Locality', 80 | 'GeocodeResponse/Address/PostalCode', 81 | 'GeocodeResponse/Address/AdminDistrict', 82 | 'GeocodeResponse/Address/CountryRegion' 83 | ]) 84 | 85 | for idx, location in enumerate(locations): 86 | writer.writerow([idx, location[0], location[1], None, None, None, None, None]) 87 | 88 | return csv_encode("Bing Spatial Data Services, 2.0\n{}".format(out.getvalue())) 89 | 90 | def _adapt_results(self, response): 91 | # print(type(response)) 92 | result = csv_io(csv_decode(response)) 93 | # Skipping first line with Bing header 94 | next(result) 95 | 96 | rows = {} 97 | for row in csv.DictReader(result): 98 | rows[row['Id']] = [ 99 | row['GeocodeResponse/Address/FormattedAddress'], 100 | row['GeocodeResponse/Address/Locality'], 101 | row['GeocodeResponse/Address/PostalCode'], 102 | row['GeocodeResponse/Address/AdminDistrict'], 103 | row['GeocodeResponse/Address/CountryRegion'] 104 | ] 105 | 106 | return rows 107 | 108 | 109 | if __name__ == '__main__': 110 | g = BingBatchReverse([(40.7943, -73.970859), (48.845580, 2.321807)], key=None) 111 | g.debug() 112 | -------------------------------------------------------------------------------- /geocoder/geonames_details.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | 3 | from geocoder.geonames import GeonamesQuery, GeonamesResult 4 | 5 | 6 | class GeonamesFullResult(GeonamesResult): 7 | """ Get more information for given geonames_id, e.g timzone and administrative hierarchy""" 8 | 9 | @property 10 | def continent(self): 11 | return self.raw.get('continentCode', "") 12 | 13 | @property 14 | def country_geonames_id(self): 15 | return self.raw.get('countryId', 0) 16 | 17 | @property 18 | def state_geonames_id(self): 19 | return self.raw.get('adminId1', 0) 20 | 21 | @property 22 | def admin2(self): 23 | return self.raw.get('adminName2', "") 24 | 25 | @property 26 | def admin2_geonames_id(self): 27 | return self.raw.get('adminId2', "") 28 | 29 | @property 30 | def admin3(self): 31 | return self.raw.get('adminName3', "") 32 | 33 | @property 34 | def admin3_geonames_id(self): 35 | return self.raw.get('adminId3', "") 36 | 37 | @property 38 | def admin4(self): 39 | return self.raw.get('adminName4', "") 40 | 41 | @property 42 | def admin4_geonames_id(self): 43 | return self.raw.get('adminId4', "") 44 | 45 | @property 46 | def admin5(self): 47 | return self.raw.get('adminName5', "") 48 | 49 | @property 50 | def admin5_geonames_id(self): 51 | return self.raw.get('adminId5', "") 52 | 53 | @property 54 | def srtm3(self): 55 | return self.raw.get('srtm3', 0) 56 | 57 | @property 58 | def wikipedia(self): 59 | return self.raw.get('wikipediaURL', "") 60 | 61 | @property 62 | def timeZoneId(self): 63 | timezone = self.raw.get('timezone') 64 | if timezone: 65 | return timezone.get('timeZoneId') 66 | 67 | @property 68 | def timeZoneName(self): 69 | timezone = self.raw.get('timezone') 70 | if timezone: 71 | return timezone.get('timeZoneId') 72 | 73 | @property 74 | def rawOffset(self): 75 | timezone = self.raw.get('timezone') 76 | if timezone: 77 | return timezone.get('gmtOffset') 78 | 79 | @property 80 | def dstOffset(self): 81 | timezone = self.raw.get('timezone') 82 | if timezone: 83 | return timezone.get('dstOffset') 84 | 85 | @property 86 | def bbox(self): 87 | bbox = self.raw.get('bbox', {}) 88 | south = bbox.get('south') 89 | west = bbox.get('west') 90 | north = bbox.get('north') 91 | east = bbox.get('east') 92 | return self._get_bbox(south, west, north, east) 93 | 94 | 95 | class GeonamesDetails(GeonamesQuery): 96 | """ Details: 97 | http://api.geonames.org/getJSON?geonameId=6094817&style=full 98 | """ 99 | 100 | provider = 'geonames' 101 | method = 'details' 102 | 103 | _URL = 'http://api.geonames.org/getJSON' 104 | _RESULT_CLASS = GeonamesFullResult 105 | 106 | def _build_params(self, location, provider_key, **kwargs): 107 | """Will be overridden according to the targetted web service""" 108 | return { 109 | 'geonameId': location, 110 | 'username': provider_key, 111 | 'style': 'full' 112 | } 113 | 114 | def _adapt_results(self, json_response): 115 | # the returned JSON contains the object. 116 | # Need to wrap it into an array 117 | return [json_response] 118 | 119 | 120 | if __name__ == '__main__': 121 | c = GeonamesDetails(6094817) 122 | c.debug() 123 | --------------------------------------------------------------------------------