设为首页 收藏本站
查看: 2100|回复: 0

[经验分享] 在纯真IP数据库(qqwry.dat)里查询IP地址归属地,Python 3版

[复制链接]

尚未签到

发表于 2015-12-1 12:50:12 | 显示全部楼层 |阅读模式
  特点:
  1、for Python 3.0+。
  2、有两套实现供选择。有一个查找速度更快,但加载稍慢一点、占用内存稍多一点。
  3、i3 3.6GHz,在Python 3.5上查询速度达10.2万次/秒。
  4、仅import array和bisect这两个Python自带的模块。
  5、经过较严格测试。
  6、另提供一个从纯真网络(cz88.net)更新qqwry.dat的小工具,见github项目。

用法:



from qqwry import QQwry
q = QQwry()
q.load_file('qqwry.dat', loadindex=False)
q.lookup('8.8.8.8')
  详细用法见qqwry.py文件里面的说明
  
  解释load_file函数的loadindex参数:


loadindex=False(默认)

loadindex=True
说明把整个文件读入内存。  把整个文件读入内存。
  额外加载索引,把索引读入更快的数据结构。

加载速度稍快稍慢
进程占用内存12.6 MB17.7 MB
查询速度3.9 万次/秒10.2 万次/秒
备注适合桌面程序适合服务器程序
  以上是在i3 3.6GHz, Win10, Python 3.5.0rc2 64bit,qqwry.dat 8.85MB时的数据

github上的项目:
https://github.com/animalize/qqwry-python3
  
  源码:



# coding=utf-8
#
# for Python 3.0+
# 来自: https://github.com/animalize/qqwry-python3
# 版本:2015-10-23
#
# 用法:
# from qqwry import QQwry
# q = QQwry()  # 生成对象
# q.load_file(filename, loadindex=False) # 加载qqwry.dat文件
# q.lookup('8.8.8.8')  # 查询IP地址
#
# q.load_file(filename, loadindex=False)函数:
# 参数filename可以是qqwry.dat的文件名,也可以为bytes类型的文件内容
# 参数loadindex为False时,把qqwry.dat整体读入内存,不额外加载索引
# 参数loadindex为True时,把qqwry.dat整体读入内存,额外加载索引
# 后者比前者查找更快(3.9万次/秒,10.2万次/秒)
# 后者比前者占用更多内存(测试进程的内存分别为12.6MB,17.7MB)
# 后者比前者加载稍慢
# 以上是在i3 3.6GHz, Win10, Python 3.5.0rc2 64bit,qqwry.dat 8.85MB时的数据
# 函数成功返回True,失败返回False
#
# q.lookup('8.8.8.8')函数:
# 找到则返回一个含有两个字符串的元组:('国家', '省份')
# 没有找到结果返回一个None
#
# q.get_lastone()函数:
# 返回最后一条数据,最后一条通常为数据的版本号
# 没有数据则返回None
#
# q.is_loaded()函数:
# 是否已加载数据,返回True或False
#
# q.clear()函数:
# 清空已加载的qqwry.dat
# 再次调用load_file时不必执行q.clear()
import array
import bisect
__all__ = ('QQwry')
def int3(data, offset):
return data[offset] + (data[offset+1] << 8) + \
(data[offset+2] << 16)
def int4(data, offset):
return data[offset] + (data[offset+1] << 8) + \
(data[offset+2] << 16) + (data[offset+3] << 24)
class QQwry:
def __init__(self):
self.clear()
def clear(self):
self.idx1 = None
self.idx2 = None
self.idxo = None
self.data = None
self.index_begin = -1
self.index_end = -1
self.index_count = -1
self.__fun = None
def load_file(self, filename, loadindex=False):
self.clear()
if type(filename) == bytes:
self.data = buffer = filename
filename = 'memory data'
elif type(filename) == str:
# read file
try:
with open(filename, 'br') as f:
self.data = buffer = f.read()
except Exception as e:
print('打开、读取文件时出错:', e)
self.clean()
return False
if self.data == None:
print('%s load failed' % filename)
self.clear()
return False
else:
self.clean()
return False
if len(buffer) < 8:
print('%s load failed, file only %d bytes' %
(filename, len(buffer))
)
self.clear()
return False            
# index range
index_begin = int4(buffer, 0)
index_end = int4(buffer, 4)
if index_begin > index_end or \
(index_end - index_begin) % 7 != 0 or \
index_end + 7 > len(buffer):
print('%s index error' % filename)
self.clear()
return False
self.index_begin = index_begin
self.index_end = index_end
self.index_count = (index_end - index_begin) // 7 + 1
if not loadindex:
print('%s %s bytes, %d segments. without index.' %
(filename, format(len(buffer),','), self.index_count)
)
self.__fun = self.__raw_search
return True
# load index
self.idx1 = array.array('L')
self.idx2 = array.array('L')
self.idxo = array.array('L')
try:
for i in range(self.index_count):
ip_begin = int4(buffer, index_begin + i*7)
offset = int3(buffer, index_begin + i*7 + 4)
# load ip_end
ip_end = int4(buffer, offset)
self.idx1.append(ip_begin)
self.idx2.append(ip_end)
self.idxo.append(offset+4)
except:
print('%s load index error' % filename)
self.clear()
return False
print('%s %s bytes, %d segments. with index.' %
(filename, format(len(buffer),','), len(self.idx1))
)
self.__fun = self.__index_search
return True
def __get_addr(self, offset):        
# mode 0x01, full jump
mode = self.data[offset]
if mode == 1:
offset = int3(self.data, offset+1)
mode = self.data[offset]
# country
if mode == 2:
off1 = int3(self.data, offset+1)
c = self.data[off1:self.data.index(b'\x00', off1)]
offset += 4
else:
c = self.data[offset:self.data.index(b'\x00', offset)]
offset += len(c) + 1
# province
if self.data[offset] == 2:
offset = int3(self.data, offset+1)
p = self.data[offset:self.data.index(b'\x00', offset)]
return c.decode('gb18030', errors='replace'), \
p.decode('gb18030', errors='replace')
def lookup(self, ip_str):
try:
ip = sum(256**j*int(i) for j,i
in enumerate(ip_str.strip().split('.')[::-1]))
return self.__fun(ip)
except:
return None
def __raw_search(self, ip):
l = 0
r = self.index_count
while r - l > 1:
m = (l + r) // 2
offset = self.index_begin + m * 7
new_ip = int4(self.data, offset)
if ip < new_ip:
r = m
else:
l = m
offset = self.index_begin + 7 * l
ip_begin = int4(self.data, offset)
offset = int3(self.data, offset+4)
ip_end = int4(self.data, offset)
if ip_begin <= ip <= ip_end:
return self.__get_addr(offset+4)
return None
def __index_search(self, ip):
posi = bisect.bisect_right(self.idx1, ip) - 1
if posi >= 0 and self.idx1[posi] <= ip <= self.idx2[posi]:
return self.__get_addr(self.idxo[posi])
else:
return None
def is_loaded(self):
return self.__fun != None
def get_lastone(self):
try:
offset = int3(self.data, self.index_end+4)
return self.__get_addr(offset+4)
except:
return None
if __name__ == '__main__':
import sys
if len(sys.argv) > 1:
fn = 'qqwry.dat'
q = QQwry()
q.load_file(fn)
for ipstr in sys.argv[1:]:
s = q.lookup(ipstr)
print('%s\n%s' % (ipstr, s))
else:
print('请以查询ip作为参数运行')

  

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-145877-1-1.html 上篇帖子: 在sublimetext上打造一个兼容virtualenv的web&python开发环境 下篇帖子: Python之调用WebService:suds
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表