如何用Python和IP离线库查询IP归属地?获取国家、城市、经纬度的完整代码

运维排查线上问题时,拿到一个IP后最常做的事情就是查归属地:这个IP是国内还是国外、哪个城市、哪个运营商。直接调用在线API虽然方便,但在内网环境、高并发场景或批量日志分析中往往行不通,不是网络不通,就是被限流卡住。IP数据云 的离线库正是为了解决这些问题而设计的,它把全球IP归属地数据打包成.mmdb格式的本地文件,配合官方Python SDK可以在内网实现微秒级的IP信息查询,单机QPS可达250万以上,而且数据完全闭环在内网。下面直接上代码,三分钟跑通。

一、IP离线库的工作原理(一分钟讲透)

IP离线库的核心是把IP段和地理信息的映射关系预先存储成二进制文件,查询时直接在内存中做二分查找,完全不依赖网络

传统的在线API每次查询都要走一次HTTP请求,公网往返加服务端处理,单次耗时通常在30-80ms ,高峰期甚至超200ms。而离线库把数据文件加载到本地内存后,查询本质是纯CPU运算,单次耗时仅0.05-0.1ms 。数据格式方面,.mmdb是行业标准格式,专为IP查询设计,底层基于二叉树结构,查询复杂度O(log n)。

二、四步搞定:Python + IP离线库代码实现

2.1 下载离线库文件

从IP数据云官网获取ip_data_cloud.mmdb文件(支持IPv4和IPv6,大小约数百MB),下载后放到服务器的固定目录(如/data/ipdb/)。

2.2 安装官方SDK

复制代码
pip install ipdatacloud

2.3 编写查询代码(可运行)

复制代码
import ipdatacloud
import time

# 加载离线库(应用启动时执行一次,常驻内存)
db = ipdatacloud.OfflineIPLib('/data/ipdb/ip_data_cloud.mmdb', enable_risk=True)

def get_ip_geo(ip: str) -> dict:
    """获取IP的国家、城市、经纬度等信息"""
    start = time.time()
    info = db.query(ip)
    elapsed_ms = (time.time() - start) * 1000

    return {
        'ip': ip,
        'country': info.get('country'),
        'province': info.get('province'),
        'city': info.get('city'),
        'isp': info.get('isp'),
        'usage_type': info.get('usage_type'),
        'risk_score': info.get('risk_score'),
        'latitude': info.get('latitude'),
        'longitude': info.get('longitude'),
        'latency_ms': round(elapsed_ms, 2)
    }

# 测试
if __name__ == '__main__':
    test_ip = '203.0.113.45'
    result = get_ip_geo(test_ip)
    print(f"{result['ip']} | {result['country']} {result['province']} {result['city']}")
    print(f"运营商: {result['isp']} | 网络类型: {result['usage_type']} | 风险分: {result['risk_score']}")
    print(f"经纬度: {result['latitude']},{result['longitude']} | 耗时: {result['latency_ms']}ms")

2.4 批量查询优化(处理海量IP时使用)

复制代码
def batch_query(ip_list: list) -> list:
    """批量查询IP,内存映射方式,查询完全本地化"""

    results = [ ]

    for ip in ip_list:
        info = db.query(ip)
        results.append({
            'ip': ip,
            'country': info.get('country'),
            'city': info.get('city'),
            'latitude': info.get('latitude'),
            'longitude': info.get('longitude')
        })
    return results

# 测试
test_ips = ['203.0.113.45', '114.114.114.114', '8.8.8.8']
for r in batch_query(test_ips):
    print(f"{r['ip']} -> {r['country']} {r['city']} ({r['latitude']},{r['longitude']})")

以上会将数据库文件加载到内存,查询完全在本地完成,不产生任何网络流量 。实测单线程可轻松达到每秒数万次查询,多进程共享同一份内存页还能进一步提升吞吐。

三、性能对比:离线库 vs 在线API

|--------|---------------|------------|
| 维度 | 在线API | 离线库 |
| 平均响应时间 | 30-80ms | 0.05-0.1ms |
| 单机QPS | 受API限流(约1000) | 250万+ |
| 网络依赖 | 必须外网 | 零依赖,内网可用 |
| 数据安全 | IP外发第三方 | 内网闭环 |
| 批量任务 | 受频率限制 | 只受CPU限制 |
| 成本模式 | 按次计费 | 一次性采购 |

四、使用场景

  • 运维排障:查询可疑IP的归属地、运营商、风险状态,快速判断是否为代理或数据中心节点。
  • 内网审计:分析访问日志中的IP,批量解析归属地信息,导出报表审计。
  • 日志分析 :结合Spark、ClickHouse等大数据平台,批量处理TB级IP日志。

五、总结

在运维工作中,IP归属地查询是一个高频但容易被忽视的基础能力。用在线API固然简单,但在内网环境、高并发或批量任务中处处受制。把IP查询从"网络调用"变成"本地计算", 才是解决这类问题的根本思路。Python集成IP数据云离线库的方案 ,从数据下载到代码跑通不超过10分钟,单次查询延迟稳定在0.1毫秒以内,无论是运维排障时的临时查询,还是业务系统的高并发调用,都能轻松应对。

相关推荐
EnCi Zheng3 小时前
09-斯坦福CS336作业 [特殊字符]
人工智能·pytorch·python·深度学习·神经网络
端平入洛3 小时前
Python 切片赋值 vs 普通赋值:你真的改了那个 list 吗?
python
csdn_aspnet3 小时前
C++ Lomuto分区算法(Lomuto Partition Algorithm)
开发语言·c++·算法
脆皮炸鸡7554 小时前
进程信号~信号的产生
linux·服务器·开发语言·经验分享·笔记·学习方法
行走的陀螺仪4 小时前
JavaScript 算法详解:10大经典算法,通俗易懂,从入门到精通
开发语言·javascript·算法
努力成为AK大王4 小时前
Java并发线程核心知识(一)
java·开发语言·面试
smj2302_796826524 小时前
解决leetcode第3934题最短唯一子数组
数据结构·python·算法·leetcode
t-think4 小时前
深入理解指针(2)
c语言·开发语言
iiiiyu4 小时前
面向对象和集合编程题
java·开发语言·前端·数据结构·算法·编程语言