通过python解析纯真IP数据库

一、简述

通过python解析纯真IP数据库,并且能够快速匹配查询指定的IP归属地。

二、纯真数据库简述

纯真(CZ88.NET)自2005年起一直为广大社区用户提供社区版IP地址库,只要获得纯真的授权就能免费使用,并不断获取后续更新的版本。

纯真除了免费的社区版IP库外,还提供数据更加准确、服务更加周全的商业版IP地址查询数据。纯真围绕IP地址,基于 网络空间拓扑测绘 + 移动位置大数据 方案,对IP地址定位、IP网络风险、IP使用场景、IP网络类型、秒拨侦测、VPN侦测、代理侦测、爬虫侦测、真人度等均有近20年丰富的数据沉淀。

三、纯真IP数据库社区版获取方法

1)通过关注公众号,获取社区版数据库文章地址

​​​​​​
​​在这里插入图片描述

2)下载并安装应用程序后,点击解压,获取到txt格式的IP数据库

在这里插入图片描述

四、通过python解析导出的txt类型数据库

1)基本思路

将IP数据库的每行读取出来,然后进去切割,切割后的数据存储到区间树中。

2)加载IP数据库到内存中

这个过程会比较久,原因是在生成节点添加到区间树的时候会有较大开销。
    def load_ip_data(self, file_path):
        """
        加载IP地址范围和实际地址的数据
        :param file_path: 包含IP地址范围数据的文件路径
        :return: 包含所有IP范围与实际地址映射的字典
        """
        ip_data = {}
        with open(file_path, 'r') as file:
            for line in file:
                parts = line.strip().split()
                if len(parts) >= 3:
                    start_ip = int(parts[0])
                    end_ip = int(parts[1])
                    location = ' '.join(parts[2:])
                    #ip_data[(start_ip, end_ip)] = location
                    if start_ip !=end_ip:
                        self.tree.add(Interval(start_ip, end_ip,location))
                        self.rangs[start_ip]=location
                    else:
                        self.rangs[start_ip]=location
                    #print('ip:',start_ip,'location:',location)
                    
        return ip_data

3)给定一个IP,返回对应的实际地址

    def find_ip_location(self, ip):
        """
        根据输入的IP地址查找实际地址
        :param ip: 输入的IP地址
        :return: 输入IP地址对应的地理位置,如果未找到则返回""
        """
        ip_int=int.from_bytes(socket.inet_aton(ip), byteorder='big')
        matching_intervals = self.tree[ip_int]
        data=''
        if matching_intervals:        
            for match in matching_intervals:
                data=match.data
        else:
            if ip_int in self.rangs:
                data = self.rangs[ip_int]
                
            else:
                print(f"值 {ip} 不在任何区间内。")
        
        return data

4)对IP段内仅仅只有一个IP的处理方式

以起始IP为key,用一个字典存储
                    if start_ip !=end_ip:
                        self.tree.add(Interval(start_ip, end_ip,location))
                        self.rangs[start_ip]=location
                    else:
                        self.rangs[start_ip]=location

5)完整代码

import socket
from intervaltree import Interval, IntervalTree

class IPGeoLocator:
    def __init__(self, ip_data_file):
        """
        初始化IP地址地理位置定位器
        :param ip_data_file: 包含IP地址范围数据的文件路径
        """
        self.tree= IntervalTree()
        self.rangs={}
        self.load_ip_data(ip_data_file)

    def load_ip_data(self, file_path):
        """
        加载IP地址范围和实际地址的数据
        :param file_path: 包含IP地址范围数据的文件路径
        :return: 包含所有IP范围与实际地址映射的字典
        """
        ip_data = {}
        with open(file_path, 'r') as file:
            for line in file:
                parts = line.strip().split()
                if len(parts) >= 3:
                    start_ip = int(parts[0])
                    end_ip = int(parts[1])
                    location = ' '.join(parts[2:])
                    #ip_data[(start_ip, end_ip)] = location
                    if start_ip !=end_ip:
                        self.tree.add(Interval(start_ip, end_ip,location))
                        self.rangs[start_ip]=location
                    else:
                        self.rangs[start_ip]=location
                    #print('ip:',start_ip,'location:',location)
                    
        return ip_data

    def find_ip_location(self, ip):
        """
        根据输入的IP地址查找实际地址
        :param ip: 输入的IP地址
        :return: 输入IP地址对应的地理位置,如果未找到则返回""
        """
        ip_int=int.from_bytes(socket.inet_aton(ip), byteorder='big')
        matching_intervals = self.tree[ip_int]
        data=''
        if matching_intervals:        
            for match in matching_intervals:
                data=match.data
        else:
            if ip_int in self.rangs:
                data = self.rangs[ip_int]
                
            else:
                print(f"值 {ip} 不在任何区间内。")
        
        return data

