使用免費GeoLite2-City.mmdb進行IP信息解析和地理定位



通過輸入一個IP地址,解析並獲取信息,比如國家、國家代碼、省份、省份代碼、城市、郵政編碼、經緯度等等信息

例如,解析ip(128.101.101.101)的信息如下:

實現方式及區別

使用在線第三方提供的api:

  • ip-api.com
  • ip.taotao.com
  • 百度地圖api
  • 新浪 iplookup

使用離線查詢方式:

  • 純真庫
  • GeoLite2
  • 埃文科技

數據豐富度對比:

查詢准確率比較:

查詢速度比較:

總結: 需要速度用離線,需要准確率用在線,需要數據豐富性GeoLite2、埃文科技,需要免費用GeoLite2(埃文科技雖說國內頭頭,奈何收費)

python代碼實現

本文介紹使用離線的GeoLite2來解析IP獲取目標的地理位置

需要下載GeoLite2-City.mmdb,地址:https://github.com/wp-statistics/GeoLite2-City.git,並將該包解壓與下述代碼放置同一文件夾。

需要安裝geoip2模塊:pip install geoip2

import re
import geoip2.database
reader = geoip2.database.Reader('GeoLite2-City.mmdb')

# 查詢IP地址對應的物理地址
def ip_get_location(ip_address):
    # 載入指定IP相關數據
    response = reader.city(ip_address)

    #讀取國家代碼
    Country_IsoCode = response.country.iso_code
    #讀取國家名稱
    Country_Name = response.country.name
    #讀取國家名稱(中文顯示)
    Country_NameCN = response.country.names['zh-CN']
    #讀取州(國外)/省(國內)名稱
    Country_SpecificName = response.subdivisions.most_specific.name
    #讀取州(國外)/省(國內)代碼
    Country_SpecificIsoCode = response.subdivisions.most_specific.iso_code
    #讀取城市名稱
    City_Name = response.city.name
    #讀取郵政編碼
    City_PostalCode = response.postal.code
    #獲取緯度
    Location_Latitude = response.location.latitude
    #獲取經度
    Location_Longitude = response.location.longitude

    if(Country_IsoCode == None):
        Country_IsoCode = "None"
    if(Country_Name == None):
        Country_Name = "None"
    if(Country_NameCN == None):
        Country_NameCN = "None"
    if(Country_SpecificName == None):
        Country_SpecificName = "None"
    if(Country_SpecificIsoCode == None):
        Country_SpecificIsoCode = "None"
    if(City_Name == None):
        City_Name = "None"
    if(City_PostalCode == None):
        City_PostalCode = "None"
    if(Location_Latitude == None):
        Location_Latitude = "None"
    if(Location_Longitude == None):
        Location_Longitude = "None"

    print('================Start===================')
    print('[*] Target: ' + ip_address + ' GeoLite2-Located ')
    print(u'  [+] 國家編碼:        ' + Country_IsoCode)
    print(u'  [+] 國家名稱:        ' + Country_Name)
    print(u'  [+] 國家中文名稱:    ' + Country_NameCN)
    print(u'  [+] 省份或州名稱:    ' + Country_SpecificName)
    print(u'  [+] 省份或州編碼:    ' + Country_SpecificIsoCode)
    print(u'  [+] 城市名稱 :       ' + City_Name)
    print(u'  [+] 城市郵編 :       ' + City_PostalCode)
    print(u'  [+] 緯度:            ' + str(Location_Latitude))
    print(u'  [+] 經度 :           ' + str(Location_Longitude))
    print('===============End======================')


# 檢驗和處理ip地址
def seperate_ip(ip_address):
    ip_match = r"^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|0?[0-9]?[1-9]|0?[1-9]0)\.)(?:(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){2}(?:25[0-4]|2[0-4][0-9]|1[0-9][0-9]|0?[0-9]?[1-9]|0?[1-9]0)$"
    ip_match_list = r"^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|0?[0-9]?[1-9]|0?[1-9]0)\.)(?:(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){2}(?:25[0-4]|2[0-4][0-9]|1[0-9][0-9]|0?[0-9]?[1-9])-(?:25[0-4]|2[0-4][0-9]|1[0-9][0-9]|0?[0-9]?[1-9]|0?[1-9]0)$"

    if re.match(ip_match, ip_address):
        try:
            ip_get_location(ip_address)
        except Exception as e:
            print(e)
    elif re.match(ip_match_list, ip_address):
        ip_start =  ip_address.split('-')[0].split('.')[3]
        ip_end = ip_address.split('-')[1]
        # 如果ip地址范圍一樣,則直接執行
        if(ip_start == ip_end):
            try:
                seperate_ip(ip_address.split('-')[0])
            except Exception as e:
                print(e)
        elif ip_start > ip_end:
            print('the value of ip, that you input, has been wrong! try again!')
            exit(0)
        else:
            ip_num_list =  ip_address.split('-')[0].split('.')
            ip_num_list.pop()
            for ip_last in range(int(ip_start), int(ip_end)+1):
                ip_add = '.'.join(ip_num_list)+'.'+str(ip_last)
                try:
                    ip_get_location(ip_add)
                except Exception as e:
                    print(e)
    else:
        print('Wrong type of ip address!')
        print('100.8.11.58  100.8.11.58-100  alike!')
        
if __name__ == '__main__':
    seperate_ip('39.99.228.188')
    
'''
================Start===================
[*] Target: 39.99.228.188 GeoLite2-Located 
  [+] 國家編碼:        CN
  [+] 國家名稱:        China
  [+] 國家中文名稱:    中國
  [+] 省份或州名稱:    Zhejiang
  [+] 省份或州編碼:    ZJ
  [+] 城市名稱 :       Hangzhou
  [+] 城市郵編 :       None
  [+] 緯度:            30.294
  [+] 經度 :           120.1619
===============End======================
'''

django 中從META中獲取IP

ip = x_forwarded_for.split(',')[0]  # 所以這里是真實的ip
ip = request.META.get('REMOTE_ADDR')  # 這里獲得代理ip
def get_ip(request):
    """獲取訪問頁面及客戶端ip地址"""
    ip = None
    proxy_ip = None
    server_name = request.META.get('SERVER_NAME')
    if request.META.get('HTTP_X_FORWARDED_FOR'):
        ip = request.META.get("HTTP_X_FORWARDED_FOR")
        proxy_ip = request.META.get("REMOTE_ADDR")
    else:
        ip = request.META.get("REMOTE_ADDR")
    # 獲取物理地址
    try:
        address = ip_address(ip)
    except:
        address = '獲取失敗'
    # 寫入日志文件
    log_init().info(f'{server_name} {ip} {address}')
    return HttpResponse(ip)

IP地址定位查詢

@retry(stop_max_attempt_number=5)
def ip_address(ip):
    """ip地址查詢物理地址"""
    url = f'http://api.map.*****.com/location/ip?ak=*******j&ip={ip}&coor=bd09ll'
    rsp = requests.get(url, timeout=10).text
    content = json.loads(rsp)

    # 請求狀態 0有數據 1無數據
    status = content['status']
    if status:
        return content['message']
    address = content['content']['address']
    return address


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM