一、简述

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

二、纯真数据库简述

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

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

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

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



python解析LDF数据_数据库

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

python解析LDF数据_python_02

四、通过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归属地进行解析,能方便看出一些异常情况。