2019独角兽企业重金招聘Python工程师标准>>>
在某些场景下,可能需要用到根据ip地址获取ip所对应的城市名。
貌似腾讯、百度等开放接口已经失效或者免费服务接口关闭等原因,很多免费接口已不能使用,本文暂时给出如下三种方法来做:
- 使用淘宝的开放接口
- 使用新浪的开放接口
- 使用MaxMind提供的GeoIp离线包
接下来,我们就一起来看看这三种方法的具体使用方法,所有的示例采用Java代码完成。
淘宝和新浪开放的api都返回JSON格式的数据。
完成淘宝和新浪api接口调用,本文使用如下的依赖包:
4.5.2
1.2.23
org.apache.httpcomponents
httpclient
${http-client.version}
com.alibaba
fastjson
${fast-json.version}
使用淘宝的开放接口
接口地址
淘宝的开放接口URL格式为:
http://ip.taobao.com/service/getIpInfo.php?ip=
示例:
http://ip.taobao.com/service/getIpInfo.php?ip=117.136.42.86
返回结果
{
"data":{
"region":"北京市",
"area_id":"100000",
"country_id":"CN",
"isp":"移动",
"region_id":"110000",
"ip":"117.136.42.86",
"country":"中国",
"city":"北京市",
"isp_id":"100025",
"city_id":"110100",
"area":"华北",
"county":"",
"county_id":"-1"
},
"code":0
}
代码示例
public String getCityNameByTaoBaoAPI(String ip) {
String url = "http://ip.taobao.com/service/getIpInfo.php?ip=" + ip;
String cityName = "";
HttpClient client = HttpClientBuilder.create().build();
HttpGet request = new HttpGet(url);
try {
HttpResponse response = client.execute(request);
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode == HttpStatus.SC_OK) {
String strResult = EntityUtils.toString(response.getEntity());
try {
JSONObject jsonResult = JSON.parseObject(strResult);
System.out.println(JSON.toJSONString(jsonResult, true));
JSONObject dataJson = jsonResult.getJSONObject("data");
cityName = dataJson.getString("city");
System.out.println(JSON.toJSONString(jsonResult, true));
} catch (Exception e) {
e.printStackTrace();
}
}
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return cityName;
}
使用新浪的开放
接口地址
新浪的开放接口URL格式为:
http://int.dpool.sina.com.cn/iplookup/iplookup.php?format=json&ip=
示例:
http://int.dpool.sina.com.cn/iplookup/iplookup.php?format=json&ip=117.136.42.60
返回结果
{
"ret":1,
"desc":"",
"start":-1,
"isp":"",
"province":"北京",
"type":"",
"district":"",
"end":-1,
"city":"北京",
"country":"中国"
}
代码示例
public static String getCityNameBySinaAPI(String ip) {
String url = "http://int.dpool.sina.com.cn/iplookup/iplookup.php?format=json&ip="
+ ip;
String cityName = "";
HttpClient client = HttpClientBuilder.create().build();
HttpGet request = new HttpGet(url);
try {
HttpResponse response = client.execute(request);
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode == HttpStatus.SC_OK) {
String strResult = EntityUtils.toString(response.getEntity());
try {
JSONObject jsonResult = JSON.parseObject(strResult);
cityName = jsonResult.getString("city");
System.out.println(JSON.toJSONString(jsonResult, true));
} catch (Exception e) {
e.printStackTrace();
}
}
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return cityName;
}
使用GeoLiteCity离线包
下载离线包
下载GeoLiteCity离线包,并解压到本地。
下载地址http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz
解压缩之后,可以看到解压后的GeoLiteCity.dat文件。
准备依赖包
1.2.15
com.maxmind.geoip
geoip-api
${geoip-api.version}
代码示例
import java.io.IOException;
import java.net.InetAddress;
import com.maxmind.geoip.Location;
import com.maxmind.geoip.LookupService;
public class GeoLiteCityExample {
public static final String GEO_LITE_FILE_LOCATION = "D:\\ips\\GeoLiteCity.dat";
public String getCityName(String ip) {
try {
LookupService lookupService = new LookupService(
GEO_LITE_FILE_LOCATION, LookupService.GEOIP_MEMORY_CACHE);
Location location = lookupService.getLocation(ip);
if (location != null) {
return location.city;
}
} catch (IOException e) {
e.printStackTrace();
}
return "";
}
public String getCityName(InetAddress inetAddress) {
try {
LookupService lookupService = new LookupService(
GEO_LITE_FILE_LOCATION, LookupService.GEOIP_MEMORY_CACHE);
Location location = lookupService.getLocation(inetAddress);
if (location != null) {
return location.city;
}
} catch (IOException e) {
e.printStackTrace();
}
return "";
}
}
测试代码如下:
import java.net.InetAddress;
import java.net.UnknownHostException;
public class Main {
public static void main(String[] args) {
GeoLiteCityExample example = new GeoLiteCityExample();
String ip = "223.95.66.34";
String cityName = example.getCityName(ip);
// Hangzhou
System.out.println(cityName);
try {
InetAddress inetAddress = InetAddress.getByName(ip);
cityName = example.getCityName(inetAddress);
// Hangzhou
System.out.println(cityName);
} catch (UnknownHostException e) {
e.printStackTrace();
}
}
}
Location类说明
当拿到com.maxmind.geoip.Location类后,上述示例只是拿了一个属性city来获取城市的名称,其实还能获取更多的属性,如国家,经纬度等。
package com.maxmind.geoip;
public class Location {
public String countryCode;
public String countryName;
public String region;
public String city;
public String postalCode;
public float latitude;
public float longitude;
public int dma_code;
public int area_code;
public int metro_code;
//省略其它
}
有兴趣的读者,可以尝试一下~~。
至此,使用Maxmind提供的GeoLiteCity离线包,通过ip获取对应城市名的示例也完成了。
小结
本篇博文给出了三个方法用于获取IP对应的城市名称:使用淘宝开放API、使用新浪开放API和使用MaxMind提供的离线包。
从体验上来看,
新浪接口返回结果还是挺快的。淘宝的接口可能做了连续访问的限制,有时候没有正常返回结果。
使用离线包的方式更加稳定,但是,返回结果是拼音。有些城市拼音一样,如果要进一步确定中文城市名,需要做些额外的操作来保证。
(打算写个多线程程序,将离线包中的中国城市IP信息存放到数据库中去,以后结合缓存加快处理 ~~)
今天就写到这吧
大家如果有其它不错的方式-- 获取IP地址对应的城市名称,也请留言,一起分享,谢谢。