Python使用纯真年代数据库qqwry.dat转换物理位置
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转换物理位置的更多相关文章
- 纯真IP数据库(qqwry.dat)转换成最新的IP数据库格式(ipwry.dat)
纯真IP数据库(qqwry.dat)转换成最新的IP数据库格式(ipwry.dat) 转载自:http://blog.cafeboy.org/2011/02/25/qqwry-to-ipwry/ ht ...
- 优化读取纯真IP数据库QQWry.dat获取地区信息
改自HeDaode 2007-12-28的代码 将之改为从硬盘读取后文件后,将MemoryStream放到内存中,提高后续查询速度 ///<summary> /// 提供从纯真IP数据库搜 ...
- python 使用qqwry.dat获取ip物理地址:速度快
# -*- coding: utf-8 -*- import socket import struct class IPAddresss: def __init__(self, ipdbFile): ...
- python绝技 — 使用PyGeoIP关联IP地址和物理位置
准备工作 要关联IP与物理位置,我们需要有一个包含这样对应关系的数据库. 我们可以使用开源数据库GeoLiteCity,它能够较为准确地把IP地址与所在城市关联起来 下载地址:http://dev.m ...
- 【Python全栈-数据库】数据库基础
数据库的简介 数据库 数据库(database,DB)是指长期存储在计算机内的,有组织,可共享的数据的集合.数据库中的数据按一定的数学模型组织.描述和存储,具有较小的冗余,较高的数据独立性和易扩展性, ...
- QQWry.dat 数据写入
纯真IP库 数据多,更新及时,很多同学在用,网上关于其读取的帖子也有不少(当然其中有一些是有BUG的),但却很少有关于其写入的帖子.OK,下面分享下写QQWry.dat. QQWry.dat 分三个部 ...
- MySQL---连接器(python如何操作数据库媒介,基于python语言)
MySQL — 连接器 连接器的概念 它们往往是一类Python包,或者是一类已经写好的Python库.这些库提供了我们Python去连接数据库服务器的基本功能. 既然它是一个包,那么我们首先学会 ...
- C# 调用IP库(QQWry.Dat)查询IP位置及自动升级IP库方法【转】
前言 C# 用IP地址(123.125.114.144)查询位置(北京市百度公司)的东西,非常好用也非常方便,可手动升级刷新IP库,一次编码永久收益,可支持winform.asp.net等程序. 本文 ...
- 深入解读阿里云数据库POLARDB核心功能物理复制技术
日志是数据库的重要组成部份,按顺序以增量的方式记录了数据库上所有的操作,日志模块的设计对于数据库的可靠性.稳定性和性能都非常重要. 可靠性方面,在有一个数据文件的基础全量备份后,对运行中的数据库来说, ...
随机推荐
- toString&&equals方法
toString&&equals方法 先来看看这个题该怎样做? 分析: 1.java里的三大特性,有封装,继承,多态(方法的重载),super,this等关键字 2.常用的方法,equ ...
- 深入N皇后问题的两个最高效算法的详解 分类: C/C++ 2014-11-08 17:22 117人阅读 评论(0) 收藏
N皇后问题是一个经典的问题,在一个N*N的棋盘上放置N个皇后,每行一个并使其不能互相攻击(同一行.同一列.同一斜线上的皇后都会自动攻击). 一. 求解N皇后问题是算法中回溯法应用的一个经典案例 回溯算 ...
- MySQL slave状态之Seconds_Behind_Master
在MySQL的主从环境中,我们能够通过在slave上运行show slave status来查看slave的一些状态信息,当中有一个比較重要的參数Seconds_Behind_Master.那么你是否 ...
- ExtJs4学习(四):Extjs 中id与itemId的差别
为了方便表示或是指定一个组件的名称,我们一般会使用id或者itemId进行标识命名. (推荐尽量使用itemId.这样能够降低页面唯一标识而产生的冲突) id: id是作为整个页面的Comp ...
- Java读取WEB-INF目录下的properties配置文件
如何在Java代码中读取WEB-INF目录下的properties配置文件,下文给出了一个解决方案. 我们习惯将一些配置信息写在配置文件中,比如将数据库的配置信息URL.User和Password写在 ...
- mysql查看端口
在你的my.ini(Windows)或my.cfg(Linux) 中就有啊. 或者如果已经连入MySQL可以直接 SQL code ? 1 2 3 4 5 6 7 8 9 mysql> show ...
- 上传文件时 ContentType 浏览器差异
上传图片时,ie会把 jpg.jpeg翻译成image/pjpeg,png翻译成image/x-png . 火狐.chrome则很标准:jpg.jpeg翻译成image/jpeg,png翻译成imag ...
- CUDA与VS2013安装
@import url(http://i.cnblogs.com/Load.ashx?type=style&file=SyntaxHighlighter.css);@import url(/c ...
- oracle添加数据时主键自动增长
CREATE TABLE STUDENT( --创建学生表 ID NUMBER(10) PRIMARY KEY, --主键ID SNAME VARCHAR2(20), ); 此时给学生表添加数 ...
- CentOS 6.4 编译 Hadoop 2.5.1
为了防止无良网站的爬虫抓取文章,特此标识,转载请注明文章出处.LaplaceDemon/SJQ. http://www.cnblogs.com/shijiaqi1066/p/4058956.html ...