qqzeng-ip.dat IP库读取python版

qqzeng-ip.dat是一个特殊格式的dat文件,可以快速的查找IP对应的地理位置信息。据作者测试的结果来看,是100万ip查找速度0.5秒。

当然这和语言有非常大的关系,python的循环性能一直是为人所诟病的。目前python版本测试的结果是10万IP的查找速度是3.X秒左右,还算够用,毕竟真实情况下的30秒~5分钟内的日志不太可能出现一批数据中的不重复IP超过10万个。

作者提供了解析dat的java/c/php脚本,但没有提供python版本的。所以我就写了一个,以供需要用python语言读取ip的地理位置信息使用。

代码如下:

#coding:utf-8
import os
import math
import socket
import struct
import io
from io import SEEK_SET

path = os.path.normpath(os.path.dirname(os.path.abspath(__file__)) + "/qqzeng-ip-utf8.dat")

class IpSearch(object):
    fp = None
    firstStartIpOffset = None
    lastStartIpOffset = None
    preStartOffset = None
    preEndOffset = None
    ipCount = None
    prefixCount = None
    prefixList = dict()

    def __init__(self):
        self.fp = io.open(path,"rb")
        buff = self.fp.read(16)
        self.firstStartIpOffset = self.bytesToLong(buff[0],buff[1],buff[2],buff[3])
        self.lastStartIpOffset = self.bytesToLong(buff[4],buff[5],buff[6],buff[7])
        self.preStartOffset = self.bytesToLong(buff[8],buff[9],buff[10],buff[11])
        self.preEndOffset = self.bytesToLong(buff[12],buff[13],buff[14],buff[15])
        self.ipCount = (self.lastStartIpOffset - self.firstStartIpOffset) / 12 + 1
        self.prefixCount = (self.preEndOffset - self.preStartOffset) / 9 + 1

        self.fp.seek(self.preStartOffset,SEEK_SET)
        preBuff = self.fp.read(self.prefixCount*9)
        for k in range(0,self.prefixCount):
            i = k*9
            startIndex = self.bytesToLong(preBuff[1+i],preBuff[2+i],preBuff[3+i],preBuff[4+i])
            endIndex = self.bytesToLong(preBuff[5+i],preBuff[6+i],preBuff[7+i],preBuff[8+i])
            self.prefixList[ord(preBuff[i])] = {
                "start_index":startIndex,
                "end_index":endIndex
            }

    def __del__(self):
        if self.fp != None:
            self.fp.close()

    def get(self,ip):
        if ip == '':
            return ""

        high = 0
        low = 0
        startIp = 0
        endIp = 0
        localOffset = 0
        localLength = 0
        prefix = ip.split(".")[0]
        prefix = int(prefix)
        ipnum = self.ip2unit(ip)
        if prefix in self.prefixList.keys():
            index = self.prefixList[prefix]
            low = index["start_index"]
            high = index["end_index"]
        else:
            return ""

        left = low if low == high else self.binarySearch(low,high,ipnum)
        left,startIp,endIp,localOffset,localLength = self.getIndex(left,startIp,endIp,localOffset,localLength)
        if startIp <= ipnum and endIp >= ipnum:
            return self.getLocal(localOffset,localLength)
        else:
            return ""

    def getLocal(self,localOffset,localLength):
        self.fp.seek(localOffset,SEEK_SET)
        return self.fp.read(localLength)

    def getIndex(self,left,startIp,endIp,localOffset,localLength):
        leftOffset = self.firstStartIpOffset + left*12
        self.fp.seek(leftOffset,SEEK_SET)
        buff = self.fp.read(12)
        startIp = self.bytesToLong(buff[0],buff[1],buff[2],buff[3])
        endIp = self.bytesToLong(buff[4],buff[5],buff[6],buff[7])
        r3 = (ord(buff[8]) << 0 | ord(buff[9]) << 8 | ord(buff[10]) << 16)
        if r3 < 0:
            r3 += 4294967296
        localOffset = r3
        localLength = ord(buff[11])

        return [left,startIp,endIp,localOffset,localLength]

    def binarySearch(self,low,high,k):
        m = 0
        while low <= high:
            mid = (low + high)/2
            endIpNum = self.getEndIpNum(mid)
            if endIpNum >= k:
                m = mid
                if mid == 0:
                    break
                high = mid - 1
            else:
                low = mid + 1
        return m

    def getEndIpNum(self,left):
        leftOffset = self.firstStartIpOffset + (left*12) + 4
        self.fp.seek(leftOffset,SEEK_SET)
        buf = self.fp.read(4)
        return self.bytesToLong(buf[0],buf[1],buf[2],buf[3])

    def ip2unit(self,ip):
        lip = self.ip2long(ip)
        if lip < 0:
            lip += 4294967296
        return lip

    def ip2long(self,ip):
        packedIP = socket.inet_aton(ip)
        return struct.unpack("!L", packedIP)[0] 

    def bytesToLong(self,a,b,c,d):
        iplong = (ord(a) << 0) | (ord(b) << 8) | (ord(c) << 16) | (ord(d) << 24)
        if iplong < 0:
            iplong += 4294967296
        return iplong

if __name__ == '__main__':
    ipSearch = IpSearch()
    print ipSearch.get("210.51.200.123").decode("utf-8").encode("gbk")

    import time
    startTime = time.time()
    for i in range(0,100000):
        ipSearch.get("210.51.200.123")
    endTime = time.time()
    print "time waste:",endTime-startTime

