1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
|
#!/usr/bin/env python3
"""Wrapper around US Census address geocoder API described here:
https://www2.census.gov/geo/pdfs/maps-data/data/Census_Geocoder_User_Guide.pdf"""
import logging
import re
from typing import Dict, Optional
import requests
from bs4 import BeautifulSoup
from requests.utils import quote
logger = logging.getLogger(__name__)
def geocode_address(address: str) -> Optional[Dict[str, str]]:
"""Send a single address to the US Census geocoding API.
>>> out = geocode_address('5 Shelbern Dr,,, 07738')
>>> out['Matched Address']
'5 SHELBERN DR, LINCROFT, NJ, 07738'
"""
encoded_address = quote(address)
url = 'https://geocoding.geo.census.gov/geocoder/geographies/onelineaddress'
url += f'?address={encoded_address}'
url += '&layers=all&benchmark=4&vintage=4'
logger.debug('GET: %s', url)
r = requests.get(url)
if r.status_code != 200:
logger.error(f'Unexpected response code {r.status_code}, wanted 200. Fail.')
return None
else:
soup = BeautifulSoup(r.text, 'html.parser')
result = soup.find('div', id='pl_gov_census_geo_geocoder_domain_AddressResult')
logger.debug('Unhelpful result blurb: "%s"', result)
output = result.get_text('\n')
label = None
out = {}
for line in output.split('\n'):
if re.match(r'.*: *$', line):
label = line[:-2].strip()
logger.debug('Label is: "%s"', label)
else:
if label:
out[label] = line.strip()
logger.debug('Value is: "%s"', out[label])
return out
if __name__ == '__main__':
import doctest
doctest.testmod()
|