2014-12-27 4 views
0

У меня есть файл CSV, где диапазоны IP хранятся вместе с их landcode:Возвращаясь код страны IP-адрес

"1.0.0.0","1.0.0.255","16777216","16777471","AU","Australia" 
"1.0.1.0","1.0.3.255","16777472","16778239","CN","China" 
"1.0.4.0","1.0.7.255","16778240","16779263","AU","Australia" 
"1.0.8.0","1.0.15.255","16779264","16781311","CN","China" 

Это можно прочитать так:

range_start, range_stop, ignored, ignored, country_code, country_name 

Когда пользователь запрашивает конкретный IP-адрес, я хочу вернуть ему код страны, соответствующий этому IP-адресу. Вот, например, 1.0.9.10 вернутся CN для Китая, потому что между 1.0.8.0 и 1.0.15.255.

Я не знаю, как с этим справиться. Вот то, что я сделал до сих пор, но я сомневаюсь, что я нахожусь в правильном направлении:

import csv 

with open("GeoIPCountryWhois.csv") as csvfile: 

readCSV = csv.reader(csvfile, delimiter = ",") 

IP_LOWs = [] 
IP_HIGHs = [] 
Land_CODEs = [] 
Lands = [] 

for row in readCSV: 
    IP_LOW = row[0] 
    IP_HIGH = row[1] 
    Land_CODE = row[4] 
    Land = row[5] 

    IP_LOWs.append(IP_LOW) 
    IP_HIGHs.append(IP_HIGH) 
    Land_CODEs.append(Land_CODE) 
    Lands.append(Land) 

whatIP = input("What IP should be looked up? ") 

codedex = IP_LOWs.index(whatIP) 
landdex = Lands.index(whatIP) 
IP_to_Code = Land_CODE[codedex] 
IP_to_land = Land[landdex] 

print(IP_to_Code) 
print(IP_to_land) 
+0

Добавить блок отступа после 'с открытым (" GeoIPCountryWhois.csv ") как csvfile' :) –

+2

Почему вы игнорируете столбцы 3 и 4? Это числовые эквиваленты начального и конечного IP. Вы должны преобразовать входной IP в число и сравнить их с этими диапазонами. См. Http://stackoverflow.com/questions/9590965/convert-an-ip-string-to-a-number-and-vice-versa – Barmar

ответ

0

Вы можете использовать библиотеку netaddr при работе с IP-адресами.

from netaddr import * 
IPAddress("1.0.3.255")>IPAddress("1.1.2.1") 
#False 

Затем вы можете использовать что-то вроде:

Примечание: Ниже код не тестировался, так как у меня нет данных. Возможно, вам придется внести незначительные изменения, чтобы фактически запустить код. Если у вас возникнет какая-либо ошибка при запуске, отправьте ее здесь, я попытаюсь исправить ситуацию.

import csv 
from netaddr import * 
with open("GeoIPCountryWhois.csv") as csvfile: 

    readCSV = csv.reader(csvfile, delimiter = ",") 

    whatIP = input("What IP should be looked up? ") 

    for row in readCSV: 
     IP_LOW = IPAddress(row[0])  
     IP_HIGH = IPAddress(row[1]) 
     Land = row[4] 

     if IPAddress(whatIP)>=IP_LOW and IPAddress(whatIP)<=IP_HIGH: 
      print Land 
+0

В нем есть ошибка: "netaddr.core.AddrFormatError: не удалось обнаружить действительный IP-адрес от «.0.0.» « –

+0

В нем работают отличные резервуары! :) –

1

Используя код из Convert an IP string to a number and vice versa, вы можете преобразовать входной IP в число. Затем вы можете сравнить его с числовой версией IP-адреса start/end, которые находятся в столбцах 3 и 4 CSV.

import csv 

with open("GeoIPCountryWhois.csv") as csvfile: 

    readCSV = csv.reader(csvfile, delimiter = ",") 

    GeoIPs = [] 

    for row in readCSV: 
     GeoIPs.append({ low: row[2], high: row[3], land_code: row[4], land: row[5] }) 

    whatIP = input("What IP should be looked up? ") 
    whatIP_long = ip2long(whatIP)   
    found_range = next((GeoIP for GeoIP in GeoIPs if GeoIP.low <= whatIP_long <= GeoIP.high), None) 
    if found_range: 
     IP_to_Code = found_range.land_code 
     IP_to_land = found_range.land 

    print(IP_to_Code) 
    print(IP_to_land) 
0

Немного не связанный с вопросом, но изобретать колесо заставило меня бросить мои два цента. Если это не домашняя работа или учебный проект, вы можете использовать GeoIP + бесплатную базу данных MaxMind (или платную версию). Код стабилен, проверен и готов к использованию в производстве.

Пример:

# 
from pygeoip import GeoIP, MEMORY_CACHE 
# 
try: 
    import win_inet_pton#patches socket library for Windows use 
except ImportError: 
    pass 
import socket 

############################################################################### 

def is_valid_ipv4(ip_str): 
    """ 
    Check the validity of an IPv4 address 
    """ 
    try: 
     socket.inet_pton(socket.AF_INET, ip_str)#@UndefinedVariable 
    except AttributeError: 
     try: 
      socket.inet_aton(ip_str) 
     except socket.error: 
      return False 
     return ip_str.count('.') == 3 
    except socket.error: 
     return False 
    return True 

def is_valid_ipv6(ip_str): 
    """ 
    Check the validity of an IPv6 address 
    """ 
    try: 
     socket.inet_pton(socket.AF_INET6, ip_str)#@UndefinedVariable 
    except socket.error: 
     return False 
    return True 

############################################################################### 

def get_country_from_ip(ip): 

    geo_record = None 

    if is_valid_ipv4(ip): 
     geo_country_ipv4_db = GeoIP('[path/to/dat/file]GeoLiteCity.dat', MEMORY_CACHE) 
     geo_record = geo_country_ipv4_db.record_by_addr(ip) 

    if is_valid_ipv6(ip): 
     geo_country_ipv6_db = GeoIP('[path/to/dat/file]GeoLiteCityv6.dat', MEMORY_CACHE) 
     geo_record = geo_country_ipv6_db.record_by_addr(ip) 

    if geo_record: 
     return geo_record.get('country_code', '').lower() 

    return None 

############################################################################### 

print get_country_from_ip('1.0.9.10') 

Требования:

Связанный:

Regexp to check if an IP is valid

Установите необходимые расширения, замените "[путь// DAT/файла]", и вы сделали.

0

Предполагая, что вы работаете только с адресами IPV4, конвертируйте из десятичных знаков с десятичной точностью в свой 32-разрядный эквивалент. Теперь это вопрос поиска местоположения с использованием 32-битных IP-адресов, предоставленных в исходном файле в столбцах 3 и 4.

Если вы будете выполнять множественный поиск, хорошей структурой данных для использования является отсортированный список. Поиск может выполняться с использованием алгоритма деления пополам, предусмотренного в модуле bisect.

Обратите внимание на наличие пробелов в исходных данных GeoIPCountryWhois.csv для нераспределенных IP-адресов или этих IP-адресов в частном диапазоне адресов, поэтому требуется небольшое предварительное массирование данных. Вот это класс, который загружает данные из файла, заполняет любые пробелы, и использует bisect_left() для выполнения поиска:

import csv 
import socket 
import struct 

from bisect import bisect_left 

def ip2long(ip): 
    """ 
    Convert an IP string to long (see http://stackoverflow.com/a/9591005/21945) 
    """ 
    packedIP = socket.inet_aton(ip) 
    return struct.unpack("!L", packedIP)[0] 


class GeoIPCountry(object): 
    def __init__(self, geoips_file): 
     """ 
     Load IP range location map from CSV file filling in any empty ranges as 
     we go. Assumes that the data in geoips_file is sorted by IP address. 
     """ 
     r = csv.reader(geoips_file) 
     self.geoips = [] 
     last_hi = 0 
     for row in r: 
      if int(row[2]) != last_hi+1: 
       self.geoips.append((last_hi+1, int(row[2])-1, None, None)) 
      self.geoips.append((int(row[2]), int(row[3]), row[4], row[5])) 
      last_hi = int(row[3]) 
     if last_hi < ip2long('255.255.255.255'): 
      self.geoips.append((last_hi+1, ip2long('255.255.255.255'), None, None)) 
     self.keys = [geoip[1] for geoip in self.geoips] 
#  assert sorted(self.keys) == self.keys 

    def lookup_country(self, ip_address): 
     """ 
     Return tuple of country code and country name for an IP address. 
     """ 
     return self.geoips[bisect_left(self.keys, ip2long(ip_address))][-2:] 


if __name__ == '__main__': 
    with open('GeoIPCountryWhois.csv') as geoips_file: 
     geoip = GeoIPCountry(geoips_file) 

    for ip_address in ('0.1.2.3', '1.2.3.4', '192.168.1.1', '203.123.4.23', 
         '123.132.123.123', '223.255.255.255', '255.255.255.255'): 
     country = geoip.lookup_country(ip_address) 
     if country[0] is not None: 
      print "{:<15} -> {} ({})".format(ip_address, country[1], country[0]) 
     else: 
      print "{:<15} -> unknown".format(ip_address) 

Выход

 
0.1.2.3   -> unknown 
1.2.3.4   -> United States (US) 
192.168.1.1  -> unknown 
203.123.4.23 -> Singapore (SG) 
123.132.123.123 -> China (CN) 
223.255.255.255 -> Australia (AU) 
255.255.255.255 -> unknown 
0

Вы можете использовать IP Найти для этого.

import urllib, json 
url = 'https://ipfind.co/?auth=ip=' + ip_address; 
response = urllib.urlopen(url) 
data = json.loads(response.read()) 

Это вернет объект JSON со кодом страны ISO в качестве собственности.

Смежные вопросы