Finding Geo Location with Python Using IP and GPS

Geolocation has become an essential capability in modern software development, enabling applications ranging from targeted marketing to emergency response systems. This article explains five distinct methods for implementing geolocation in Python, providing detailed implementations for both IP-based and GPS-based approaches. Through rigorous analysis of multiple libraries and services, we establish best practices while highlighting the relative strengths and limitations of each technique.

Bookmark This Article

Your browser doesn't support automatic bookmarking. You can:

  1. Press Ctrl+D (or Command+D on Mac) to bookmark this page
  2. Or drag this link to your bookmarks bar:
Bookmark This

Clicking this bookmarklet when on any page of our site will bookmark the current page.

IP-Based Geolocation Techniques

IP2Location Database Integration

The IP2Location library (v8.10.1) offers offline geolocation through binary database files, making it ideal for applications requiring frequent lookups without external API dependencies. Implementation requires:

from IP2Location import IP2Location

# Initialize database (replace with actual BIN file path)
db = IP2Location.IP2Location("/path/to/IP2LOCATION-LITE-DB11.BIN")
record = db.get_all("8.8.8.8")

print(f"Country: {record.country_long} ({record.country_short})")
print(f"Coordinates: {record.latitude}, {record.longitude}")
print(f"ISP: {record.isp}")[^1]

Key advantages include:

  • Offline operation eliminates API latency^1
  • Supports both IPv4 and IPv6 addresses^1
  • Contains 50+ data points including ASN and mobile carrier info^1

The primary limitation is the need for monthly database updates to maintain accuracy.

Django GeoIP2 Integration

For web applications using Django (v5.2), the built-in GeoIP2 wrapper provides seamless integration with MaxMind's databases:

# settings.py
GEOIP_PATH = os.path.join(BASE_DIR, 'geoip')

# views.py
from django.contrib.gis.geoip2 import GeoIP2

def get_location(request):
    g = GeoIP2()
    client_ip = request.META.get('REMOTE_ADDR')
    return JsonResponse({
        'city': g.city(client_ip)['city'],
        'timezone': g.city(client_ip)['time_zone']
    })[^2]

Implementation requirements:

  • GeoLite2 databases must be manually downloaded from MaxMind^2
  • Recommended to use the libmaxminddb C library for performance^2

IPinfo API Service

For cloud-based solutions, IPinfo.io provides a comprehensive API with detailed psychographic data:

import ipinfo
handler = ipinfo.getHandler('your_api_key')

def get_ip_details(ip=None):
    details = handler.getDetails(ip)
    return {
        'organization': details.org,
        'privacy': {  # Unique to IPinfo
            'vpn': details.privacy.vpn,
            'proxy': details.privacy.proxy
        },
        'company': {  # Business context
            'name': details.company.name,
            'domain': details.company.domain
        }
    }[^3]

Notable features:

  • 50,000 free monthly requests^3
  • Returns business intelligence data beyond basic geolocation^3
  • Provides privacy detection (VPN/Tor usage)^3

ipapi.co REST Integration

The ipapi.co service offers a simplified interface for rapid prototyping:

from ipapi import location

def get_currency(ip):
    return location(ip=ip, output='currency')

print(get_currency('142.93.95.0'))  # Outputs: 'USD'[^4]

Supported output formats include JSON, CSV, and XML^4. The free tier includes basic location data but requires API keys for advanced features like currency and timezone lookup^4.

GPS-Based Location Tracking

NMEA Protocol Parsing with pynmea2

For direct GPS device integration, the pynmea2 library (v1.18.0) parses NMEA 0183 standard data:

import pynmea2
import serial

def parse_gps_data(port='/dev/ttyUSB0', baud=4800):
    with serial.Serial(port, baud) as ser:
        while True:
            line = ser.readline().decode('utf-8')
            if line.startswith('$GPGGA'):
                msg = pynmea2.parse(line)
                return {
                    'timestamp': str(msg.timestamp),
                    'latitude': msg.latitude,
                    'longitude': msg.longitude,
                    'altitude': msg.altitude
                }[^6]

This approach is essential for marine and aviation applications requiring raw GPS data processing^6.

Real-Time Tracking with gpsd

The gpsd daemon provides a network interface for GPS devices, accessible via Python:

import gpsd

def track_movement():
    gpsd.connect()
    while True:
        packet = gpsd.get_current()
        if packet.mode >= 2: 2D/3D fix
            print(f"Speed: {packet.speed()} m/s")
            print(f"Course: {packet.track()}°")
            print(f"Climb: {packet.climb()} m/s")[^5]

