最近发现项目中使用的省市区数据库很旧了,很多新增区的数据没有。网上找了很多,都不是最新了。

找到一篇博客,他是自己去国家统计局上取的,

https://blog.csdn.net/z_wen_quan/article/details/79737567

不过他使用的php,我没有php环境,而且数据库的格式不一样,所以自己重新写了一个工具类。

思路是:

  1. 通过统计局网站上找到的各个省市区的ID可以 拼接出相关界面的URL
  2. 通过网络请求可以通过URL获取到当前界面的源码
  3. 通过正则表达式 截取需要的数据,包括 名称、统计用区划代码、跳转下级界面ID
  4. 将获取到的数据拼接成SQL语句,或者拼接为JSON字符串输出

工具类ChinaCityNameUtils有四个方法:

  • printProvinceSQL()   printCitySQL ()    printAreaSQL()   分别在控制台打印 表 province   city  area  的 插入SQL 语句
  • getCitiesJson 在控制台打印 json字符串,并保持到D盘

注意,sql语句是根据我用的数据库的格式拼接的,如果使用的数据库格式和我使用的不通,可以自行修改对应的SQL语句

/*** Copyright (C), 2018-2019, wankun*/
package com.wankun.richduckling.utils;import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.thymeleaf.util.StringUtils;import java.io.ByteArrayOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;/*** 获取中国城市相关数据** @author wankun* @create 2019/4/10* @since 1.0.0*/
public class ChinaCityNameUtils {/*** 当前取得是国家统计局2018年的数据*/private static final String WEB_URL = "http://www.stats.gov.cn/tjsj/tjbz/tjyqhdmhcxhfdm/2018/index.html";private static final String BASE_URL = "http://www.stats.gov.cn/tjsj/tjbz/tjyqhdmhcxhfdm/2018/";/*** 省份的对应的id* 测试时只取前两个或者前三个,加快测试速度*/private static final int[] province_id = {11, 12, 13, 14, 15, 21, 22, 23, 31, 32, 33, 34, 35, 36, 37, 41, 42, 43, 44, 45, 46, 50, 51, 52,53, 54, 61, 62, 63, 64, 65};private static final String[] province_name = {"北京市", "天津市", "河北省", "山西省", "内蒙古自治区", "辽宁省", "吉林省", "黑龙江省","上海市", "江苏省", "浙江省", "安徽省", "福建省", "江西省", "山东省", "河南省","湖北省", "湖南省", "广东省", "广西壮族自治区", "海南省", "重庆市", "四川省", "贵州省","云南省", "西藏自治区", "陕西省", "甘肃省", "青海省", "宁夏回族自治区", "新疆维吾尔自治区"};private static final String RGEX_IDS = "<a href=\\'\\d{2}\\/(.{1,30}).html\\'>(.{1,30})<\\/a><\\/td><\\/tr>";private static final String RGEX_NAMES = "<a href=\\'.*?.html\\'>(.{1,30})<\\/a><\\/td><\\/tr>";private static final String RGEX_CODES = "<td><a href=\\'.*?.html\\'>(.{1,30})<\\/a><\\/td><td>";private static final String RGEX_CODES_NO_A = "<tr class=\\'countytr\\'><td>(.{1,30})<\\/td><td>.*?<\\/td><\\/tr>";private static final String RGEX_NAMES_NO_A = "<tr class=\\'countytr\\'><td>.*?<\\/td><td>(.{1,30})<\\/td><\\/tr>";private static int cityFromIdId = 0;private static int provinceFromId = 0;private static int areaFormId = 0;/*** 表结构参考 如下创建表的sql*/private static String CREAT_PROVINCE_SQL = "CREATE TABLE `province`(`pro_id` int(11),`pro_code` varchar(18),`pro_name` varchar(60),`pro_name2` varchar(60));";private static String CREAT_CITY_SQL = " CREATE TABLE `city`( `id` int(11),   `province_id` int(10),   `code` varchar(18),   `name` varchar(60),   `province_code` varchar(18));";private static String CREAT_AREA_SQL = " CREATE TABLE `area`(`id` int(11),   `city_id` int(10),   `code` varchar(18),   `name` varchar(60),   `city_code` varchar(18));";/*** 获取省市sql*/public static void printProvinceSQL() {System.out.println("size:" + province_id.length);String sql = "";for (int i = 0; i < province_id.length; i++) {int id = i + 1;//注意id补零if (!StringUtils.isEmpty(sql)) {sql = String.format("%s,", sql);}sql = String.format("%s(%s,'%s0000','%s','')",sql, id, province_id[i], province_name[i]);}sql =  String.format("insert into province values %s ;", sql);System.out.println(sql);}/*** 获取 城市表sql* 注意:1、输出的sql 在控制台中获取* 2、清除表数据 delete from  area;*/public static void printCitySQL() {System.out.println("获取城市数据");//城市表中的idcityFromIdId = 0;provinceFromId = 0;for (int i = 0; i < province_id.length; i++) {String url = BASE_URL + province_id[i] + ".html";provinceFromId++;String html = getHtml(url);try {//暂停等待获取网页数据String provinceCode = province_id[i] + "0000";// 匹配的模式String sql = getSqlStr(0, html, RGEX_NAMES, RGEX_CODES, provinceCode);sql = String.format("insert into city values %s ;", sql);System.out.println(sql);} catch (Exception e) {e.printStackTrace();}}System.out.println("城市总数:" + cityFromIdId);}/*** 获取地区的表sql*/public static void printAreaSQL() {System.out.println("获取地区数据");areaFormId = 0;cityFromIdId = 0;for (int i = 0; i < province_id.length; i++) {String url = BASE_URL + province_id[i] + ".html";String html = getHtml(url);//暂停5秒等待获取网页数据try {// 匹配的模式List<String> ids = getSubUtil(html, RGEX_IDS);List<String> codes = getSubUtil(html, RGEX_CODES);for (int n = 0; n < ids.size(); n++) {cityFromIdId++;//获取区级的数据String urlQu = BASE_URL + province_id[i] + "/" + ids.get(n) + ".html";String htmlQu = getHtml(urlQu);//部分省市的区级 不一样,没有跳转事件,所以 正则不一样String sql = getSqlStr(1, htmlQu, RGEX_NAMES_NO_A, RGEX_CODES_NO_A, codes.get(n));sql = String.format(StringUtils.isEmpty(sql) ? "%s %s" : "%s,%s", sql, getSqlStr(1, htmlQu, RGEX_NAMES, RGEX_CODES, codes.get(n)));sql = String.format("insert into area values %s ;", sql);System.out.println(sql);}} catch (Exception e) {e.printStackTrace();}}System.out.println("地区总数:" + areaFormId);}/*** 通过正则获取 html中的相关数据,并拼接Sql语句** @param type 表类型, 0 城市表, 1 地区表* @return*/private static String getSqlStr(int type, String html, String rgexNames, String rgexCodes, String parentsCode) {String sql = "";int formId = 0;int parentsFromIdId = 0;List<String> names = getSubUtil(html, rgexNames);List<String> codes = getSubUtil(html, rgexCodes);for (int q = 0; q < names.size(); q++) {if (type == 0) {cityFromIdId++;parentsFromIdId = provinceFromId;formId = cityFromIdId;} else {areaFormId++;parentsFromIdId = cityFromIdId;formId = areaFormId;}if (!StringUtils.isEmpty(sql)) {sql = String.format("%s,", sql);}//拼接插入数据的SQL语句sql = String.format("%s(%s,%s,%s,'%s',%s)", sql, formId, parentsFromIdId, codes.get(q), names.get(q), parentsCode);}return sql;}/*** 获取 城市json** @return*/public static JSONArray getCitiesJson() {System.out.println("获取citiesJson");JSONArray jsonArray = new JSONArray();//城市id和区id 计算全部的,方便存数据库int cityId = 0;int areaId = 0;int provinceId = 0;//第一级为省市for (int p = 0; p < province_id.length; p++) {try {JSONObject province = new JSONObject();provinceId = p + 1;province.put("pro_id", provinceId);//注意补零province.put("pro_code", province_id[p] + "0000");province.put("pro_name", province_name[p]);//第二级 城市System.out.println("开始获取" + province_name[p] + "的城市数据");JSONArray cities = new JSONArray();String url = BASE_URL + province_id[p] + ".html";String html = getHtml(url);List<String> ids = getSubUtil(html, RGEX_IDS);List<String> names = getSubUtil(html, RGEX_NAMES);List<String> codes = getSubUtil(html, RGEX_CODES);for (int c = 0; c < ids.size(); c++) {int cityID = ++cityId;JSONObject city = new JSONObject();city.put("city_id", cityID);city.put("city_code", codes.get(c));city.put("city_name", names.get(c));//第三级 区级JSONArray areas = new JSONArray();String urlArea = BASE_URL + province_id[p] + "/" + ids.get(c) + ".html";String htmlArea = getHtml(urlArea);List<String> namesQu = new ArrayList<>();List<String> codesQu = new ArrayList<>();//有的市有"直辖区",正则处理方式不一样namesQu.addAll(getSubUtil(htmlArea, RGEX_NAMES_NO_A));codesQu.addAll(getSubUtil(htmlArea, RGEX_CODES_NO_A));namesQu.addAll(getSubUtil(htmlArea, RGEX_NAMES));codesQu.addAll(getSubUtil(htmlArea, RGEX_CODES));for (int a = 0; a < namesQu.size(); a++) {int areaID = ++areaId;JSONObject area = new JSONObject();area.put("area_id", areaID);area.put("area_code", codesQu.get(a));area.put("area_name", namesQu.get(a));areas.add(area);}city.put("city_areas", areas);cities.add(city);}province.put("pro_cities", cities);jsonArray.add(province);} catch (Exception e) {e.printStackTrace();}}//全部数据太长了,控制台打印不全,写入本地文件System.out.println(jsonArray.toString());writeFile(jsonArray.toString());return jsonArray;}/*** 将json字段写入本地D盘** @param str*/public static void writeFile(String str) {FileWriter fw = null;//设置日期格式SimpleDateFormat df = new SimpleDateFormat("yyyyMMddHHmmss");String fileName = "D:\\china_city_name_" + df.format(new Date()) + ".txt";try {//经过测试:FileWriter执行耗时:3,9,5 毫秒fw = new FileWriter(fileName);fw.write(str);} catch (Exception e) {e.printStackTrace();} finally {try {fw.close();} catch (Exception e) {e.printStackTrace();}}}/*** 通过url获取网页的源码** @param htmlUrl* @return*/public  static String getHtml(String htmlUrl) {HttpURLConnection conn = null;try {URL url = new URL(htmlUrl);conn = (HttpURLConnection) url.openConnection();//设置输入流采用字节流conn.setDoInput(true);//设置输出流采用字节流conn.setDoOutput(true);//设置缓存conn.setUseCaches(false);conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");conn.setRequestProperty("Charset", "utf-8");//请求方法为GETconn.setRequestMethod("GET");//设置连接超时为5秒conn.setConnectTimeout(5000);//服务器返回东西了,先对响应码判断if (conn.getResponseCode() == 200) {//用getInputStream()方法获得服务器返回的输入流InputStream in = conn.getInputStream();byte[] data = read(in);//这里使用gbk,使在控制台打印数据不乱码String html = new String(data, "gbk");in.close();return html;} else {return "数据错误";}} catch (IOException e) {e.printStackTrace();return "数据错误";}}/*** 流转换为二进制数组,** @param inStream* @return* @throws IOException*/public static final byte[] read(InputStream inStream)throws IOException {ByteArrayOutputStream swapStream = new ByteArrayOutputStream();byte[] buff = new byte[100];int rc = 0;while ((rc = inStream.read(buff, 0, 100)) > 0) {swapStream.write(buff, 0, rc);}byte[] in2b = swapStream.toByteArray();return in2b;}/*** 正则表达式匹配两个指定字符串中间的内容** @param soap* @return*/public  static List<String> getSubUtil(String soap, String rgex) {List<String> list = new ArrayList<String>();// 匹配的模式Pattern pattern = Pattern.compile(rgex);Matcher m = pattern.matcher(soap);while (m.find()) {int i = 1;list.add(m.group(i));i++;}return list;}
}

生成的sql文件 下载地址:

https://github.com/bihansheng/china_city_name/blob/master/china_citys_name-20190410.sql

生成的json文件 下载地址:

https://github.com/bihansheng/china_city_name/blob/master/china_city_name_20190410112328.txt

国家统计局 2019年省市区数据(自取)相关推荐

