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倍. 不过这只是测试代码,我还能改进优化存储,应该能至少压缩一半,并加快检索速度.
原文链接:https://www.f2er.com/sqlite/202964.html