我有一个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.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 :(得分: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对象。