小课堂 | 根据ip获取城市名
在某些场景下,我们需要根据ip获得对应的城市名称。比如,我们需要统计访问ip在各城市的分布;如物联网环境中,设备接入按城市维度进行统计等。
到目前为止,很多开放接口,如淘宝、新浪、腾讯、百度等开放接口或失效或需要key。很多接口已不再免费调用,本文提供3种方式:
- 使用莫名API
- 使用Ip2Region
- 使用MaxMind提供的GeoIp离线包
1、使用莫名API
莫名API介绍
访问https://api.qzone.work/doc/ipaddress.html了解。其返回结果格式如下:
{
"msg":"success",
"code":10000,
"data":{
"country":"中国",
"province":"广东省",
"city":"深圳市",
"ip":"101.105.35.57",
"ISP":"鹏博士"
},
"time":0.00932,
"info":"欢迎使用莫名博客(Qzone.Work)旗下免费提供的API服务!"
}
代码步骤
1、构建HttpClient对象,调用莫名API的URL地址
String url = "https://api.qzone.work/api/ip.address?ip="+ip;
String cityName = "";
HttpClient client = HttpClientBuilder.create().build();
HttpGet request = new HttpGet(url);
2、解析返回的json字串即可
HttpResponse response = client.execute(request);
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode == HttpStatus.SC_OK) {
String strResult = EntityUtils.toString(response.getEntity());
JSONObject jsonResult = JSON.parseObject(strResult);
System.out.println(JSON.toJSONString(jsonResult, true));
JSONObject dataJson = jsonResult.getJSONObject("data");
cityName = dataJson.getString("city");
}
... ...
2、使用ip2region
ip2region - 准确率99.9%的离线IP地址定位库,0.0x毫秒级查询,ip2region.db数据库只有数MB,提供了java,php,c,python,nodejs,golang,c#等查询绑定和Binary,B树,内存三种查询算法。
每条ip数据段都固定了格式:
_城市Id|国家|区域|省份|城市|ISP_
如;
{
"cityId":995,
"dataPtr":117853,
"region":"中国|华东|上海市|上海市|移动"
}
代码步骤:
1、准备db文件,如在src/main/resource目录下创建data目录,存放ip2region.db文件
2、引入ip2region依赖包
<dependency>
<groupId>org.lionsoul</groupId>
<artifactId>ip2region</artifactId>
<version>1.7.2</version>
</dependency>
3、读取ip2region.db文件,指定查询算法,如btreeSearch,然后获取DataBlock 结果,block的region就包含城市信息。
DbSearcher searcher = null;
try {
String dbPath = Ip2CityUtil.class.getClassLoader().getResource("data/ip2region.db").getPath();
File file = new File(dbPath);
if (file.exists()) {
DbConfig config = new DbConfig();
searcher = new DbSearcher(config, file.getPath());
Method method = searcher.getClass().getMethod("btreeSearch", String.class);
if (!Util.isIpAddress(ip)) {
System.out.println("Error: Invalid ip address");
}
DataBlock dataBlock = (DataBlock) method.invoke(searcher, ip);
System.out.println(JSON.toJSONString(dataBlock, true));
return dataBlock.getRegion();
}
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
3、使用GeoLite2
GeoLite2和ip2region一样,先准备离线数据包、导入依赖包。
代码步骤:
1、准备db文件,如在src/main/resource目录下创建data目录,存放GeoLite2-City.mmdb文件
2、引入geolite2依赖包
<dependency>
<groupId>com.maxmind.geoip2</groupId>
<artifactId>geoip2</artifactId>
<version>2.14.0</version>
</dependency>
3、读取GeoLite2-City.mmdb文件,创建DatabaseReader对象 ,然后通过reader.city方法获取CityResponse结果,其中包含丰富的地理位置信息。
public static String getCityNameByGeoLite2(String ip) {
try {
InputStream database = Ip2CityUtil.class.getClassLoader().getResourceAsStream("data/GeoLite2-City.mmdb");
// 创建 DatabaseReader对象
DatabaseReader reader = new DatabaseReader.Builder(database).build();
InetAddress ipAddress = InetAddress.getByName(ip);
CityResponse response = reader.city(ipAddress);
System.out.println(JSON.toJSONString(response, true));
// System.out.println( response.getCity().getNames().get("zh-CN"));
return response.getCity().getNames().get("zh-CN");
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
4、一个CityResponse的内容示例如下:
{
"city":{
"geoNameId":1796236,
"name":"Shanghai",
"names":{
"de":"Shanghai",
"ru":"Шанхай",
"pt-BR":"Xangai",
"ja":"上海",
"en":"Shanghai",
"fr":"Shanghai",
"zh-CN":"上海",
"es":"Shanghai"
}
},
"continent":{
"code":"AS",
"geoNameId":6255147,
"name":"Asia",
"names":{
"de":"Asien",
"ru":"Азия",
"pt-BR":"Ásia",
"ja":"アジア",
"en":"Asia",
"fr":"Asie",
"zh-CN":"亚洲",
"es":"Asia"
}
},
"country":{
"geoNameId":1814991,
"inEuropeanUnion":false,
"isoCode":"CN",
"name":"China",
"names":{
"de":"China",
"ru":"Китай",
"pt-BR":"China",
"ja":"中国",
"en":"China",
"fr":"Chine",
"zh-CN":"中国",
"es":"China"
}
},
"leastSpecificSubdivision":{
"geoNameId":1796231,
"isoCode":"SH",
"name":"Shanghai",
"names":{
"en":"Shanghai",
"fr":"Municipalité de Shanghai",
"zh-CN":"上海",
"pt-BR":"Xangai"
}
},
"location":{
"accuracyRadius":20,
"latitude":31.0449,
"longitude":121.4012,
"timeZone":"Asia/Shanghai"
},
"maxMind":{
},
"mostSpecificSubdivision":{"$ref":"$.leastSpecificSubdivision"},
"postal":{
},
"registeredCountry":{
"geoNameId":1814991,
"inEuropeanUnion":false,
"isoCode":"CN",
"name":"China",
"names":{
"de":"China",
"ru":"Китай",
"pt-BR":"China",
"ja":"中国",
"en":"China",
"fr":"Chine",
"zh-CN":"中国",
"es":"China"
}
},
"representedCountry":{
"inEuropeanUnion":false,
"names":{}
},
"subdivisions":[
{"$ref":"$.leastSpecificSubdivision"}
],
"traits":{
"anonymous":false,
"anonymousProxy":false,
"anonymousVpn":false,
"hostingProvider":false,
"ipAddress":"183.194.238.19",
"legitimateProxy":false,
"network":{
"networkAddress":"183.194.128.0",
"prefixLength":17
},
"publicProxy":false,
"satelliteProvider":false,
"torExitNode":false
}
}
可以通过response.getCity().getNames().get("zh-CN")获取城市信息,如上述示例获取的是上海。
4、相关库下载
资源下载
https://pan.baidu.com/s/4pRI9z2F
GeoLite2的信息很全面,但相对而言其准确率并不是很精确。ip2region相对较准确点。
相关文章
- 美推进脑机接口技术研发
- ES常用知识点整理第一部分
- 北师大吕海东教授课题组发现V2参与运动轮廓的感知
- Groovy实现热部署
- 收藏!“十四五”中国脑科学领域发展前瞻“一体两翼”+五项研究重点
- 同一肢体不同关节的运动想象过程中的多通道脑电图记录
- HTML技术入门
- 测试发文1
- 基于AI的便携式神经假肢让截肢14年患者操作自如,高精度、低延迟
- Nature子刊:复旦类脑院揭示大脑对语义和情景记忆的区分与处理机制
- 首个获得FDA批准的脑机接口设备:“突破性”脑机接口设备用于造福人类
- 北师大卢春明课题组发表论文揭示了亲子互动通过亲子大脑同步影响儿童认知能力的机制
- 情绪脑机接口:脑机接口概述专题三 | 从运动脑机接口到情绪脑机接口
- 干货|详解EEG脑电原理及两种主流脑电设备对比
- NeuroImage:利用高时间分辨率fMRI和动态因果模型探究人脑对痛觉和触觉信息处理的层级结构
- 北师大郭桃梅课题组在《Brain Structure and Function》发表论文揭示汉字笔顺加工的脑网络
- 分布式事务常见解决方案
- 对人脑如何控制手的新认识:我们为什么削水果时,拿的是刀柄而不会拿刀刃?
- MainUI of Darwin
- 科学家利用脑机接口让患者正常发声