#!/usr/bin/env python

# coding: utf-8

# from: http://linuxtoy.org/files/pyip.py

# Blog: http://linuxtoy.org/archives/python-ip.html

# Modified by Demon

# Blog: http://demon.tw/programming/python-qqwry-dat.html

'''用Python脚本查询纯真IP库

QQWry.Dat的格式如下:

+----------+

| 文件头 | (8字节)

+----------+

| 记录区 | (不定长)

+----------+

| 索引区 | (大小由文件头决定)

+----------+

文件头:4字节开始索引偏移值+4字节结尾索引偏移值

记录区: 每条IP记录格式 ==> IP地址[国家信息][地区信息]

对于国家记录,可以有三种表示方式:

字符串形式(IP记录第5字节不等于0x01和0x02的情况),

重定向模式1(第5字节为0x01),则接下来3字节为国家信息存储地的偏移值

重定向模式(第5字节为0x02),

对于地区记录,可以有两种表示方式: 字符串形式和重定向

最后一条规则:重定向模式1的国家记录后不能跟地区记录

索引区: 每条索引记录格式 ==> 4字节起始IP地址 + 3字节指向IP记录的偏移值

索引区的IP和它指向的记录区一条记录中的IP构成一个IP范围。查询信息是这个

范围内IP的信息

'''

importsys

importsocket

fromstructimportpack, unpack

classIPInfo(object):

'''QQWry.Dat数据库查询功能集合

'''

def__init__(self, dbname):

''' 初始化类,读取数据库内容为一个字符串,

通过开始8字节确定数据库的索引信息'''

self.dbname = dbname

# f = file(dbname, 'r')

# Demon注:在Windows下用'r'会有问题,会把\r\n转换成\n

# 详见http://demon.tw/programming/python-open-mode.html

# 还有Python文档中不提倡用file函数来打开文件,推荐用open

f =open(dbname,'rb')

self.img = f.read()

f.close()

# QQWry.Dat文件的开始8字节是索引信息,前4字节是开始索引的偏移值,

# 后4字节是结束索引的偏移值。

# (self.firstIndex, self.lastIndex) = unpack('II', self.img[:8])

# Demon注:unpack默认使用的endian是和机器有关的

# Intel x86和AMD64(x86-64)是little-endian

# Motorola 68000和PowerPC G5是big-endian

# 而纯真数据库全部采用了little-endian字节序

# 所以在某些big-endian的机器上原代码会出错