  1. python中国大学排名爬虫写明详细步骤-Python爬虫--2019大学排名数据抓取

    Python爬虫--2019大学排名数据抓取 准备工作 输入:大学排名URL连接 输出:大学排名信息屏幕输出 所需要用到的库:requests,bs4 思路 获取网页信息 提取网页中的内容并放到数据结 ...

  2. qichacha/知乎/国家统计局最新4级地区划/百度地图API获取经纬度/Google play app评论等分数据爬取

    1.企查查数据抓取 1.1 关键公司LOGO # -*-coding:utf-8-*-import pandas as pd import requests import json import ra ...

  3. 关于Python爬虫原理和数据抓取1.1

    为什么要做爬虫? 首先请问:都说现在是"大数据时代",那数据从何而来? 企业产生的用户数据:百度指数.阿里指数.TBI腾讯浏览指数.新浪微博指数 数据平台购买数据:数据堂.国云数据 ...

  4. java 省市区数据data

    2019独角兽企业重金招聘Python工程师标准>>> java 省市区数据data CREATE TABLE hat_province ( sid number(11) NOT N ...

  5. quotes 整站数据爬取存mongo

    安装完成scrapy后爬取部分信息已经不能满足躁动的心了,那么试试http://quotes.toscrape.com/整站数据爬取 第一部分 项目创建 1.进入到存储项目的文件夹,执行指令 scra ...

  6. 网络爬虫——中国大学排名数据抓取

    网络爬虫--中国大学排名数据抓取 目标网址 中国大学排名网:http://www.zuihaodaxue.com/zuihaodaxuepaiming2019.html 全球有很多份大学排名,这里以上 ...

  7. 十年电影票房数据爬取与分析 | 免费数据教程

    3月8日妇女节,我很期待的超级英雄电影<惊奇队长>上映了,票房表现很快过亿,但大众口碑却让人失望. 一个有趣且常见的现象是,隔壁获奖无数,口碑爆炸的<绿皮书>,票房却远远不如& ...

  8. 如何用python抓取文献_浅谈Python爬虫技术的网页数据抓取与分析

    浅谈 Python 爬虫技术的网页数据抓取与分析 吴永聪 [期刊名称] <计算机时代> [年 ( 卷 ), 期] 2019(000)008 [摘要] 近年来 , 随着互联网的发展 , 如何 ...

  9. 以一举三的京东数据爬取(已经分配好各个方法,修改几行代码即可应用其他网站)并以json文件保存

    json的介绍 1.个人所理解的json就是一个与xml类似的数据存储文件, 而且也比xml容易写和读,跟python中字典很相似,本篇文章也是直接保存字典. 2.https://baike.baid ...

  10. python爬虫实战三:近十年中国电影票房数据爬取与分析

    近十年中国电影票房数据爬取与分析 前言 爬取 分析 十年top10 年度top5 每年电影数 每年总票房 二八原则 代码与数据 前言 这篇文章主要讲述的是近十年(2010-2019)中国电影票房数据的 ...

最新文章

  1. windows监控——再见zmq
  2. Java序列化和克隆
  3. 科大星云诗社动态20210321
  4. 蚂蚁集团董事调整:黄益平等五人新增,彭蕾等三人退出
  5. 人工智能化发展已经到了哪一步?
  6. MAC 设置$PATH 关闭terminal后就失效 解决方案
  7. 最新 955 不加班公司名单
  8. 【C#版本详情回顾】C#2.0主要功能列表
  9. python爬虫爬取慕课网中的图片
  10. Hbase记录-client访问zookeeper大量断开以及参数调优分析(转载)
  11. 零信任时代,开放式安全沙箱让管控更灵活
  12. 16S 扩增子分析工具:Swarm 聚类OTU流程介绍
  13. 键盘数字测试软件,KeyboardTest(键盘测试工具)官方版
  14. 记一次失败的应聘实习经历
  15. php webshell探索-常见小马
  16. 自动向你的宝马车播放捷豹广告,这家公司要做高速公路上的“分众”
  17. 平平无奇的营销小天才——ChatGPT
  18. 上经 -- 乾【卦一】乾为天(一)
  19. 序列化和反序列化的概念及应用
  20. 2-44钟静雯_day03

热门文章

  1. 谷歌“Adobe Flash Player已被屏蔽”的解决办法
  2. 海康威视客户端iVMS-4200连接NVR
  3. 今晚直播丨易鲸捷HTAP融合型分布式数据库问题诊断介绍
  4. IBM Think 2019核心议题:如何打造可信人工智能
  5. USB Repair(usb设备修复工具)官方正式版V8.0.3.1069 | u盘修复软件下载 | u盘修复软件哪个最好?
  6. iOS宏定义的黑魔法 - 宏菜鸟起飞手册
  7. vue引入阿里巴巴矢量图标
  8. python创建空文本文件_Python空白txt文件创建
  9. 前端架构设计第四课 Babel构建公共库实战
  10. 神经网络的优缺点是什么,深度神经网络的优缺点