PS:网上直接找的,贴出来,方便以后随时用,感谢分享的人。

#!/usr/bin/python
#encoding: utf-8 import socket
import codecs
import mmap
from struct import pack, unpack def decode_str(old):
'''专门对纯真的gbk编码字符串解压
返回 utf8 字符串
'''
try:
return unicode(old,'gbk').encode('utf-8')
except:
# 当字符串解码失败,并且最一个字节值为'\x96',则去掉它,再解析
if old[-1] == '\x96':
try:
return unicode(old[:-1],'gbk').encode('utf-8') + '?'
except:
pass return 'Invalid' class QQWry(object):
def __init__(self, path):
self.path = path
self.db = None
self.open_db()
self.idx_start, self.idx_end = self._read_idx()
# IP索引总数
self.total = (self.idx_end - self.idx_start) / 7 + 1 def open_db(self):
if not self.db:
self.db = open(self.path, 'rb')
self.db = mmap.mmap(self.db.fileno(), 0, access = 1)
return self.db def _read_idx(self):
'''
读取数据库中IP索引起始和结束偏移值
'''
self.db.seek(0)
start = unpack('I', self.db.read(4))[0]
end = unpack('I', self.db.read(4))[0]
return start, end def version(self):
'''
返回纯真IP库的版本信息
格式如 "纯真网络2014年8月5日IP数据"
'''
ip_end_offset = self.read_offset(self.idx_end + 4)
a_raw, b_raw = self.read_record(ip_end_offset+4)
return decode_str(a_raw + b_raw) def read_ip(self, off, seek=True):
'''
读取ip值(4字节整数值)
返回IP值
'''
if seek:
self.db.seek(off)
buf = self.db.read(4)
return unpack('I', buf)[0] def read_offset(self, off, seek=True):
'''
读取3字节的偏移量值
返回偏移量的整数值
'''
if seek:
self.db.seek(off)
buf = self.db.read(3)
return unpack('I', buf+'\0')[0] def read_string(self, offset):
'''
读取原始字符串(以"\0"结束)
返回元组:字符串
'''
if offset == 0:
return 'N/A1'
flag = self.get_flag(offset)
if flag == 0:
return 'N/A2'
elif flag == 2:
# 0x02 表示该处信息还是需要重定向
offset = self.read_offset(offset+1)
return self.read_string(offset)
self.db.seek(offset)
raw_string = ''
while True:
x = self.db.read(1)
if x == '\0':
break
raw_string += x
return raw_string def get_flag(self, offset):
'''
读取偏移处的1字节整数值
QQWry地址信息字符串的第一个字节值可能会是一个标志位,
这是一个通用的函数.
'''
self.db.seek(offset)
c = self.db.read(1)
if not c:
return 0
return ord(c) def read_record(self, offset):
self.db.seek(offset)
# 读取 flag
flag = ord(self.db.read(1))
if flag == 1:
# 0x01 表示记录区记录(国家,地区)信息都重定向
# 注意:一次重定向后记录还有可能是一个重定向(其flag=0x02)
buf = self.db.read(3)
a_offset = unpack('I', buf+'\0')[0]
a_raw = self.read_string(a_offset)
# 判断新记录的flag是否为0x02,如果是,则表明:
# - 国家信息重定向另外地址
# - 地区信息为新记录起始地址偏移4字节
a_flag = self.get_flag(a_offset)
if a_flag == 2:
b_raw = self.read_string(a_offset+4)
else:
b_raw = self.read_string(a_offset+len(a_raw)+1)
elif flag == 2:
# 0x02 表示仅国家记录重定向
# 地区信息偏移4字节
buf = self.db.read(3)
a_offset = unpack('I', buf+'\0')[0]
a_raw = self.read_string(a_offset)
b_raw = self.read_string(offset+4)
else:
# 正常的信息记录
a_raw = self.read_string(offset)
b_raw = self.read_string(offset+len(a_raw)+1)
return a_raw, b_raw def output(self, output_file='ip.txt'):
'''
输出所有IP信息到文件
'''
fp = codecs.open(output_file, 'w', 'utf8')
idx = self.idx_start
while idx <= self.idx_end:
ip_int = self.read_ip(idx)
ip_start = socket.inet_ntoa(pack('!I', ip_int))
ip_end_offset = self.read_offset(idx + 4)
ip_int = self.read_ip(ip_end_offset)
ip_end = socket.inet_ntoa(pack('!I', ip_int))
a_raw, b_raw = self.read_record(ip_end_offset+4)
a_info = decode_str(a_raw)
b_info = decode_str(b_raw)
fp.write(u'%15s\t%15s\t%s,%s\n' %(
ip_start, ip_end,
a_info.decode('utf8'), b_info.decode('utf8')))
# 步进7字节:4字节的起始IP值 + 3字节的结束IP偏移值
idx += 7
fp.close() def find(self, ip, l, r):
'''
使用二分法查找网络字节编码的IP地址的索引记录
'''
if r - l <= 1:
return l
m = (l + r) / 2
offset = self.idx_start + m * 7
new_ip = self.read_ip(offset)
if ip < new_ip:
return self.find(ip, l, m)
else:
return self.find(ip, m, r) def query(self, ip):
'''
查询IP信息
'''
# 使用网络字节编码IP地址
ip = unpack('!I', socket.inet_aton(ip))[0]
# 使用 self.find 函数查找ip的索引偏移
i = self.find(ip, 0, self.total - 1)
# 得到索引记录
o = self.idx_start + i * 7
# 索引记录格式是: 前4字节IP信息+3字节指向IP记录信息的偏移量
# 这里就是使用后3字节作为偏移量得到其常规表示(QQWry.Dat用字符串表示值)
o2 = self.read_offset(o + 4)
# IP记录偏移值+4可以丢弃前4字节的IP地址信息。
(c, a) = self.read_record(o2 + 4)
return (decode_str(c), decode_str(a)) def __del__(self):
if self.db:
self.db.close() def main():
dbpath = "C:\ipdata\qqwry.dat"
ip = "183.61.60.23"
qqwry = QQWry(dbpath)
c, a = qqwry.query(ip)
print '%s %s--%s' % (ip, c.decode('utf-8'), a.decode('utf-8')) if __name__ == '__main__':
main()

  

