淘宝IP地址库 ip淘宝ip地址库
程序员文章站
2024-02-22 08:50:22
...
网上流传最广的免费IP库,是纯真的IP库:http://www.cz88.net/,且该库一直有维护,但缺点是不太准确。
淘宝的IP地址库比较准确,且提供了IP查询的接口:http://ip.taobao.com/。但它没有提供全量下载,且一秒内调用不能超过10次。
于是萌生了一个想法:
以纯真IP库作为IP分段的依据,以此去调用淘宝的接口,从而获得比较准确的IP库。
以纯真IP库的几行记录为例:
a.235995136*14.17.0.0*235997951*14.17.10.255*广东省*深圳市*广东省深圳市*电信
b.3546091247*211.93.14.239*3546091519*211.93.15.255*青海省*西宁市*青海省西宁市*联通
处理方式如下:
1.对于记录a,14.17.0.0和14.17.10.255,分两次调用淘宝的接口,获得结果均为:
14.17.0.0-14.17.10.255 广东省广州市
这种情况最为简单,直接用淘宝的结果替换纯真的结果即可。
2.对于记录b,211.93.14.239和211.93.15.255,分两次调用淘宝的接口,获得结果为:
211.93.14.239 青海省海南藏族自治州
211.93.15.255 青海省西宁市
出现了前后不一致的情况。
这时候怎么办呢?
把211.93.14.239-211.93.15.255这个IP段进行粗略的分段,按IP的前三段相同的,分为一个小段:
211.93.14.239-211.93.14.255 青海省海南藏族自治州
211.93.15.0-211.93.15.255 青海省西宁市
在每一个小段里,前后一致,纯真的一个IP段变成了两个IP段。
但这样做是基于一个前提:那就是认为211.93.15.0-211.93.15.255这样的(x.y.z.0-x.y.z.255,前三部分相同)所有IP是落在同一个城市。
这个前提不一定成立的。因此以此得到的数据,只是相对准确。
那对于x.y.z.0和x.y.z.255,如果落在不同城市呢?
这时候没有更好的办法了,只能遍历x.y.z.0-x.y.z.255之间的所有IP,得到结果后再把城市相同的进行合并。
在我的测试过程中,有455个这样的IP段是前后不一致的。
这样的处理很繁琐,我花费了几天才处理完毕,现在把结果分享出来,供有需要的人下载:http://pan.baidu.com/s/1eQg3pvW, 提取密码为nhhd。此外,为方便使用,我还在IP表中记录了IP对应的城市的经纬度:
要声明的是,本人不对数据的正确性作任何保证。
同时,提供几个用到的函数(代码待优化),供参考:
淘宝的IP地址库比较准确,且提供了IP查询的接口:http://ip.taobao.com/。但它没有提供全量下载,且一秒内调用不能超过10次。
于是萌生了一个想法:
以纯真IP库作为IP分段的依据,以此去调用淘宝的接口,从而获得比较准确的IP库。
以纯真IP库的几行记录为例:
a.235995136*14.17.0.0*235997951*14.17.10.255*广东省*深圳市*广东省深圳市*电信
b.3546091247*211.93.14.239*3546091519*211.93.15.255*青海省*西宁市*青海省西宁市*联通
处理方式如下:
1.对于记录a,14.17.0.0和14.17.10.255,分两次调用淘宝的接口,获得结果均为:
14.17.0.0-14.17.10.255 广东省广州市
这种情况最为简单,直接用淘宝的结果替换纯真的结果即可。
2.对于记录b,211.93.14.239和211.93.15.255,分两次调用淘宝的接口,获得结果为:
211.93.14.239 青海省海南藏族自治州
211.93.15.255 青海省西宁市
出现了前后不一致的情况。
这时候怎么办呢?
把211.93.14.239-211.93.15.255这个IP段进行粗略的分段,按IP的前三段相同的,分为一个小段:
211.93.14.239-211.93.14.255 青海省海南藏族自治州
211.93.15.0-211.93.15.255 青海省西宁市
在每一个小段里,前后一致,纯真的一个IP段变成了两个IP段。
但这样做是基于一个前提:那就是认为211.93.15.0-211.93.15.255这样的(x.y.z.0-x.y.z.255,前三部分相同)所有IP是落在同一个城市。
这个前提不一定成立的。因此以此得到的数据,只是相对准确。
那对于x.y.z.0和x.y.z.255,如果落在不同城市呢?
这时候没有更好的办法了,只能遍历x.y.z.0-x.y.z.255之间的所有IP,得到结果后再把城市相同的进行合并。
在我的测试过程中,有455个这样的IP段是前后不一致的。
这样的处理很繁琐,我花费了几天才处理完毕,现在把结果分享出来,供有需要的人下载:http://pan.baidu.com/s/1eQg3pvW, 提取密码为nhhd。此外,为方便使用,我还在IP表中记录了IP对应的城市的经纬度:
要声明的是,本人不对数据的正确性作任何保证。
同时,提供几个用到的函数(代码待优化),供参考:
public class IpUtil { private static final int MAX = 255; /** * 把IpRange拆成更小的IpRange,使得每个小的IpRange的前三个网段是相同的 * 例如把1.1.1.20-1.1.3.30拆成: * 1.1.1.20-1.1.1.255 * 1.1.2.0-1.1.2.255 * 1.1.3.0-1.1.3.30 * @param range * @return */ public static List<IpRange> split(IpRange range) { List<IpRange> list = new ArrayList<IpRange>(); long p0, p1, p2; long min = toLongWithFirstThreeParts(range.getStart()); long max = toLongWithFirstThreeParts(range.getEnd()); for (p0 = range.getStart().getP0(); p0 <= range.getEnd().getP0(); p0++) { for (p1 = 0; p1 <= MAX; p1++) { for (p2 = 0; p2 <= MAX; p2++) { if (firstThreePartsToLong(p0, p1, p2)< min) { continue; } if (firstThreePartsToLong(p0, p1, p2) > max) { break; } IpBean newStart = new IpBean(p0, p1, p2, 0); if (newStart.toLong() < range.getStart().toLong()) { newStart = range.getStart(); } IpBean newEnd = new IpBean(p0, p1, p2, 255); if (newEnd.toLong() > range.getEnd().toLong()) { newEnd = range.getEnd(); } IpRange ipRange = new IpRange(newStart, newEnd); list.add(ipRange); } } } return list; } /** * 只计算前三段 * @return */ public static long toLongWithFirstThreeParts(IpBean bean) { long p0 = bean.getP0(); long p1 = bean.getP1(); long p2 = bean.getP2(); return firstThreePartsToLong(p0, p1, p2); } public static long firstThreePartsToLong(long p0, long p1, long p2) { return (p0 << 24) + (p1 << 16) + (p2 << 8); } /** * 取得startIp-endIp这个IP段内所有的单个IP * @param startIp * @param endIp * @return */ public static List<IpBean> findIpList(String startIp, String endIp) { List<IpBean> list = new ArrayList<IpBean>(); IpBean startBean = toBean(startIp); IpBean endBean = toBean(endIp); long start = startBean.toLong(); long end = endBean.toLong(); long p0, p1, p2, p3; for (p0 = startBean.getP0(); p0 <= endBean.getP0(); p0++ ) { for (p1 = 0; p1 <= MAX; p1++) { for (p2 = 0; p2 <= MAX; p2++) { for (p3 = 0; p3 <= MAX; p3++) { IpBean newIp = new IpBean(); newIp.setP0(p0); newIp.setP1(p1); newIp.setP2(p2); newIp.setP3(p3); long newLongVal = newIp.toLong(); if (start <= newLongVal && newLongVal <= end) { list.add(newIp); } } } } } return list; } public static IpBean toBean(String ipStr) { long[] ip = new long[4]; // 先找到IP地址字符串中.的位置 int position1 = ipStr.indexOf("."); int position2 = ipStr.indexOf(".", position1 + 1); int position3 = ipStr.indexOf(".", position2 + 1); // 将每个.之间的字符串转换成整型 ip[0] = Long.parseLong(ipStr.substring(0, position1)); ip[1] = Long.parseLong(ipStr.substring(position1 + 1, position2)); ip[2] = Long.parseLong(ipStr.substring(position2 + 1, position3)); ip[3] = Long.parseLong(ipStr.substring(position3 + 1)); IpBean bean = new IpBean(); bean.setP0(ip[0]); bean.setP1(ip[1]); bean.setP2(ip[2]); bean.setP3(ip[3]); return bean; } }
/** * 合并连续的、在同一城市的IP */ public void merge() { IpExample example = new IpExample(); example.createCriteria().andStateEqualTo(IpConst.State.OK); example.setOrderByClause("ipstartdigital asc"); List<Ip> list = mapper.selectByExample2(example); logger.info("size={}", list.size()); Ip startIp = null; Ip endIp = null; int count = 0; for (Ip ip : list) { if (startIp == null) { startIp = ip; endIp = ip; } else { if (isMatched(endIp, ip) && isContinuous(endIp, ip) ) { endIp = ip; continue; } else { count++; insert(startIp, endIp); startIp = ip; endIp = ip; } } } if (startIp != null && endIp != null) { count++; insert(startIp, endIp); } logger.info("count={}", count); } private boolean isContinuous(Ip endIp, Ip ip) { return endIp.getIpenddigital().equals(ip.getIpstartdigital() - 1); } private void insert(Ip startIp, Ip endIp) { Ip ip = new Ip(); Helper.copyFromNotNull(ip, startIp); ip.setIpend(endIp.getIpend()); ip.setIpenddigital(endIp.getIpenddigital()); ip.setId(null); logger.info("last ipstart={}, ipstartdigital={}, ipend={}, ipenddigital={}, province={}, city={}", ip.getIpstart(), ip.getIpstartdigital(), ip.getIpend(), ip.getIpenddigital(), ip.getProvince(), ip.getCity()); mapper.insert(ip); } private boolean isMatched(Ip x, Ip y) { boolean result = false; //国家+省+市是否相等 if (x != null && y != null) { result = StringUtils.equals(x.getCountry(), y.getCountry()) && StringUtils.equals(x.getProvince(), y.getProvince()) && StringUtils.equals(x.getCity(), y.getCity()); } return result; }