Easy IP-to-country lookup in Python
We’re branching into the U.S. market with our wedding registry website, Gifty. So first we grabbed a .com
domain name, but we also had to make sure the price shows correctly in USD or NZD depending on where you’re from.
There are a number of tools available for geo-locating someone based on their IP address, including some free ones. MaxMind is pretty popular and nice to use, and their free GeoLite Country database did the trick for me.
Gifty runs on Python, so I wanted something I could just use in pure Python. It turns out that pygeoip is a nice Python replacement for MaxMind’s C-based API.
However, I was only interested in the country-code lookup, so I decided to strip it down and release the two-pages-of-Python version I’m using. Just grab MaxMind’s database and put the code in Python’s Lib/site-packages
directory:
And then to use it, simply type:
>>> import geoip
>>> geoip.country('202.21.128.102')
'NZ'
10 July 2009 by Ben 7 comments
7 comments (oldest first)
Cheers, David. Yeah, I knew about MaxMind’s HTTP-based GeoIP service, and it’s nice and easy. However, it’s slow, and because I need to do an IP-to-country lookup on every page load, it needs to be fast.
With the offline database and geoip.py, I can do 3000 lookups per second on my machine, which is fast enough for me. :-)
Oh! Oooohhh, ok. I do it once, on account creation…
If your method works quickly and is relaiable then there’s no point in change.
Nice article man! Just like to point out there is a nice mashup of google maps with Geolocation (Ip to Country) which i use often here: http://www.astalavista.com/index.php?app=onlinetools&module=ipinfo
This is awesome. So much faster doing it locally than having to query a remote source.
Awesome tool! I wrote some convenience functions for performance benefits and also automated the updating of the”GeoIP Lite Country” database:
__geoip_cache = {}
def country(ip, dbname='GeoIP.dat', cache=True, update=True):
"""Helper function that creates a GeoIP instance and calls country()."""
g = None
if cache: g = __geoip_cache.get(dbname)
if g is None:
if update_db:
update_db(dbname=dbname)
g = GeoIP(dbname)
__geoip_cache[dbname] = g
return g.country(ip)
def update_db(src='http://geolite.maxmind.com/download/geoip/database/GeoLiteCountry/GeoIP.dat.gz', dbname='GeoIP.dat', thresh=None):
import os.path, datetime
thresh = thresh or datetime.timedelta(days=7)
try:
mod_time = datetime.datetime.fromtimestamp(os.path.getctime(dbname))
except OSError: mod_time = None
cur_time = datetime.datetime.now()
if not mod_time or cur_time-mod_time > thresh:
import requests
r = requests.get(src)
data = r.content
if src.endswith(".gz"):
import gzip, StringIO #io.StringIO doesn't seem to do the job. StringIO.StringIO is legacy.
s = StringIO.StringIO(data)
data = gzip.GzipFile(fileobj=s).read()
open(dbname, "wb").write(data)
FWIW you can do it without anything other than standard libraries. This example from a django project: