背景:
收件地址管理,需要省市区三级基础数据,本来想着有哪家比较大一点的公司提供API可以调用获取,大公司提供的话稳定性有一定保障,但是未能找到。但是看到了民政部官网是有最新最完整的官方数据的,可以将它拉取下来作为我们的省市区基础数据。民政部官网地址:民政部官网地址
在行政区划代码这块,最新的是2020年的。打开“2020年中华人民共和国县以上行政区划代码”后可以看到我们想要的省市区基础数据,网页数据怎么给它拉下来是个问题,会pathy的话获取应该不成问题,可咱不会,只会java,所以找到了Jsoup来爬取网页的内容。
实现:
pom.xml引入jsoup包
<!-- html解析器-->
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.11.3</version>
</dependency>
面对百度编程,参考然后魔改成自己的原创代码:
F12查看网页省市区的数据,可以看到省市的code和name对应的class属性为“xl7228320”,区的code和name对应属性为“xl7328320”,json处理使用的是goole的gson
Elements elements = doc.getElementsByClass(“xl7228320”);
Elements areaElements=doc.getElementsByClass(“xl7328320”);
代码
public class AddressUtil {
public static void main(String[] args) {
try {
//2020年中华人民共和国县以上行政区划代码网页
Document doc = Jsoup.connect("http://www.mca.gov.cn/article/sj/xzqh/2020/20201201.html").maxBodySize(0).get();
Elements elements = doc.getElementsByClass("xl7228320");
Elements areaElements=doc.getElementsByClass("xl7328320");
List<String> stringList = elements.eachText();
List<String> areaStringList=areaElements.eachText();
List<String> stringName = new ArrayList<String>();
List<String> stringCode = new ArrayList<String>();
List<String> StringAreaName=new ArrayList<>();
List<String> StringAreaCode=new ArrayList<>();
for (int i = 0; i < stringList.size(); i++) {
if (i % 2 == 0) {
//地区代码
stringCode.add(stringList.get(i));
} else {
//地区名字
stringName.add(stringList.get(i));
}
}
for(int i=0;i<areaStringList.size();i++){
if (i % 2 == 0) {
//区代码
StringAreaCode.add(areaStringList.get(i));
} else {
//区名字
StringAreaName.add(areaStringList.get(i));
}
}
//正常情况 两个 list size 应该 一样
System.out.println("stringName size= " + stringName.size() + " stringCode size= " + stringCode.size());
if (stringName.size() != stringCode.size()) {
throw new RuntimeException("数据错误");
}
List<Province> provinceList = processData(stringName, stringCode ,StringAreaName,StringAreaCode);
String s= JSONObject.toJSONString(provinceList);
System.out.println(s);
String path = getProjectDir() + "/2020年中华人民共和国县以上行政区划代码" + ".json";
jsonWriter(provinceList, path);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 生成省份列表数据
*
* @param stringName
* @param stringCode
* @return
*/
private static List<Province> processData(List<String> stringName, List<String> stringCode,List<String> stringAreaName,List<String> stringAreaCode) {
List<Province> provinceList = new ArrayList<Province>();
for (int i = 0; i < stringCode.size(); i++) {
String provinceName = stringName.get(i);
String provinceCode = stringCode.get(i);
if (provinceCode.endsWith("0000")) {
Province province = new Province();
provinceList.add(province);
province.setCode(provinceCode);
province.setName(provinceName);
List<City> cities = new ArrayList<City>();
province.setCityList(cities);
//香港,澳门,台湾,没有市级行政单位划分,城市 地区 和省份保持一致
if (provinceName.contains("香港") || provinceName.contains("澳门") || provinceName.contains("台湾")) {
City city = new City();
List<Area> areas = new ArrayList<Area>();
city.setName(provinceName);
city.setCode(provinceCode);
city.setAreaList(areas);
cities.add(city);
Area area = new Area();
area.setName(provinceName);
area.setCode(provinceCode);
areas.add(area);
}
//直辖市 城市和省份名称一样
if (provinceName.contains("北京") || provinceName.contains("上海") || provinceName.contains("天津") || provinceName.contains("重庆")) {
City city = new City();
List<Area> areas = new ArrayList<Area>();
city.setName(provinceName);
city.setCode(provinceCode);
city.setAreaList(areas);
cities.add(city);
//县区
for (int k = 0; k < stringAreaCode.size(); k++) {
String areaName = stringAreaName.get(k);
String areaCode = stringAreaCode.get(k);
if (!provinceCode.equals(areaCode) && areaCode.startsWith(provinceCode.substring(0, 2))) {
Area area = new Area();
area.setName(areaName);
area.setCode(areaCode);
areas.add(area);
}
}
}
for (int j = 0; j < stringCode.size(); j++) {
String cityName = stringName.get(j);
String cityCode = stringCode.get(j);
//遍历获取地级市
if (!cityCode.equals(provinceCode) && cityCode.startsWith(provinceCode.substring(0, 2)) && cityCode.endsWith("00")) {
City city = new City();
List<Area> areas = new ArrayList<Area>();
city.setName(cityName);
city.setCode(cityCode);
city.setAreaList(areas);
cities.add(city);
//遍历获取县区
for (int k = 0; k < stringAreaCode.size(); k++) {
String areaName = stringAreaName.get(k);
String areaCode = stringAreaCode.get(k);
if (!areaCode.equals(cityCode) && areaCode.startsWith(cityCode.substring(0, 4))) {
Area area = new Area();
area.setName(areaName);
area.setCode(areaCode);
areas.add(area);
}
}
}
}
}
}
return provinceList;
}
public static <T> void jsonWriter(T data, String filePath) {
Gson gson = new GsonBuilder().setPrettyPrinting().create();
try(FileWriter writer = new FileWriter(filePath)) {
gson.toJson(data, writer);
} catch (IOException e) {
e.printStackTrace();
}
}
public static <T> void jsonWriter(List<T> data, String filePath) {
Gson gson = new GsonBuilder().setPrettyPrinting().create();
try(FileWriter writer = new FileWriter(filePath)) {
gson.toJson(data, writer);
} catch (IOException e) {
e.printStackTrace();
}
}
public static String getProjectDir() throws UnsupportedEncodingException {
String path=ClassUtils.getDefaultClassLoader().getResource("static").getPath();
path = java.net.URLDecoder.decode(path, "utf-8");
File directory = new File(path);// 参数为空
String courseFile = null;
try {
courseFile = directory.getCanonicalPath();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println(courseFile);
return courseFile;
}
}
在此时纠结过,这个数据是落到数据库里,还是放在json文件里。落到数据库爬取的时候得批量插入,还得建立三个表分别存储省、市、区,再关联查询出数据。落到工程json文件里,直接读取json文本返回给前端,个人感觉方便很多,若民政部有更新,重新跑下程序重新生成json文件就可以了。
代码属于工程的一部分,引用这块可能不全,若有需要可以留言联系。