Python中如何根据IP查询地区?分享一个自制的Python轮子实现

项目地址: https://github.com/459217974/ip2region 从本地数据库查询,速度很快,通过 Tornado IOLoop 可以自动从网上更新数据库。 希望有大佬可以教教我 Cython,昨天刚学的,觉得性能还可以优化一下。


Python中如何根据IP查询地区?分享一个自制的Python轮子实现
3 回复

要基于IP查地区,一个直接的办法是用现成的IP库。我写了个简单的轮子,用到了ip2region这个本地查询方案,比调用外部API更稳定快速。

首先安装依赖:

pip install ip2region

然后是这个轮子的核心代码:

import os
import socket
from ip2region import ip2region

class IPLocator:
    def __init__(self, db_path=None):
        """
        初始化IP定位器
        
        Args:
            db_path: ip2region数据库文件路径,默认使用包内自带的
        """
        if db_path is None:
            # 使用包自带的数据库
            import ip2region
            db_path = os.path.join(os.path.dirname(ip2region.__file__), 'data', 'ip2region.db')
        
        if not os.path.exists(db_path):
            raise FileNotFoundError(f"IP数据库文件不存在: {db_path}")
        
        self.searcher = ip2region.Ip2Region(db_path)
    
    def query(self, ip):
        """
        查询IP对应的地区信息
        
        Args:
            ip: 要查询的IP地址
            
        Returns:
            dict: 包含国家、省份、城市、ISP等信息
        """
        # 验证IP格式
        try:
            socket.inet_aton(ip)
        except socket.error:
            raise ValueError(f"无效的IP地址: {ip}")
        
        # 执行查询
        result = self.searcher.memorySearch(ip)
        
        # 解析结果
        region_info = {
            'ip': ip,
            'country': result.country,
            'region': result.region,
            'province': result.province,
            'city': result.city,
            'isp': result.isp
        }
        
        return region_info
    
    def batch_query(self, ip_list):
        """
        批量查询IP地址
        
        Args:
            ip_list: IP地址列表
            
        Returns:
            list: 每个IP的查询结果列表
        """
        results = []
        for ip in ip_list:
            try:
                results.append(self.query(ip))
            except Exception as e:
                results.append({'ip': ip, 'error': str(e)})
        
        return results
    
    def close(self):
        """关闭数据库连接"""
        if hasattr(self, 'searcher'):
            self.searcher.close()

# 使用示例
if __name__ == "__main__":
    # 创建定位器实例
    locator = IPLocator()
    
    # 单个IP查询
    ip = "8.8.8.8"
    result = locator.query(ip)
    print(f"查询 {ip}:")
    print(f"  国家: {result['country']}")
    print(f"  地区: {result['region']}")
    print(f"  省份: {result['province']}")
    print(f"  城市: {result['city']}")
    print(f"  ISP: {result['isp']}")
    
    # 批量查询
    ips = ["114.114.114.114", "223.5.5.5", "invalid_ip"]
    results = locator.batch_query(ips)
    print("\n批量查询结果:")
    for res in results:
        if 'error' in res:
            print(f"  {res['ip']}: 错误 - {res['error']}")
        else:
            print(f"  {res['ip']}: {res['country']}/{res['city']}")
    
    # 记得关闭连接
    locator.close()

这个实现有几个关键点:

  1. 使用本地数据库,查询速度快且不依赖网络
  2. 支持单个和批量查询
  3. 包含基本的IP格式验证
  4. 结果以字典形式返回,方便进一步处理

ip2region的数据库文件需要定期更新以获取最新的IP分配信息,可以从项目仓库下载最新的ip2region.db文件。

简单说就是:用本地IP库查地区,又快又稳。


项目里已经感谢了原项目并且跟原项 owner 说了呢。我也可以详细说一下数据来源,谢谢你提醒

回到顶部