java学习笔记(三)手机号码归属地批量查询的代码,亲测可用
重要的事情说一遍,注意本代码实现的优点是批量查询!!!
当前单个手机号码查询也是没有问题的。
由于公司行业主要是展会行业,展会上的观众注册等,填写基本信息的时候会采集手机号等信息,展会结束后我们需要做数据分析。只有通过手机号查找归属地来获取客户的地域信息。找了好多平台和api,发现没有说是能批量处理手机号信息。最后还是找了githup上找到一个插件,感谢那位大神的贡献。
传送门> https://github.com/xluohome/phonedata
主要涉及到两个类和一个dat文件
PhoneNumberGeo.java 和 PhoneNumberInfo.java 以及一个 phone.dat文件(存放手机归属信息的),dat文件可在传送门里面找到。
PhoneNumberGeo.java 文件内容如下,主要作用是来读取phone.dat文件。
package com.yh.util.phone;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.charset.StandardCharsets;
import java.util.Scanner;
/**
* Created by buring 18/10/12.
*/
public class PhoneNumberGeo {
private static String[] numberType = {null, "移动", "联通", "电信", "电信虚拟运营商", "联通虚拟运营商", "移动虚拟运营商"};
private static final int INDEX_SEGMENT_LENGTH = 9;
private static byte[] dataByteArray;
private ByteBuffer byteBuffer;
private int indexAreaOffset = -1;
private int phoneRecordCount = -1;
public PhoneNumberGeo() {
if (dataByteArray == null) {
synchronized (PhoneNumberGeo.class) {
if (dataByteArray == null) {
ByteArrayOutputStream byteData = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int readBytesLength;
try {
InputStream inputStream = PhoneNumberGeo.class
.getResourceAsStream("phone.dat");
while ((readBytesLength = inputStream.read(buffer)) != -1) {
byteData.write(buffer, 0, readBytesLength);
}
inputStream.close();
} catch (Exception e) {
System.err.println("Can't find phone.dat in classpath:phone-number-geo/phone.dat");
e.printStackTrace();
throw new RuntimeException(e);
}
dataByteArray = byteData.toByteArray();
}
}
}
byteBuffer = ByteBuffer.wrap(dataByteArray);
byteBuffer.order(ByteOrder.LITTLE_ENDIAN);
int dataVersion = byteBuffer.getInt();
indexAreaOffset = byteBuffer.getInt();
// print data version
// System.out.println(dataVersion);
phoneRecordCount = (dataByteArray.length - indexAreaOffset) / INDEX_SEGMENT_LENGTH;
// print record count
// System.out.println(phoneRecordCount);
}
public PhoneNumberInfo lookup(String phoneNumber) {
if (phoneNumber == null || phoneNumber.length() > 11 || phoneNumber.length() < 7) {
return null;
}
int phoneNumberPrefix;
try {
phoneNumberPrefix = Integer.parseInt(phoneNumber.substring(0, 7));
} catch (Exception e) {
return null;
}
int left = 0;
int right = phoneRecordCount;
while (left <= right) {
int middle = (left + right) >> 1;
int currentOffset = indexAreaOffset + middle * INDEX_SEGMENT_LENGTH;
if (currentOffset >= dataByteArray.length) {
return null;
}
byteBuffer.position(currentOffset);
int currentPrefix = byteBuffer.getInt();
if (currentPrefix > phoneNumberPrefix) {
right = middle - 1;
} else if (currentPrefix < phoneNumberPrefix) {
left = middle + 1;
} else {
int infoBeginOffset = byteBuffer.getInt();
int phoneType = byteBuffer.get();
int infoLength = -1;
for (int i = infoBeginOffset; i < indexAreaOffset; ++i) {
if (dataByteArray[i] == 0) {
infoLength = i - infoBeginOffset;
break;
}
}
String infoString =
new String(dataByteArray, infoBeginOffset, infoLength, StandardCharsets.UTF_8);
String[] infoSegments = infoString.split("\\|");
PhoneNumberInfo phoneNumberInfo = new PhoneNumberInfo();
phoneNumberInfo.setPhoneNumber(phoneNumber);
phoneNumberInfo.setProvince(infoSegments[0]);
phoneNumberInfo.setCity(infoSegments[1]);
phoneNumberInfo.setZipCode(infoSegments[2]);
phoneNumberInfo.setAreaCode(infoSegments[3]);
phoneNumberInfo.setPhoneType(numberType[phoneType]);
return phoneNumberInfo;
}
}
return null;
}
public static void main(String[] args) {
PhoneNumberGeo phoneNumberGeo = new PhoneNumberGeo();
Scanner scanner = new Scanner(System.in);
while (scanner.hasNext()) {
System.out.println(phoneNumberGeo.lookup(scanner.next()));
}
}
}
PhoneNumberInfo.java 文件内容如下,主要作用 定义一个model
package com.yh.util.phone;
public class PhoneNumberInfo {
private String phoneNumber;
private String province;
private String city;
private String zipCode;
private String areaCode;
private String phoneType;
public String getPhoneNumber() {
return phoneNumber;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
public String getProvince() {
return province;
}
public void setProvince(String province) {
this.province = province;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getZipCode() {
return zipCode;
}
public void setZipCode(String zipCode) {
this.zipCode = zipCode;
}
public String getAreaCode() {
return areaCode;
}
public void setAreaCode(String areaCode) {
this.areaCode = areaCode;
}
public String getPhoneType() {
return phoneType;
}
public void setPhoneType(String phoneType) {
this.phoneType = phoneType;
}
@Override public String toString() {
return "PhoneNumberInfo{" +
"phoneNumber='" + phoneNumber + '\'' +
", province='" + province + '\'' +
", city='" + city + '\'' +
", zipCode='" + zipCode + '\'' +
", areaCode='" + areaCode + '\'' +
", phoneType='" + phoneType + '\'' +
'}';
}
}
文件存放路径建议
调用的代码如下,这段代码可以放在for循环里面去执行,效率肯定比单个去请求开放的API效率高很多,已经测试过好几批手机号数据(均为7000+条以上),查询不到的也就剩下几十条,这个可以单独去请求开放API获得手机号码归属地,我这里没有,可以自行搜索相关实现方法。
String phoneNum = '13609257706'
PhoneNumberGeo phoneNumberGeo = new PhoneNumberGeo();
PhoneNumberInfo phoneNumberInfo = phoneNumberGeo.lookup(val);
if(null!=phoneNumberInfo){
//获取省份
String province = phoneNumberInfo.getProvince();
//获取城市 需要其他的参数自行查找PhoneNumberInfo类获取
String city = phoneNumberInfo.getCity();
System.out.println(province+"\t"+city);
}else{
System.out.println("请单独去查询");
}
有问题请随时@我,邮箱[email protected]