(self.firstIndex,self.lastIndex) = unpack('

# 每条索引长7字节,这里得到索引总个数

self.indexCount = (self.lastIndex -self.firstIndex) /7+1

defgetString(self,offset=0):

''' 读取字符串信息,包括"国家"信息和"地区"信息

QQWry.Dat的记录区每条信息都是一个以'\0'结尾的字符串'''

o2 =self.img.find('\0',offset)

#return self.img[offset:o2]

# 有可能只有国家信息没有地区信息,

gb2312_str =self.img[offset:o2]

try:

utf8_str =unicode(gb2312_str,'gb2312').encode('utf-8')

except:

return'未知'

returnutf8_str

defgetLong3(self,offset=0):

'''QQWry.Dat中的偏移记录都是3字节,本函数取得3字节的偏移量的常规表示

QQWry.Dat使用“字符串“存储这些值'''

s =self.img[offset:offset+3]

s +='\0'

# unpack用一个'I'作为format,后面的字符串必须是4字节

# return unpack('I', s)[0]

# Demon注:和上面一样,强制使用little-endian

returnunpack('

defgetAreaAddr(self,offset=0):

''' 通过给出偏移值,取得区域信息字符串,'''

byte =ord(self.img[offset])

ifbyte ==1orbyte ==2:

# 第一个字节为1或者2时,取得2-4字节作为一个偏移量调用自己

p =self.getLong3(offset+1)

return self.getAreaAddr(p)

else:

return self.getString(offset)

defgetAddr(self,offset, ip =0):

img =self.img

o =offset

byte =ord(img[o])

ifbyte ==1:

# 重定向模式1

# [IP][0x01][国家和地区信息的绝对偏移地址]

# 使用接下来的3字节作为偏移量调用字节取得信息

return self.getAddr(self.getLong3(o +1))

ifbyte ==2:

# 重定向模式2

# [IP][0x02][国家信息的绝对偏移][地区信息字符串]

# 使用国家信息偏移量调用自己取得字符串信息

cArea =self.getAreaAddr(self.getLong3(o +1))

o +=4

# 跳过前4字节取字符串作为地区信息

aArea =self.getAreaAddr(o)

return(cArea, aArea)

ifbyte !=1andbyte !=2:

# 最简单的IP记录形式,[IP][国家信息][地区信息]

# 重定向模式1有种情况就是偏移量指向包含国家和地区信息两个字符串

# 即偏移量指向的第一个字节不是1或2,就使用这里的分支

# 简单地说:取连续取两个字符串!

cArea =self.getString(o)

#o += len(cArea) + 1

# 我们已经修改cArea为utf-8字符编码了,len取得的长度会有变,

# 用下面方法得到offset

o =self.img.find('\0',o) +1

aArea =self.getString(o)

return(cArea, aArea)

deffind(self, ip, l, r):

''' 使用二分法查找网络字节编码的IP地址的索引记录'''

ifr - l <=1:

returnl

m = (l + r) /2

o =self.firstIndex + m *7

#new_ip = unpack('I', self.img[o: o+4])[0]

# Demon注:和上面一样,强制使用little-endian

new_ip = unpack('

ifip <= new_ip:

return self.find(ip, l, m)

else:

return self.find(ip, m, r)

defgetIPAddr(self, ip):

''' 调用其他函数,取得信息!'''

# 使用网络字节编码IP地址

ip = unpack('!I',socket.inet_aton(ip))[0]

# 使用 self.find 函数查找ip的索引偏移

i =self.find(ip,0,self.indexCount -1)

# 得到索引记录

o =self.firstIndex + i *7

# 索引记录格式是: 前4字节IP信息+3字节指向IP记录信息的偏移量

# 这里就是使用后3字节作为偏移量得到其常规表示(QQWry.Dat用字符串表示值)

o2 =self.getLong3(o +4)

# IP记录偏移值+4可以丢弃前4字节的IP地址信息。

(c, a) =self.getAddr(o2 +4)

return(c, a)

defoutput(self,first,last):

foriinrange(first,last):

o =self.firstIndex + i *7

ip =socket.inet_ntoa(pack('!I', unpack('I',self.img[o:o+4])[0]))

offset=self.getLong3(o +4)

(c, a) =self.getAddr(offset+4)

print"%s %d %s/%s"% (ip,offset, c, a)

defmain():

i = IPInfo('QQWry.Dat')

(c, a) = i.getIPAddr(sys.argv[1])

# Demon注:如果是在Windows命令行中运行把编码转回gb2312以避免乱码

ifsys.platform=='win32':

c =unicode(c,'utf-8').encode('gb2312')

a =unicode(a,'utf-8').encode('gb2312')

print'%s %s/%s'% (sys.argv[1], c, a)

if__name__=='__main__':

main()

# changelog

# 时间:2009年5月29日

# 1. 工具下面网友的建议,修改"o += len(cArea) + 1"

# http://linuxtoy.org/archives/python-ip.html#comment-113960

# 因为这个时候我已经把得到的字符串变成utf-8编码了,长度会有变化!

python ipaddr库_用Python脚本查询纯真IP库QQWry.dat(Demon修改版)相关推荐

  1. python 时间序列预测_使用Python进行动手时间序列预测

    python 时间序列预测 Time series analysis is the endeavor of extracting meaningful summary and statistical ...

  2. python 概率分布模型_使用python的概率模型进行公司估值

    python 概率分布模型 Note from Towards Data Science's editors: While we allow independent authors to publis ...

  3. 纯真IP库的结构分析及一个查询类

    个人网站上有个功能,记录访问者的IP及其归属地.最初我偷懒通过一个WebService来查询IP归属地,后来觉得通过这种方法响应时间长,资源耗费大,而且对那个WebSerice的依赖度太高,如果它挂了 ...

  4. CnSeu社工库免费查询_ip代理-golang测试纯真ip库与免费版ipip.net库比较

    ip代理-golang测试纯真ip库与免费版ipip.net库比较 本篇文章主要为使用golang测试国内两款纯真ip数据库与ipip.net免费版数据库进行操作,当输入一个ip地址或域名时可以看到输 ...

  5. qq纯真IP库安装及更新

    QQ纯真IP库和命令,其主要功能就是把一些网络工具的输出的IP字符串,附加上地理位置信息(使用纯真数据库).例如218.65.137.1会变成218.65.137.1[广西南宁市电信]. qqwry. ...

  6. 根据IP地址获取真实IP所在地区 ,使用纯真IP库(纯真版20160215)

     package com.alpha.util; import java.io.ByteArrayOutputStream; import java.io.IOException; import ...

  7. Discuz!开发之替换系统IP库为纯真IP库的方法

    Discuz!默认使用的IP库只有1M,运行时占用资源少,但很多ip不准确,更新也慢,默认存放的路径在data/ipdata/tinyipdata.dat,这里给大家介绍如何将系统IP库换成纯真ip库 ...

  8. python进行数据分析需要安装哪两个库_对Python进行数据分析_关于Package的安装问题...

    一.为什么要使用Python进行数据分析? python拥有一个巨大的活跃的科学计算社区,拥有不断改良的库,能够轻松的集成C,C++,Fortran代码(Cython项目),可以同时用于研究和原型的构 ...

  9. python人脸识别库_基于Python的face_recognition库实现人脸识别

    Python Python开发 Python语言 基于Python的face_recognition库实现人脸识别 一.face_recognition库简介 face_recognition是Pyt ...

最新文章

  1. emoji mysql 转 unicode_unicode和emoji编码
  2. linux pid t 头文件_Linux信号处理
  3. c语言指向常量的指针和常量指针
  4. RabbitMQ播放模块! 构架
  5. LeetCode C语言刷题——day1
  6. python Web 之基石 - - CGI 编程 (基于python3)
  7. 《WCF全面解析》(下册)- 目录
  8. matlab图像分类器,[转载]两种图像分类算法和matlab源代码
  9. Question 20171117 Java中的编码问题?
  10. JavaEE之HTML常见标签及个人简历制作
  11. 我是如何次次《头脑王者》获得满分的
  12. 量子物理与计算机,量子计算机与量子物理
  13. Java 使用记事本编写第一个java程序
  14. C# DateTime:日期、日期差、时间、时间差
  15. 鸿蒙开发者招募!给后辈的一点建议,终局之战
  16. 了解python正则表达式
  17. 面试官:RecyclerView布局动画原理了解吗?
  18. [程序设计]前端Web页面使用原生JavaScript实现校验身份证号码在算法层面是否合法
  19. Classification and inference with machine learning
  20. 苹果cms模板_苹果cms怎么更换模板?

热门文章

  1. qt-sdk-linux,在linux系统上安装qt-sdk步骤.doc
  2. switch java 语法_Java_基础语法之switch语句
  3. 多态——面向接口编程
  4. 网易云深度学习第二课notebook1
  5. 数据结构—链表-单链表应用-删除元素最大的节点
  6. 邀请函丨云和恩墨邀您一起迈向混合数据库时代!
  7. 技术实践:教你用Python搭建gRPC服务
  8. 你的Parquet该升级了:IOException: totalValueCount == 0问题定位之旅
  9. 【华为云技术分享】实战案例丨代码优化:如何去除context中的warning?
  10. 【直播分享】实现LOL小地图英雄头像分析案例【华为云分享】