Geolocation of IP’s

Photo by henry perks on Unsplash

There are lots of libraries and examples out there.

Here I’m use code from https://ipinfo.io .They want you to register, you can make 50,000 calls a month, you get a token (I’ve obfuscated mine below).

import ipinfo
access_token = 'XXXXXXXf0a5b6'
handler = ipinfo.getHandler(access_token)
details = handler.getDetails("212.239.36.212")
print ("%s,%s,%s,%s,%s" % (details.ip,details.city,details.country,
                        details.longitude, details.latitude))

./geo4.py
216.239.36.21,Mountain View,US,-122.0775,37.4056

Obviously now I’m excited about plotting that latitude and longitude on a map. I could read in IP’s from my apache access_logs into an array and plot them all.

IP’s locations plotted from apache off aardvark yesterday
#!/usr/bin/env python3
from mpl_toolkits.basemap import Basemap
import matplotlib.pyplot as plt
import requests
import time
from math import *
import ipinfo
import sys

handler = ipinfo.getHandler(cache_options={'ttl':30, 'maxsize': 128})
ip_lat = ip_lan = 0

def get_ip_position(ip_address):
  access_token = 'XXXXXX8f0a5b6' 
  handler = ipinfo.getHandler(access_token)
  details = handler.getDetails(ip_address)
  return float(details.latitude),float(details.longitude)

fig = plt.figure(figsize=(20,8))
m = Basemap(projection='cyl')
m.etopo()

ips = []
with open('list_of_ips') as my_file:
    for line in my_file:
        ips.append(line.strip())
print(ips)
for ip in ips:
  ip_lat, ip_lon = get_ip_position(ip)
  xpt, ypt = m(ip_lon, ip_lat)
  print(ip)
  m.plot(xpt,ypt, 'ro')

plt.savefig('iplocation.png')
plt.show()

I’m new to this, so it turns out Basemap is deprecated since 2017. We should be using Cartopy. Modifying an example by Joshua Hrisko I could plot down to street level of an IP and lookup location details like postcode using postcodes_io_api

def coord_to_postcode(x_lat,y_lon):
  api  = postcodes_io_api.Api(debug_http=False)
  data = api.get_nearest_postcodes_for_coordinates(latitude=x_lat,longitude=y_lon,limit=2)
  dict = data['result'][0]
  postcode = dict['postcode']
  label = dict['country'] + "/" + str(dict['admin_county']) + "/" + dict['parish'] + "/" + dict['postcode']
  return(postcode,label)

Google have mapping software. You have to login to their cloud platform to get a token. You get free credits so playing around shouldn’t cost you. If you get your API token set up for the right “Maps Javascript API” then you get this funky map below:

#!/usr/bin/env python3
from geopy.geocoders import GoogleV3
import gmaps
APIKEY='XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
geolocator=GoogleV3(api_key=APIKEY)
name = "Albert Hall"
location = geolocator.geocode(name)
print(location.address)
my_coordinates = (location.latitude, location.longitude)
gmaps.configure(api_key=APIKEY)
gmaps.figure(center=my_coordinates, zoom_level=12)

And trace an IP or IP’s location and drop a marker:

#!/usr/bin/env python3
import gmaps
import ipinfo

def get_ip_position(ip_address):
  access_token = 'XXXXXXXXXXXXX''
  handler = ipinfo.getHandler(access_token)
  details = handler.getDetails(ip_address)
  return float(details.latitude),float(details.longitude)
ip='147.197.131.119'
x_lat, y_lon = get_ip_position(ip)
APIKEY='XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX''
my_coordinates = (x_lat, y_lon)
marker_locations = [(x_lat, y_lon)]
gmaps.configure(api_key=APIKEY)
markers = gmaps.marker_layer(marker_locations)
gmaps.figure()
fig = gmaps.figure()
fig.add_layer(markers)
fig

I only got this working in Jupyter notebook. An actual .py file verison on will give me an error:

Exception ignored in: <function RequestsAdapter.__del__ at 0x7fa1cae7e550>