星空漫步 发表于 2020-7-29 09:24

爬取行政区划

本帖最后由 LIN168168 于 2020-7-29 09:25 编辑

公司开发一个项目,需要行政区划编码,所以自己写了一份代码去民政部爬取,至于为什么不用python,当然是因为我不会了。。。


根据民政部行政区划,初始化省市区编码
url 改为最新的行政区划网址就可以 运行RegionCode 的main方法

编码规则
    省 2位
    市 4位
    区 6位
   
    二级编码缺少
    1.直辖市               增加与省同名的市
    2.省直辖县级行政区划   增加名字为省直辖县级行政区划的市
   
    三级编码缺少
    增加与市同名的区
   
    港澳台
    增加港澳台同名的市和区




/**
* 使用 Jsoup 采集民政部行政区划编码
*
* @AuThor : xxx
* @date : 2020/7/2
*/
public class RegionCode {

    public static void main(String[] args) throws IOException {

      // 民政部行政区划编码地址
      String url = "http://www.mca.gov.cn/article/sj/xzqh/2020/2020/202003301019.html";
      Document doc = Jsoup.connect(url).maxBodySize(0).timeout(100000).get();
      Elements trs = doc.select("tr");
      List<Code> codes = new ArrayList<>();

      for (Element tr : trs) {

            Elements tds = tr.select("td");
            if (tds.size() > 3) {
                String regionCode = tds.get(1).text();
                String regionArea = tds.get(2).text();
                String parentCode = "";

                if (validCode(regionCode)) {
                  int level;
                  if (!regionCode.endsWith("00")) {
                        level = 3;
                        parentCode = regionCode.substring(0, 4);
                  } else if (regionCode.endsWith("0000")) {
                        level = 1;
                        parentCode = "0";
                        regionCode = regionCode.substring(0, 2);
                  } else {
                        level = 2;
                        parentCode = regionCode.substring(0, 2);
                        regionCode = regionCode.substring(0, 4);
                  }
                  codes.add(new Code(regionCode, regionArea, parentCode, level));
                }
            }
      }

      make(codes);
      System.out.println("总数量为:" + codes.size());

      codes.sort(Comparator.comparing(Code::getRegionCode));
      codes.forEach(code -> {
            //自己拼接sql语句
            String content =
                "insert into xxx";
            System.out.println(content);
      });
    }

    /**
   * 判断是否是行政编码
   *
   * @Param code
   * @return
   */
    public static boolean validCode(String code) {
      try {
            Integer.parseInt(code);
            return true;
      } catch (Exception e) {
            return false;
      }
    }

    /**
   * 数据清洗
   *
   * @param codes
   * @return
   */
    public static List<Code> make(List<Code> codes) {

      List<Code> level2Codes = new ArrayList<>();
      List<Code> level3Codes = new ArrayList<>();
      Set<String> defect = new HashSet<>();

      for (Code code : codes) {

            String parentCode = code.getParentCode();
            String regionCode = code.getRegionCode();
            Integer level = code.getLevel();
            boolean level2exits = false;
            boolean level3exits = false;

            for (Code code2 : codes) {
                if (parentCode.equals(code2.getRegionCode())) {
                  level2exits = true;
                }
                if (regionCode.equals(code2.getParentCode())) {
                  level3exits = true;
                }
            }

            // 二级行政编码缺少
            if (!level2exits && level != 1) {
                defect.add(parentCode);
            }

            // 三级行政编码缺少,自动补齐同名市级为第三级
            if (!level3exits && level == 2) {
                level3Codes.add(new Code(regionCode + "00", code.getRegionArea(), regionCode, 3));
            }
      }

      for (String s : defect) {

            // 后缀为1 为直辖市
            if (s.endsWith("1")) {
                for (Code code : codes) {
                  if (s.substring(0, 2).equals(code.getRegionCode())) {
                        level2Codes.add(new Code(s, code.getRegionArea(), s.substring(0, 2), 2));
                        break;
                  }
                }
            } else {
                level2Codes.add(new Code(s, "省直辖县级行政区划", s.substring(0, 2), 2));
            }
      }
      codes.addAll(level2Codes);
      codes.addAll(level3Codes);

      // 港澳台增加编码 三级下拉框对齐
      codes.add(new Code("7100", "台湾省", "71", 2));
      codes.add(new Code("710000", "台湾省", "7100", 3));
      codes.add(new Code("8100", "香港特别行政区", "81", 2));
      codes.add(new Code("810000", "香港特别行政区", "8100", 3));
      codes.add(new Code("8200", "澳门特别行政区", "82", 2));
      codes.add(new Code("820000", "澳门特别行政区", "8200", 3));
      return codes;
    }
}


public class Code {
    private String regionCode;
    private String regionArea;
    private String parentCode;
    private Integer level;
}

注释写的我还是挺全的,直接运行main方法就可以了,下次自己用python在写一次:lol

家有葫芦仔 发表于 2020-7-29 10:17

大佬没看懂你的java,但我用python写出来是这样的,二级缺少自动补齐是啥意思呢?
import requests
from lxml import etree
import csv
url = 'http://www.mca.gov.cn/article/sj/xzqh/2020/2020/202003301019.html'
r = requests.get(url).text
html = etree.HTML(r)
c = html.xpath('//*[@id="2020年1月份县以上行政区划代码_30721"]/table/tr/td//text()')
m = html.xpath('//*[@id="2020年1月份县以上行政区划代码_30721"]/table/tr/td/text()')
b = zip(c,m)
for bb in b:
    with open('邮政编码.csv', 'a+', newline='')as f:
      writer = csv.writer(f)
      writer.writerows()

星空漫步 发表于 2020-7-29 10:20

120254184 发表于 2020-7-29 10:17
大佬没看懂你的java,但我用python写出来是这样的,二级缺少自动补齐是啥意思呢?


直辖市和省直辖县级行政区划是没有第二级的编码的,为了页面上三级级联对应,所以加了一个

星空漫步 发表于 2020-7-29 09:30

打开页面的F12,就会发现我上面的jsoup为什么先取<tr>标签,再循环取<td>了

家有葫芦仔 发表于 2020-7-29 09:38

学习学习,我也想学Java,但看着好难

挑灯看花 发表于 2020-7-29 10:14

挺有意思的,思路也有了,不过数据储存我不知道怎么办

星空漫步 发表于 2020-7-29 10:18

挑灯看花 发表于 2020-7-29 10:14
挺有意思的,思路也有了,不过数据储存我不知道怎么办

我是拼接成sql了 直接执行,存到mysql就好了

kuang42694 发表于 2020-7-29 10:24

不明觉厉很厉害的样子

家有葫芦仔 发表于 2020-7-29 10:26

LIN168168 发表于 2020-7-29 10:20
直辖市和省直辖县级行政区划是没有第二级的编码的,为了页面上三级级联对应,所以加了一个

好吧,没看懂,我再研究研究

冰镇苏打水 发表于 2020-7-29 10:28

这里有两种形式的 json

一个是嵌套的多维数组.一个是一维数组.

一直在用的 json.
页: [1] 2
查看完整版本: 爬取行政区划