Golang — 根据IP获取地理位置信息
1 介绍
1.1 ip2region
ip2region
是一个离线IP地址定位库和IP定位数据管理框架,10微秒级别的查询效率,提供了众多主流编程语言的 xdb 数据生成和查询客户端实现。
特点:
- 是一个开源的IP地理位置库。
- 标准化的数据格式
每个 ip 数据段的 region 信息都固定了格式:国家|区域|省份|城市|ISP,只有中国的数据绝大部分精确到了城市,其他国家部分数据只能定位到国家,后前的选项全部是0。 - 数据去重和压缩
- 极速查询响应
即使是完全基于 xdb 文件的查询,单次查询响应时间在十微秒级别。 - IP 数据管理框架
缺点:
ip2region
重点在于 研究 IP 数据的存储和快速查询的实现
,并没有原始 IP 数据的支撑,本项目不保证及时的数据更新
,暂时也不会有商用版本。
1.2 geoip2-golang
geoip2-golang
只是一个使用示例,它所需的IP地理信息库是基于MaxMind
提供的 GeoLite2
和 GeoIP2
数据库。
特点:
maxmind
提供了免费的可在本地部署的geo-ip数据库(GeoLite2)(mmdb以及csv格式),和geo-ip查询api服务。- 支持ipv4和ipv6的地理信息查询,以及ASN数据库(ip-运营商信息查询)
- 免费的数据库
更新周期为两周一次
,需要付费才能得到最快的更新速度。
1.3 总结
推荐优先使用 geoip2-golang
,其次是ip2region
,如果需要更加精确的话,建议选择商用的。
2 使用
2.1 ip2region
-
下载ip地址库
到github:https://github.com/lionsoul2014/ip2region下载代码。 -
ip2region
的库
在data
下的ip2region.xdb
-
使用
package main
import (
"fmt"
"github.com/lionsoul2014/ip2region/binding/golang/xdb"
"net"
"time"
)
func main() {
ip2region()
}
func ip2region() {
var dbPath = "iputil/ip2region/ip2region.xdb"
searcher, err := xdb.NewWithFileOnly(dbPath)
if err != nil {
fmt.Printf("failed to create searcher: %s\n", err.Error())
return
}
defer searcher.Close()
var ip = "115.223.9.122"
var tStart = time.Now()
ips, err := net.LookupIP("www.github.com")
ipres := ips[0].String()
fmt.Printf("域名的ip:%s\n", ipres)
region, err := searcher.SearchByStr(ip)
if err != nil {
fmt.Printf("failed to SearchIP(%s): %s\n", ip, err)
return
}
fmt.Printf("{region: %s, took: %s}\n\n", region, time.Since(tStart))
// 备注:并发使用,每个 goroutine 需要创建一个独立的 searcher 对象。
}
结果:
域名的ip:20.205.243.166
{region: 中国|0|浙江省|温州市|电信, took: 70.8846ms}
2.2 geoip2-golang
geoip2-golang
只是一个使用示例,它所需的IP地理信息库是基于MaxMind
提供的 GeoLite2
和 GeoIP2
数据库。所以需要去MAXMID
官网注册账号,然后才能下载最新的IP地理位置库
。
- 注册
地址:https://www.maxmind.com/en/geolite2/signup,除了邮箱外,其他都不需要真实信息。 - 登录
- 下载最新的
IP地理位置库
登陆后点击 Download Databases进入下载选择页面
- 下载库文件
maxmind提供了六种免费的数据库,有mmdb
【推荐】,也有csv
格式。你也可以全部下载下来看看。
ASN数据库
从图中可以看到有些数据库的标题后面写着“ASN”三个字母,这个ASN的指的就是ip-运营商信息的数据库。
mmdb数据库
mmdb
是maxmind
自己的一种二进制数据库格式,它提供较快的ip查询速度。
这里我们只下载不是CSV格式
的库文件即可,即只下载红色圈起来的,右侧是下载按钮。
注意:MAXMIND
会记录下载,所以不要反复下载,以免被禁。
- 库文件
- GeoLite2-ASN_20230505.tar.gz
- GeoLite2-City_20230505.tar.gz
- GeoLite2-Country_20230505.tar.gz
解压后都是mmdb数据库类型,具体差别自己测试吧。
- 使用
- 下载
geoip2-golang
go get github.com/oschwald/geoip2-golang
代码示例:
package main
import (
"fmt"
"github.com/lionsoul2014/ip2region/binding/golang/xdb"
"github.com/oschwald/geoip2-golang"
"log"
"net"
"time"
)
func main() {
ip2region()
geoip()
}
func ip2region() {
var dbPath = "iputil/ip2region/ip2region.xdb"
searcher, err := xdb.NewWithFileOnly(dbPath)
if err != nil {
fmt.Printf("failed to create searcher: %s\n", err.Error())
return
}
defer searcher.Close()
var ip = "115.223.9.122"
var tStart = time.Now()
ips, err := net.LookupIP("www.github.com")
ipres := ips[0].String()
fmt.Printf("域名的ip:%s\n", ipres)
region, err := searcher.SearchByStr(ip)
if err != nil {
fmt.Printf("failed to SearchIP(%s): %s\n", ip, err)
return
}
fmt.Printf("{region: %s, took: %s}\n\n", region, time.Since(tStart))
// 备注:并发使用,每个 goroutine 需要创建一个独立的 searcher 对象。
}
func geoip() {
db, err := geoip2.Open("iputil/geolite2/GeoLite2-City.mmdb")
if err != nil {
log.Fatal(err)
}
defer db.Close()
// If you are using strings that may be invalid, check that ip is not nil
//ip := net.ParseIP("81.2.69.142")
ip := net.ParseIP("115.192.211.101")
record, err := db.City(ip)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Portuguese (BR) city name: %v\n", record.City.Names["pt-BR"])
if len(record.Subdivisions) > 0 {
fmt.Printf("English subdivision name: %v\n", record.Subdivisions[0].Names["en"])
}
fmt.Printf("Russian country name: %v\n", record.Country.Names["ru"])
fmt.Printf("ISO country code: %v\n", record.Country.IsoCode)
fmt.Printf("Time zone: %v\n", record.Location.TimeZone)
fmt.Printf("Coordinates: %v, %v\n", record.Location.Latitude, record.Location.Longitude)
// Output:
// Portuguese (BR) city name: Londres
// English subdivision name: England
// Russian country name: Великобритания
// ISO country code: GB
// Time zone: Europe/London
// Coordinates: 51.5142, -0.0931
fmt.Println("中文结果")
fmt.Printf("Portuguese (BR) city name: %v\n", record.City.Names["zh-CN"])
if len(record.Subdivisions) > 0 {
fmt.Printf("English subdivision name: %v\n", record.Subdivisions[0].Names["zh-CN"])
}
fmt.Printf("Russian country name: %v\n", record.Country.Names["zh-CN"])
fmt.Printf("ISO country code: %v\n", record.Country.IsoCode)
fmt.Printf("Time zone: %v\n", record.Location.TimeZone)
fmt.Printf("Coordinates: %v, %v\n", record.Location.Latitude, record.Location.Longitude)
}
结果:
Portuguese (BR) city name: Hangzhou
English subdivision name: Zhejiang
Russian country name: Китай
ISO country code: CN
Time zone: Asia/Shanghai
Coordinates: 30.2994, 120.1612
中文结果
Portuguese (BR) city name: 杭州
English subdivision name: 浙江省
Russian country name: 中国
ISO country code: CN
Time zone: Asia/Shanghai
Coordinates: 30.2994, 120.1612
- 将输出结果改为中文
只需要将Names[“en”]更改为Names[“zh-CN”]即可显示中文。