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核心功能物理复制技术
日志是数据库的重要组成部份,按顺序以增量的方式记录了数据库上所有的操作,日志模块的设计对于数据库的可靠性.稳定性和性能都非常重要. 可靠性方面,在有一个数据文件的基础全量备份后,对运行中的数据库来说, ...
随机推荐
- winfrom 操作 INI 文件 分类: WinForm 2014-07-22 12:49 156人阅读 评论(0) 收藏
<strong><span style="font-size:18px;">(1)INI文件的名称:FileConfig.ini</span>& ...
- tableview: 实现tableview 的 section header 跟随tableview滑动
方法一:(只有一个headerView)一段 如果你的tableview恰好只有一个headerView,实现这种效果就好办了.把要设置的headerView设置成tableView的header而不 ...
- hdu 2824 The Euler function(欧拉函数)
如果打表的话会超内存,我想到了一种方法解决这个问题.题目给出的数据时3000000,我将三百万分成300个数据,将整万的数据存储下来,计算的时候,先计算x和y之间整万的数据,然后再计算零散数据. 想法 ...
- UIButton图文上下对齐
- (void)centerImageAndTitle:(float)spacing { // get the size of the elements here for readability CG ...
- VS2010+Opencv-2.4.9的配置攻略
1.下载软件 vs2010入门书籍,免积分下载 http://download.csdn.net/detail/u014112584/7325617 opencv2.4.0版本号和一些样例,免积分 ...
- shell入门之变量测试 分类: 学习笔记 linux ubuntu 2015-07-10 15:49 31人阅读 评论(0) 收藏
格式:test 测试条件 字符串测试: 注意空格: test str1 == str2 测试字符串是否相等 test str1 != str2 测试字符串是否不相等 test str1 测试字符串是否 ...
- 如何在windows/wamp环境下在本机配置站点
1. 在D:\wamp\bin\apache\Apache2.5.4\conf文件夹下,找到httpd.conf,使用记事bej打开它,搜索#Include conf/extra/httpd-vhos ...
- Apache MINA 框架之默认session管理类实现
DefaultSocketSessionConfig 类 extends AbstractSocketSessionConfig extends AbstractIoSessionConfig imp ...
- win 10 安装 mysql解压版 步骤
参考资料:win 10 安装 mysql 5.7 网址:http://blog.sina.com.cn/s/blog_5f39af320102wbk0.html 本文参考上面的网址的教程,感谢作者分享 ...
- PHP面向对象的基本写法(区别于java)
<?php /** * 这是一个人的对象 */ class ClassName { public $name; public $age; public $sex; public static $ ...