QQwry到Sqlite3

来源:互联网 发布:有关网络暴力的视频 编辑:程序博客网 时间:2024/06/06 05:12

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, index = index, 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, lastIndex, 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, end_ip, country, 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, end_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倍.

不过这只是测试代码,我还能改进优化存储,应该能至少压缩一半,并加快检索速度.

原创粉丝点击