测试结果如下:

与百度查出的IP信息进行对比:

还挺不错的,对吧。

时间: 2024-07-30 03:15:55

qqzeng-ip.dat IP库读取python版的相关文章

ip地址定位库

ip2region 1.2.1 发布了,新增 Python 内存查询+数据文件更新. 准确率99.9%的ip地址定位库,0.0x毫秒级查询,数据库文件大小只有1.5M,提供了java, php, c, python, nodejs查询绑定和Binary,B树,内存三种查询算法,妈妈再也不用担心我的ip地址定位! 1.2.1更新内容如下: 1,python查询客户端增加内存查询模式. 2,数据更新至2016/07/12版本,届时ip2region.db文件大小1.6M. 版本仓库地址: http:

强大的IP地址定位库--ip2region 的初步使用

2019年05月05日 开源的IP 地址定位库 ip2region 1.9.0 发布了,功能还是很不错的,下面我就应用下ip2region,来解析ip的地址 一.下载ip库并解压地址为:https://github.com/lionsoul2014/ip2region/archive/v1.9.0-release.tar.gz解压 把ip2region.db粘贴到我们maven工程的resources下 二.添加ip2region依赖 <dependency> <groupId>o

微信支付SDK(python版)

最近一段时间一直在搞微信平台开发,最近的v3.37版本微信支付接口变化贼大,所以就看着php的demo移植为 python版,为了保持一致,所以接口方法基本都没有变,这样的好处就是不用写demo了,看着微信官方的demo 照葫芦画瓢就可以了. 我已经把代码放到github了,https://github.com/Skycrab/wzhifuSDK,我主要测试了JsApi调用方式,其它的调用方式并没有测试,如果你发现了bug,请多多pull request,我将不甚感激. 方便观看,代码贴于此.

不依赖任何额外的运行库S/MIME版使用公钥密码系统

/n software IP*Works! S/MIME版使用公钥密码系统标准(PKCS)实现基于S/MIME V2标准的加密和解密./n software IP*Works! S/MIME不仅可以加密文件.邮件和新闻组文章,还可以用X.509数字证书署上消息签名.验证消息的签名.它包含的组件有:通用的S/MIME组件(SMIME).证书管理(CertMgr).可激活S/MIME的IP*Works! POP3.IMAP4. NNTP和 SMTP组件. 产品特征: 100% C# .NET组件,用

FastDFS客户端(Python版)指南

最近做了一个分布式的项目用到了FastDFS,关于FastDFS这里就不阐述了,有兴趣了解的小伙伴,请到官网:http://bbs.chinaunix.net/forum-240-1.html.这里着重介绍FastDFS客户端(Python版),此版客户端已经用于实际项目,目前运行稳定.项目托管于git,地址:https://github.com/cosysun/FastDFSClient_Python.git. 一.原理 在官方C++客户端的基础上重新封装C++接口,并提供给Python调用

python 版DES和MAC算法

最近工作中需要用到python中的DES算法,虽然有现成的库,但总感觉用着不方便.于是把之前用的C和Java写的DES和MAC算法移植到python中.测试了下没问题. 这样以后就方便了,.在python中终于可以用DES算法了.之前把C写的DES算法封装成动态库,然后由python的ctypes调用,虽然可以但是不是很方便. 附:python版DES算法源码,还未封装成类,仍在完善中.源码CSDN资源中可下载.直接编译执行没问题. #!/usr/bin/env python # -*- cod

编码的秘密(python版)

编码(python版) 最近在学习python的过程中,被不同的编码搞得有点晕,于是看了前人的留下的文档,加上自己的理解,准备写下来,分享给正在为编码苦苦了挣扎的你. 编码的概念 编码就是将信息从一种格式转换成另一种格式,计算机只认识二进制,简单的理解,将我们眼睛看到的文字转换为计算机能够识别的二进制格式视为编码,而二进制以某种编码格式转换为我们能看的文字的过程可以看成是解码.既然计算机只能认识二进制0,1,那么我们用的字母.数字和文字等是怎样和他们对应的呢?那就请继续看吧! python中查看

TCP/IP协议-IP协议

A contented mind is a perpetual feast. "知足长乐" 参考资料:TCP/IP入门经典 (第五版) TCP/IP详解 卷一:协议 一.简介 IP协议(Internet协议,网际协议),是TCP/IP协议族中最核心的协议,位于协议栈的网络层 既然位于网络层,所以IP协议最主要的功能就是 提供独立于硬件的逻辑寻址 和 支持网间数据传递的路由选择,我们将在后面的部分介绍这两个功能,下面先来分析一下IP首部 二.IP首部 我们在 TCP/IP协议-入门 中说

python 版 quicksort 快排

今天看了下苹果xml 解析,写了个小demo 心想还是 在博客上写点东西吧,毕竟很久很久都没有上来了 先上个效果图把 接下来 看下 工程目录图吧 本demo 分两种解析模式,一是苹果自带的, 首先先看下苹果自带的吧,工程文件为 NoteXMLParser 文件 ,另一种解析模式 是 NotesTBXMLParser文件 NoteXMLParser.h 文件代码如下 : // // NoteXMLParser.h // TestXML // // Created by choni on 14-5-