Result:

https://github.com/Teaing/PythonWorld/blob/master/Transformation_Address.py

Python使用纯真年代数据库qqwry.dat转换物理位置的更多相关文章

  1. 纯真IP数据库(qqwry.dat)转换成最新的IP数据库格式(ipwry.dat)

    纯真IP数据库(qqwry.dat)转换成最新的IP数据库格式(ipwry.dat) 转载自:http://blog.cafeboy.org/2011/02/25/qqwry-to-ipwry/ ht ...

  2. 优化读取纯真IP数据库QQWry.dat获取地区信息

    改自HeDaode 2007-12-28的代码 将之改为从硬盘读取后文件后,将MemoryStream放到内存中,提高后续查询速度 ///<summary> /// 提供从纯真IP数据库搜 ...

  3. python 使用qqwry.dat获取ip物理地址:速度快

    # -*- coding: utf-8 -*- import socket import struct class IPAddresss: def __init__(self, ipdbFile): ...

  4. python绝技 — 使用PyGeoIP关联IP地址和物理位置

    准备工作 要关联IP与物理位置,我们需要有一个包含这样对应关系的数据库. 我们可以使用开源数据库GeoLiteCity,它能够较为准确地把IP地址与所在城市关联起来 下载地址:http://dev.m ...

  5. 【Python全栈-数据库】数据库基础

    数据库的简介 数据库 数据库(database,DB)是指长期存储在计算机内的,有组织,可共享的数据的集合.数据库中的数据按一定的数学模型组织.描述和存储,具有较小的冗余,较高的数据独立性和易扩展性, ...

  6. QQWry.dat 数据写入

    纯真IP库 数据多,更新及时,很多同学在用,网上关于其读取的帖子也有不少(当然其中有一些是有BUG的),但却很少有关于其写入的帖子.OK,下面分享下写QQWry.dat. QQWry.dat 分三个部 ...

  7. MySQL---连接器(python如何操作数据库媒介,基于python语言)

    MySQL — 连接器 连接器的概念 它们往往是一类Python包,或者是一类已经写好的Python库.这些库提供了我们Python去连接数据库服务器的基本功能. ​ 既然它是一个包,那么我们首先学会 ...

  8. C# 调用IP库(QQWry.Dat)查询IP位置及自动升级IP库方法【转】

    前言 C# 用IP地址(123.125.114.144)查询位置(北京市百度公司)的东西,非常好用也非常方便,可手动升级刷新IP库,一次编码永久收益,可支持winform.asp.net等程序. 本文 ...

  9. 深入解读阿里云数据库POLARDB核心功能物理复制技术

    日志是数据库的重要组成部份,按顺序以增量的方式记录了数据库上所有的操作,日志模块的设计对于数据库的可靠性.稳定性和性能都非常重要. 可靠性方面,在有一个数据文件的基础全量备份后,对运行中的数据库来说, ...

