核心代碼:
#!/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 sysimport socketfrom struct import pack, unpack class IPInfo(object): '''QQWry.Dat資料庫查詢功能集合 ''' def __init__(self, dbname): ''' 初始化類,讀取資料庫內容為一個字串, 通過開始8位元組確定資料庫的索引資訊''' self.dbname = dbname # f = file(dbname, 'r') # Demon註:在Windows下用'r'會有問題,會把\r\n轉換成\n # 詳見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('用Python指令碼查詢純真IP庫QQWry.dat(Demon修改版)
由於要用 Python 讀取一個和純真IP資料庫 QQWry.dat 格式差不多的 IPv6 資料庫,所以在網上搜尋了一下,在 LinuxTOY 看到了一個 Python 指令碼,發現有一些小小的問題,於是修改了一下。
#!/usr/bin/env python# coding: utf-8# from: http://linuxtoy.org/files/pyip.py# Blog: http://linuxtoy.org/archives/python-ip.html# Modified by Demon# Blog: http://demon.tw/programming/python-qqwry-dat.html'''用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 sysimport socketfrom struct import pack, unpackclass IPInfo(object): '''QQWry.Dat資料庫查詢功能集合 ''' def __init__(self, dbname): ''' 初始化類,讀取資料庫內容為一個字串, 通過開始8位元組確定資料庫的索引資訊''' self.dbname = dbname # f = file(dbname, 'r') # Demon註:在Windows下用'r'會有問題,會把\r\n轉換成\n # 詳見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('