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核心功能物理复制技术
日志是数据库的重要组成部份,按顺序以增量的方式记录了数据库上所有的操作,日志模块的设计对于数据库的可靠性.稳定性和性能都非常重要. 可靠性方面,在有一个数据文件的基础全量备份后,对运行中的数据库来说, ...
随机推荐
- Windows版本搭建安装React Native环境配置及相关问题
此文档整理参考地址: http://www.lcode.org/%E5%8F%B2%E4%B8%8A%E6%9C%80%E8%AF%A6%E7%BB%86windows%E7%89%88%E6%9C% ...
- 6 Java学习之 枚举
1. 概念 枚举是一种规范,它规范了参数的形式,这样就可以不用考虑类型的不匹配,并且显示的替代了int型参数可能带来的模糊概念. 常用来定义一个final类型的变量(常量),保证输入安全.如 ...
- 看个人思路吧,清晰的话就简单 CodeForces 271A - Beautiful Year
It seems like the year of 2013 came only yesterday. Do you know a curious fact? The year of 2013 is ...
- 吐槽一下CSDN的封停审查机制
今天和一同学用私信交流,我回答中用了"春季zhaopin"这几个字(大家知道是哪两个字),结果提示我内容非法无法发送,我立即改动用了谐音发了过去.结果我出来一看,显示我的个人主页 ...
- .net web 开发平台- 表单设计器 一(web版)
如今为了适应需求的不断变化,动态表单设计器应运而生.它主要是为了满足界面的不断变化和提高开发速度.比如:一些页面客户可能也无法确定页面的终于布局,控件的位置,在哪种情况下显示或不显示等可能须要随时改动 ...
- UML应用:业务内涵的分析抽象&表达
上一篇,架构设计的UML图形思考 ,简介了图形思考设计.表达设计对于架构师的重要意义,以及简介了使用统一建模语言UML描写叙述类以及类之间的继承关系,这样的描写叙述还停留在写代码,表达的但是说是怎样写 ...
- css考核点整理(八)-在什么情况下通过img引入图片,什么情况用背景图引入?背景属性有哪些
在什么情况下通过img引入图片,什么情况用背景图引入?背景属性有哪些
- Json字符串与字典互转
#pragma mark 转换json字符串 +(NSString *)toJSON:(id)aParam { NSData *jsonData=[NSJSONSerialization data ...
- springmvc配置文件 spring-servlet
<?xml version="1.0" encoding="UTF-8"?><!-- Bean头部 --><beans xmlns ...
- 利用MutationObserver对页面元素的改变进行监听
'use strict'; let MutationObserver = window.MutationObserver || window.WebKitMutationObserver || win ...