QQwry是国内很流行的一个中文IP数据库,它使用特别的格式存储IP记录压缩率很高,正因如此,每次升级数据库时得重新下载整库,我希望让它更简单一点,升级只需要下载批量更新数据,我试着把它转换成sqlite3, 先贴我的代码 Python代码:
''' Created on 2010-4-17 @author: Ben @mail: ben.pang.china@gmail.com ''' import os import sys import sqlite3 def binToInt(data): """将传入的bytes转换为integer 传入的bytes序列将按编号从低位到高位的排序组转换为integer,如: data[0]~data[3]分别是:0x00 0x01 0x02 0x03 那么它对应的数值的binary是 00000011 00000010 00000001 00000000 等于十进制数值50462976 """ x = 0 for i,d in enumerate(data): x |= d << ( i * 8 ) return x def readRecord(index): """根据传入的索引地址读取该记录的全部信息 根据传入的索引地址读取该IP记录,如其实IP,结束IP,country字段,area字段 """ def readStr(): """从指定索引读取出文本内容 从指定索引开始向后检索0,提取出字节并转换为字符信息;索引index引用readRecord的变量index,并且在读取字符后将index指向0 """ nonlocal index old,index = index,data.find( b'x00',index ) # 从index位置开始查找0所在位置 return data[ old : index ].decode('gbk' ) start_ip = '{}.{}.{}.{}' .format( *reversed(data[ index : index + 4 ]) ) # 将IP字节转换为人可读的IP地址,如: 192.168.1.1 index = binToInt(data[ index + 4 : index + 7 ]) # 获取结束IP的索引地址 end_ip = '{}.{}.{}.{}' .format( *reversed(data[ index : index + 4 ]) ) # 结束IP地址 # 设置索引变量指向指向end ip后的索引处 index += 4 # 判断IP信息的索引模式 if data[ index ] == 0x01: index = binToInt(data[ index + 1 : index + 4 ]) # 重设索引到新位置 if data[ index ] == 0x02: # 判断country信息是指针还是字符串 old,binToInt( data[ index + 1 : index + 4 ] ) # 缓存当前索引地址,并将索引变量指向country字符串所在地址 country = readStr() # 读取country信息 index = old + 4 # 将索引指area地址 else : country = readStr() index += 1 if data[ index ] == 0x01 or data[ index ] == 0x02: index = binToInt( data[ index + 1 : index + 4 ] ) area = readStr() # 获取area信息 return [ start_ip,end_ip,country,area ] # 全局变量,用于存储一些数据库的常量 data = bytes() # 用于缓存数据库内容 cur = None c_record = {} a_record = { "" : None } def convert(db): """将IP记录从QQway中检索出来并存入sqlite3数据库中""" if not os.path.exists(db): print("Not found db:",db) return global data,firstIndex,lastIndex,cur with open(db,'rb' ) as f: data = f.read() # 从数据库中读取字节并进行缓存 firstIndex = binToInt(data[:4]) lastIndex = binToInt(data[4:8]) conn = sqlite3.connect( "ipdb.sdb3" ) cur = conn.cursor() for i in range(firstIndex,7): saveIpRecord( readRecord(i) ) else : conn.commit() conn.close() print("converted and saving to ipdb.sql3" ) def saveIpRecord(record): """保存IP记录到数据库""" global cur,c_record,a_record start_ip,area = record if country not in c_record: cur.execute("INSERT INTO country VALUES(null,?)",(country,)) c_record[ country ] = cur.execute("SELECT max(id) FROM country" ).fetchone()[0] if area not in a_record: cur.execute("INSERT INTO area VALUES(null,(area,)) a_record[ area ] = cur.execute("SELECT max(id) FROM area" ).fetchone()[0] cur.execute("INSERT INTO ipaddr VALUES(null,?,( start_ip,c_record[ country ],a_record[ area ] )) if __name__ == '__main__' : if len(sys.argv) == 2: convert(sys.argv[1]) else : print("usage: converter.py database" )
你需要先了解QQwry.dat的格式,那么应该看的懂我们代码.生成的sqlite3很大是原来的6倍. 不过这只是测试代码,我还能改进优化存储,应该能至少压缩一半,并加快检索速度. (编辑:李大同)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|