# 使用示例
if __name__ == "__main__":
    ip_locator = IPGeoLocator("ip_ranges.txt")  # 假设你的文本文件名为ip_ranges.txt
    
    # 示例查询
    query_ip = "127.0.0.1"
    location = ip_locator.find_ip_location(query_ip)
    print(f"IP地址 {query_ip} 对应的实际地址是:{location}")

五、总结

记录下IP归属地解析的方法,在安全运维以溯源中都是挺好用的工具。可以在解析了中间件日志,如access.log、IIS访问日志时,对IP归属地进行解析,能方便看出一些异常情况。

本模块代码是针对在 2011 年在 CSDN 论坛个发布的“最新 NET 读取纯真IP数据库代码(C#)”源码,做了一次升级,这次升级不是简单的修补,是本人精心的重写,现在只需要 5 分哦,您值得拥有!该源代码不同于网上的代码,网上代码基本可分为两大类,第一类直接使用文件流,通过移动文件流指针(即更改 Stream.Position 属性值)搜索 IP 地址对应的信息,此类代码问题是:其一移动文件指针效率是比较低的(给 Position 赋值),多线程并发时,会重复打开多个文件效率更加底下;第二类是把文件直接加载内存中,通过这种缓冲,速度是提升了,但并没有为多线程环境优化,多线程并发时(如:Web 中每位访客,都是一根线程),意味会重复的读取文件,重复的创建缓存,浪费内存空间。 该源代码特点是考虑到了多线程应用环境(如:Web 每个会话,都是一根线程),设计了缓存对象 QQWryCache 用于管理缓存,用 QQCacheStream 流读取缓存数据。在多线程应用环境中,假设 10 根线程访问同一个纯真 IP 数据库时,只会开辟 1 份缓存,给多根线程共享,避免了不必要的内存浪费。 注1:本模块代码,保证所有静态方法都是线程安全的,但不保证所有实例方法都是线程安全的。 注2:每根线程访问缓存时,请通过 QQWryCache.GetCache 静态方法获取缓存对象。 注3:多根线程获取到的缓存对象,通常都是同一对象,该对象已经考虑了线程同步,不必担心线程安全问题。 /* >>> 使用完全缓存(缓存整个文件,约 8.8MB),调用方法如下: */ QQWryCache cache = QQWryCache.GetCache("qqwry.dat", true); Stream stream = cache.GetCacheStream(); QQWrySearcher searcher = new QQwryScanner(stream); QQWryLocation location = searcher.Query("IP 地址"); Console.WritleLine("Country = {0}, Location = {1}", location.Country, location.Location); /* 完全缓冲, * 缓存一旦初始化完毕,就会自动关闭文件, * 所以不再依赖于文件,因此可以不用关闭缓冲流, * 下面调用 Close 方法,其实没有实际意义,但也不会引发异常。 */ stream.Close(); /* >>> 使用索引缓存(仅缓存索引部分,约 3MB),调用方法如下: <<>> 直接使用文件流(不使用缓存),调用方法如下: <<>> 遍历 IP 数据库。 <<< */ QQWryCache cache = QQWryCache.GetCache("qqwry.dat", true); Stream stream = cache.GetCacheStream(); QQWrySearcher searcher = new QQWrySearcher(stream); // 用 for 循环遍历 for(int i = 0; i < searcher.Count; i++) { QQWryIpLocation item = searcher[i]; Console.WritleLine("Country = {0}, Location = {1}", location.Country, location.Location); } // 用 foreach 循环遍历 foreach(QQWryIpLocation item in searcher) { QQWryIpLocation item = searcher[i]; Console.WritleLine("Country = {0}, Location = {1}", location.Country, location.Location); }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值