

#!/usr/bin/env python 
# -*- coding: utf-8 -*- 
from bisect import bisect 
_LIST1, _LIST2 = [], [] 
_INIT = False 
ip2int = lambda ip_str: reduce(lambda a, b: (a << 8) + b, [int(i) for i in ip_str.split('.')]) 
def _init(): 
global _LIST, _INIT 
if not _INIT: 
for l in open('ipdata.txt', 'rb'): 
ip1, ip2 = l.split()[:2] 
addr = ' '.join(l.split()[2:]) 
ip1, ip2 = ip2int(ip1), ip2int(ip2) 
_LIST1.append(ip1) 
_LIST2.append((ip1, ip2, addr)) 
_INIT = True 
def ip_from(ip): 
_init() 
i = ip2int(ip) 
idx = bisect(_LIST1, i) 
assert(idx > 0) 
if len(_LIST1) <= idx: 
return u'unknown ip address %s' % ip 
else: 
frm, to ,addr = _LIST2[idx - 1] 
if frm <= i <= to: 
return addr 
else: 
return u'unknown ip address %s' % ip 
if __name__ == '__main__': 
print ip_from('115.238.54.106') 
print ip_from('220.181.29.160') 
print ip_from('115.238.54.107') 
print ip_from('8.8.8.8')代码打包下载 http://xiazai.bitsCN.com/201105/yuanma/ipaddress.7z 
接下来为大家分享更完美的代码:
#!/usr/bin/env python
# coding: utf-8
 
'''用Python脚本查询纯真IP库
 
QQWry.Dat的格式如下:
 
+----------+
| 文件头 | (8字节)
+----------+
| 记录区 | (不定长)
+----------+
| 索引区 | (大小由文件头决定)
+----------+
 
文件头:4字节开始索引偏移值+4字节结尾索引偏移值
 
记录区: 每条IP记录格式 ==> IP地址[国家信息][地区信息]
 
 对于国家记录,可以有三种表示方式:
 
 字符串形式(IP记录第5字节不等于0x01和0x02的情况),
 重定向模式1(第5字节为0x01),则接下来3字节为国家信息存储地的偏移值
 重定向模式(第5字节为0x02),
 
 对于地区记录,可以有两种表示方式: 字符串形式和重定向
 
 最后一条规则:重定向模式1的国家记录后不能跟地区记录
 
索引区: 每条索引记录格式 ==> 4字节起始IP地址 + 3字节指向IP记录的偏移值
 
 索引区的IP和它指向的记录区一条记录中的IP构成一个IP范围。查询信息是这个
 范围内IP的信息
 
'''
 
import sys
import socket
from struct import pack, unpack
 
class IPInfo(object):
 '''QQWry.Dat数据库查询功能集合
 '''
 def __init__(self, dbname):
 ''' 初始化类,读取数据库内容为一个字符串,
 通过开始8字节确定数据库的索引信息'''
 
 self.dbname = dbname
 # f = file(dbname, 'r')
 
 # Demon注:在Windows下用'r'会有问题,会把
转换成
 # 详见http://demon.tw/programming/python-open-mode.html
 # 还有Python文档中不提倡用file函数来打开文件,推荐用open
 f = open(dbname, 'rb')
 
 self.img = f.read()
 f.close()
 
 # QQWry.Dat文件的开始8字节是索引信息,前4字节是开始索引的偏移值,
 # 后4字节是结束索引的偏移值。
 # (self.firstIndex, self.lastIndex) = unpack('II', self.img[:8])
 
 # Demon注:unpack默认使用的endian是和机器有关的
 # Intel x86和AMD64(x86-64)是little-endian
 # Motorola 68000和PowerPC G5是big-endian
 # 而纯真数据库全部采用了little-endian字节序
 # 所以在某些big-endian的机器上原代码会出错
 (self.firstIndex, self.lastIndex) = unpack('