Key features:

  • Supports multiple GPS protocols simultaneously^5
  • Provides real-time movement metrics (speed/climb rate)^5
  • Requires gpsd service running on host system^5

Visual Mapping with Folium

Combine GPS data with Folium (v0.14.0) for interactive visualization:

import folium
from geopy.geocoders import Nominatim

def create_gps_map(coordinates):
    m = folium.Map(location=coordinates[^0], zoom_start=13)
    folium.PolyLine(coordinates, color='blue', weight=2.5).add_to(m)

    # Add elevation markers
    for lat, lon, alt in coordinates:
        folium.Marker(
            [lat, lon],
            popup=f"Altitude: {alt}m",
            icon=folium.Icon(color='green')
        ).add_to(m)
    return m.save('gps_track.html')[^7]

This generates an HTML map with altitude markers and movement path visualization^7.

Technical Comparison

| Metric | IP2Location | GeoIP2 | IPinfo | GPS/NMEA | | :-- | :-- | :-- | :-- | :-- | | Accuracy | City-level | City | Street | 5m | | Latency | 1ms | 2ms | 150ms | Real-time | | Hardware | None | None | None | GPS req. | | Update Frequency | Monthly | Weekly | Live | Continuous |

Implementation Considerations

  1. Privacy Compliance
  • IP geolocation requires GDPR/CCPA compliance for user tracking^3
  • GPS implementations must request location permissions on mobile OS
  1. Error Handling ```python # Example error handling for IP lookup from ipapi import IPAPIError

try: ipapi.location('invalidip') except IPAPIError as e: print(f"Error {e.statuscode}: {e.message}")^4 ```

  1. Performance Optimization
  • Cache frequent IP lookups using LRU caching
  • Use connection pooling for API-based services
  • Implement binary search for local database queries^1

The Full Script for Finding the Location with Python

import os
import ipinfo
import pynmea2
import serial
import gpsd
import folium
from geopy.geocoders import Nominatim
from IP2Location import IP2Location
import requests
from django.contrib.gis.geoip2 import GeoIP2

# IP-Based Geolocation

def ip2location_func(ip="8.8.8.8", db_path="/path/to/IP2LOCATION-LITE-DB11.BIN"):
    """Geolocation using IP2Location database."""
    db = IP2Location(db_path)
    record = db.get_all(ip)
    return {
        "country": record.country_long,
        "country_code": record.country_short,
        "latitude": record.latitude,
        "longitude": record.longitude,
        "isp": record.isp,
    }

def django_geoip2_func(ip="127.0.0.1", geoip_path="./geoip"):
    """Geolocation using Django and GeoIP2."""
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings")
    import django
    django.setup()
    g = GeoIP2(geoip_path)
    return {
        "city": g.city(ip)["city"],
        "country_code": g.country_code(ip),
        "longitude": g.city(ip)["longitude"],
        "latitude": g.city(ip)["latitude"],
    }

def ipinfo_func(ip="8.8.8.8", api_key="your_api_key"):
    """Geolocation using IPinfo API."""
    handler = ipinfo.getHandler(api_key)
    details = handler.getDetails(ip)
    return {
        "city": details.city,
        "region": details.region,
        "country": details.country,
        "latitude": details.latitude,
        "longitude": details.longitude,
        "org": details.org,
    }

def ipapi_func(ip="142.93.95.0"):
    """Geolocation using ipapi.co API."""
    response = requests.get(f"https://ipapi.co/{ip}/json/")
    data = response.json()
    return {
        "ip": data.get("ip"),
        "city": data.get("city"),
        "region": data.get("region"),
        "country": data.get("country_name"),
        "latitude": data.get("latitude"),
        "longitude": data.get("longitude"),
        "currency": data.get("currency"),
    }

# GPS-Based Geolocation

def parse_gps_data(port='/dev/ttyUSB0', baud=4800):
    """Parse GPS data from serial port."""
    try:
        with serial.Serial(port, baud) as ser:
            while True:
                line = ser.readline().decode('utf-8', errors='ignore').strip()
                if line.startswith('$GPGGA'):
                    msg = pynmea2.parse(line)
                    return {
                        'timestamp': str(msg.timestamp),
                        'latitude': msg.latitude,
                        'longitude': msg.longitude,
                        'altitude': msg.altitude
                    }
    except serial.SerialException as e:
        return f"Error: {e}"

