├── 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 |
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 |
2 |
3 |
4 |
5 |
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 |
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 |
2 |
3 |
4 |
5 |
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 | 
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 |
--------------------------------------------------------------------------------