随机推荐

  1. Quartz.Net任务调度框架

    Quartz.Net是一个开源的任务调度框架,非常强大,能够通过简单的配置帮助我们定时具体的操作. 相对于我们用的线程里面while(true)然后sleep来执行某个操作,应该算的上是高端,大气,上 ...

  2. Web App和Native App 谁将是未来

    未来是Web App的天下,还是Native App的天下?作为设计师,我们是应该努力把客户端的体验提升到最优,还是在网页应用层面上做更多的设计?这个一直是大家关心的话题.那么,我们首先应该立体的认识 ...

  3. Debian自启动知识 2015-03-31 20:23 79人阅读 评论(0) 收藏

    Debian6添加了insserv用来代替update-rc.d.update-rc.d 就不多做介绍. Debian6里边要添加一个自动启动的服务需要先将启动脚本放在/etc/init.d,然后使用 ...

  4. MySQL slave状态之Seconds_Behind_Master

    在MySQL的主从环境中,我们能够通过在slave上运行show slave status来查看slave的一些状态信息,当中有一个比較重要的參数Seconds_Behind_Master.那么你是否 ...

  5. block代码块介绍

    关于block的简单介绍 什么是block? Block是C语言的一个语法特性,同时也是C语言的运行时特性,它很像C中的函数指针,因为你可以像使用函数指针一样的去使用block对象:它也很像C++中的 ...

  6. 如何判断JDK是32位还是64位

    第一种方法 在CMD窗口中使用java -version 命令进行查看 如果是64位的则会显示 Java HotSpot<TM>64-Bit 字样,32位的则没有类似信息. 注:这是Sun ...

  7. 第八条——覆盖equals方法时需遵守的通用约定

    1)自反性 对于任何非null的引用值x,x.equals(x)必须返回true.---这一点基本上不会有啥问题 2)对称性 对于任何非null的引用值x和y,当且仅当x.equals(y)为true ...

  8. Android Studio学习随笔-UI线程阻塞以及优化

    我们在使用手机的时候,经常会遇到一个问题:先是卡死,然后跳出该程序无响应,是否关闭的提示(当然有可能是我们手机性能太差=.=)这是因为线程的阻塞引起的,在这里我讲述一下UI线程,一般处理程序会在UI线 ...

  9. Active Desktop--桌面字体背景被修改

    怎么修改回来 步骤如下 方法一.在桌面上点击右键 -- 排列图标 -- 去掉“在桌面上锁定Web项目”上的勾. 方法二.右键点击我的电脑 -- 属性 -- 高级 -- 点击“性能”下面的“设置”按钮, ...

  10. 国内流行的两大开源.net微信公众平台SDK对比分析

    最近忙于微信周边的开发 难免手痒去搜索一下有没有相关的sdk直接拿来使 还真发现了不少 这里总结两个看起来比较不错的.net平台下基于C#语言开发的SDK 一个强大一个小巧 (1) Senparc.W ...