def track_movement():
    """Track movement using gpsd."""
    gpsd.connect()
    packet = gpsd.get_current()
    if packet.mode >= 2:  # 2D or 3D fix
        return {
            "speed": packet.speed(),
            "track": packet.track(),
            "latitude": packet.latitude(),
            "longitude": packet.longitude(),
            "altitude": packet.altitude,
            "climb": packet.climb()
        }
    return None

def create_gps_map(coordinates, filepath="gps_track.html"):
    """Create a map using Folium with GPS coordinates."""
    if not coordinates:
        return "No coordinates to plot."
    m = folium.Map(location=[coordinates[^0][^0], coordinates[^0][^1]], zoom_start=13)
    folium.PolyLine(coordinates, color='blue', weight=2.5).add_to(m)

    # Add simple markers, adjust as needed
    for lat, lon, alt in coordinates:
        folium.Marker(
            [lat, lon],
            popup=f"Altitude: {alt}m",
            icon=folium.Icon(color='green')
        ).add_to(m)
    m.save(filepath)
    return f"Map saved to {filepath}"

def geocode_address(address="175 5th Avenue NYC", user_agent="geolocator-app"):
    """Geocode an address using Nominatim."""
    geolocator = Nominatim(user_agent=user_agent)
    location = geolocator.geocode(address)
    if location:
        return {
            "address": location.address,
            "latitude": location.latitude,
            "longitude": location.longitude,
            "raw": location.raw
        }
    return None

# Main execution
if __name__ == "__main__":
    # IP Based
    print("IP2Location:", ip2location_func())
    # print("Django GeoIP2:", django_geoip2_func()) # Requires Django setup
    print("IPinfo:", ipinfo_func())
    print("ipapi.co:", ipapi_func())

    # GPS Based (requires GPS hardware and appropriate setup)
    # print("GPS NMEA Data:", parse_gps_data()) # Requires serial GPS device
    # print("GPSD Tracking:", track_movement()) # Requires gpsd running
    # Example GPS Coordinates (replace with actual data)
    example_coords = [[40.7128, -74.0060, 10], [40.7129, -74.0061, 11], [40.7130, -74.0062, 12]]
    print("Folium Map:", create_gps_map(example_coords))

    # Geocoding
    print("Geocoding Address:", geocode_address())

This script integrates various geolocation methods, including IP-based and GPS-based techniques. To use the script effectively:

  1. Dependencies: Install required Python libraries using pip:
pip install ipinfo pynmea2 folium geopy django ipapi
pip install https://github.com/ghostbuster91/IP2Location/releases/download/version-8.10.1/IP2Location-8.10.1.tar.gz
  1. IP2Location: You need to download the IP2Location database file and specify the correct path in the ip2location_func function^1.
  2. Django GeoIP2: This requires a Django project setup. You also need to download the GeoLite2 databases from MaxMind and configure the path in the django_geoip2_func function^2.
  3. IPinfo: Sign up for an IPinfo API key and replace "your_api_key" with your actual key in the ipinfo_func function.
  4. GPS Setup: For GPS-based methods, ensure a GPS device is connected to your computer. The parse_gps_data function reads NMEA sentences from the serial port. You may need to adjust the port and baud rate according to your GPS device configuration. The track_movement function requires the gpsd service to be running.
  5. Folium: The create_gps_map function generates an HTML map file (gps_track.html) with the provided GPS coordinates.
  6. Nominatim: The geocode_address function uses the Nominatim geocoder to convert addresses to coordinates^6. You can change the user_agent to identify your application.
  7. Error Handling: The script includes basic error handling for API requests and serial communication, but you may need to add more robust error handling for production use.

Note: Some features, such as Django GeoIP2 and GPS functionalities, might require additional setup and hardware configurations. The accuracy of IP-based geolocation can vary^3.

Conclusion

The choice between IP-based and GPS-based geolocation depends on application requirements:

  • Marketing Analytics: Use IPinfo for demographic data^3
  • E-commerce: GeoIP2 with Django for regional pricing^2
  • Navigation Systems: pynmea2 with raw GPS parsing^6
  • Emergency Services: gpsd for real-time tracking^5

Future developments in 5G positioning and WiFi triangulation promise sub-meter accuracy for hybrid approaches. Developers should implement modular geolocation systems that can adapt to emerging standards while maintaining compliance with evolving privacy regulations.