Skip to content

Instantly share code, notes, and snippets.

@sbp
Created August 13, 2012 13:04
Show Gist options
  • Save sbp/3340491 to your computer and use it in GitHub Desktop.
Save sbp/3340491 to your computer and use it in GitHub Desktop.
Get a list of Wikipedia articles near a location
#!/usr/bin/env python
import sys, re, urllib
from decimal import Decimal as dec
def error(message):
print message
sys.exit(1)
def parse_lat_lon_string(lat_lon):
lat, lon = lat_lon.split(',', 1)
lat, lon = lat.strip(), lon.strip()
lat, lon = dec(lat), dec(lon)
if not (dec(-90) <= lat <= dec(90)):
raise ValueError("Latitude not within -90 to 90 inclusive")
if not (dec(-180) <= lon <= dec(180)):
raise ValueError("Longitude not within -180 to 180 inclusive")
return lat, lon
r_string = re.compile(r'("(\\.|[^"\\])*")')
r_json = re.compile(r'^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]+$')
env = {'__builtins__': None, 'null': None, 'true': True, 'false': False}
def json(text):
"""Evaluate JSON text safely (we hope)."""
if r_json.match(r_string.sub('', text)):
text = r_string.sub(lambda m: 'u' + m.group(1), text)
return eval(text.strip(' \t\r\n'), env, {})
raise ValueError('Input must be serialised JSON.')
def distance(d):
if d.endswith("m"):
try: dist = float(d[:-1])
except: return d
if dist > 99:
return str(round(dist / 1000, 1)) + "km"
return d
def wikilocation(lat_lon, locale="en"):
try: lat, lon = parse_lat_lon_string(lat_lon)
except Exception, e:
error("Couldn't parse lat,lon input. Python says: %s" % e)
data = {
"locale": locale,
"lat": lat,
"lng": lon,
"radius": 20000,
"limit": 36
}
query = urllib.urlencode(data)
service = "http://api.wikilocation.org/articles"
u = urllib.urlopen("?".join((service, query)))
bytes = u.read()
u.close()
# articles = json.loads(bytes)
articles = json(bytes)
results = []
seen = set()
for article in articles["articles"]:
result = article["title"] + " (" + distance(article["distance"]) + ")"
seen_result = article["title"].strip("0123456789- ")
if not (seen_result in seen):
results.append(result)
seen.add(seen_result)
response = ""
while (len(response) < 360) and results:
response += results[0] + ", "
results = results[1:]
return response.rstrip(", ")
def wikby(args):
if args.startswith(":"):
locale, lat_lon = args.split(" ", 1)
locale = locale.lstrip(":")
else: locale, lat_lon = "en", args
print wikilocation(lat_lon, locale=locale)
# e.g. wikby("51.500688, -0.124411")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment