返回IP地址的国家/地区代码

时间:2014-12-27 11:17:30

标签: python csv python-3.4

我有一个CSV文件,其中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.01.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)

5 个答案:

答案 0 :(得分:1)

使用Convert an IP string to a number and vice versa中的代码,您可以将输入IP转换为数字。然后,您可以将其与开始/结束IP的数字版本进行比较,它们位于CSV的第3列和第4列。

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)

答案 1 :(得分:0)

您可以在处理IP地址时使用库netaddr

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

答案 2 :(得分: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

安装所需的扩展名,替换&#34; [path / to / dat / file]&#34;而且你已经完成了。

答案 3 :(得分:0)

假设您只使用IPV4地址,请将点分十进制表示法转换为32位等效表示法。现在,使用第3和第4列中源文件中提供的32位IP地址查找位置。

如果要执行多次查找,要使用的良好数据结构是排序列表。可以使用bisect模块中提供的二分算法执行查找。

请注意,对于未分配的IP地址或私有地址范围内的IP,源数据GeoIPCountryWhois.csv中存在间隙,因此需要进行少量的前期数据按摩。这是一个从文件加载数据的类,填补任何空白,并使用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

答案 4 :(得分:0)

您可以使用IP Find。

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

这将返回一个带有ISO国家/地区代码作为属性的JSON对象。