前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >一文教你识别IP地址所属国家和城市

一文教你识别IP地址所属国家和城市

原创
作者头像
Luoyger
发布2024-05-13 17:04:10
4140
发布2024-05-13 17:04:10
举报

在网关的应用中,有时会有限制服务在指定的国家和城市进行开放,目前主流的方案有使用付费的在线API和使用离线的IP数据库。接下来将介绍这两种方案的实际应用。

付费API

腾讯云上的千帆云市场就有大量的第三方企业提供的付费API服务,比如:https://market.cloud.tencent.com/products/30498,这种方式的API通常是按次数计费,35元就能调用一百万次。

商品详情页面也提供了API接口的不同语言的调用示例,其中在头部信息中的secretId和secretKey需要购买服务后从腾讯云平台中获取。

接口返回的数据示例如下,更多接口信息请参考详情页面。

代码语言:json
复制
{
  "code": 200, //  详见code返回码说明
  "msg": "成功", //   code对应的描述
  "charge": true, 
  "taskNo": "69564903663951243279", // 本次唯一请求号
  "data": {
    "country": "中国",  // 国家
    "country_id": "CN", // 国家编号
    "area": "华东", //地域
    "region": "浙江", //省份
    "region_id": "330000", //省份编号
    "city": "杭州", //城市
    "city_id": "330100", //城市编号
    "ip": "120.26.64.20",
    "long_ip": "2014986260",
    "isp": "移动" // 运营商
  }
}

需要注意的是,这种调用API的方式会收到第三方服务的性能限制,咨询过商家,建议QPS在100左右,超过之后可能会报错,因为服务是所有用户共用。

本地解析

本地解析的前提是要获取IP相关的数据库,目前比较主流的是maxmind的IP库,也有其它的IP解析服务商如ipinfo

Maxmind

Maxmind是IP数据领域中的专业级公司,在注册平台之后,免费用户可以获取lite版本的数据库,该数据库每周更新一次,如果需要更精确的调用需求,则可以考虑升级付费用户,数据库更精确,且每天更新一次。

下载链接如下,在链接中更新个人的license_key信息,也可以在页面中自行选择需要下载的内容。

代码语言:javascript
复制
https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-City&license_key=xxxx&suffix=tar.gz

使用示例如下,使用的SDK是geoip2,在Maxmind开源的SDK maxminddb基础上再封装了一层。

代码语言:go
复制
import (
    "encoding/json"
    "fmt"
    "log"
    "net"

    "github.com/oschwald/geoip2-golang"
)

const ipCityDataPath = "../data/GeoLite2-City.mmdb"

func main() {
    // 要查询的IP地址
    ip := "x.x.x.x"

    // 本地maxmind数据库调用
    geoip2DB, err := geoip2.Open(ipCityDataPath)
    if err != nil {
        log.Printf("country: %v", err.Error())
        println(err)
        return
    }
    parseIP := net.ParseIP(ip)
    country, err := geoip2DB.Country(parseIP)
    if err != nil {
        println(err)
        return
    }
    city, err := geoip2DB.City(parseIP)
    if err != nil {
        println(err)
        return
    }
    val, _ := json.Marshal(city)

    log.Printf("local db resp country: %s, city: %v", country.Country.IsoCode, city.City.Names)
    log.Printf("local db resp: %v", string(val))
}

返回的示例如下,注意,有可能获取不到City的相关信息,Names可能为null,但是还是可以获取到Location中的经纬度,根据经纬度也能获取到城市信息。

代码语言:json
复制
{
    "City": {
        "Names": {
            "de": "Bangkok",
            "en": "Bangkok",
            "es": "Bangkok",
            "fr": "Bangkok",
            "ja": "バンコク",
            "pt-BR": "Banguecoque",
            "ru": "Бангкок",
            "zh-CN": "曼谷"
        },
        "GeoNameID": 1609350
    },
    "Postal": {
        "Code": "10200"
    },
    "Continent": {
        "Names": {
            "de": "Asien",
            "en": "Asia",
            "es": "Asia",
            "fr": "Asie",
            "ja": "アジア",
            "pt-BR": "Ásia",
            "ru": "Азия",
            "zh-CN": "亚洲"
        },
        "Code": "AS",
        "GeoNameID": 6255147
    },
    "Subdivisions": [
        {
            "Names": {
                "en": "Bangkok",
                "ja": "バンコク",
                "zh-CN": "曼谷"
            },
            "IsoCode": "10",
            "GeoNameID": 1609348
        }
    ],
    "RepresentedCountry": {
        "Names": null,
        "IsoCode": "",
        "Type": "",
        "GeoNameID": 0,
        "IsInEuropeanUnion": false
    },
    "Country": {
        "Names": {
            "de": "Thailand",
            "en": "Thailand",
            "es": "Tailandia",
            "fr": "Thaïlande",
            "ja": "タイ王国",
            "pt-BR": "Tailândia",
            "ru": "Таиланд",
            "zh-CN": "泰国"
        },
        "IsoCode": "TH",
        "GeoNameID": 1605651,
        "IsInEuropeanUnion": false
    },
    "RegisteredCountry": {
        "Names": {
            "de": "Deutschland",
            "en": "Germany",
            "es": "Alemania",
            "fr": "Allemagne",
            "ja": "ドイツ連邦共和国",
            "pt-BR": "Alemanha",
            "ru": "ФРГ",
            "zh-CN": "德国"
        },
        "IsoCode": "DE",
        "GeoNameID": 2921044,
        "IsInEuropeanUnion": true
    },
    "Location": {
        "TimeZone": "Asia/Bangkok",
        "Latitude": 13.7512,
        "Longitude": 100.5172,
        "MetroCode": 0,
        "AccuracyRadius": 20
    },
    "Traits": {
        "IsAnonymousProxy": false,
        "IsSatelliteProvider": false
    }
}

IPInfo

IpInfo在注册之后,也能获取每月50k的免费调用次数,可以获取到城市信息,如果需要更多调用需求,则可以考虑升级付费用户。

当然也可以在页面https://ipinfo.io/account/data-downloads中下载所需要的离线IP数据库,支持IPv4和IPv6,不过只能精确到国家。一般下载选择mmdb数据格式,后续可以用现有SDK快速解析,离线的数据库每天更新一次,后续可以通过脚本每日从下载链接中更新数据库。

使用示例如下,使用的SDK就是Maxmind开源的maxminddb。

代码语言:go
复制
import (
    "encoding/json"
    "fmt"
    "log"
    "net"

    "github.com/oschwald/maxminddb-golang"
)

const ipCityDataPath = "../data/Country.mmdb"

func main() {
    // 要查询的IP地址
    ip := "x.x.x.x"

    // 本地infoip数据库调用
    db, err := maxminddb.Open(ipCityDataPath)
    if err != nil {
       log.Fatal(err)
    }
    defer db.Close()
    ipNet := net.ParseIP(ip)

    var record any
    err = db.Lookup(ipNet, &record)
    if err != nil {
       log.Fatal(err)
    }
    result := record.(map[string]interface{})
    fmt.Printf("local db resp Country: %s\n", result["country"])
    log.Printf("local db resp: %v", result)
}

返回的示例如下:

代码语言:json
复制
{
  "ip": "1.194.x.x",
  "hostname": "194.1.broad.ha.dynamic.163data.com.cn",
  "region": "Henan",
  "country": "CN",
  "loc": "34.7578,113.6486",
  "org": "AS4134 CHINANET-BACKBONE",
  "postal": "450000",
  "timezone": "Asia/Shanghai"
}

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 付费API
  • 本地解析
    • Maxmind
      • IPInfo
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档