https://github.com/sotex/XingZhengQuHuaShuJu.git
天地图接口
天地图官网都有相关介绍,这里只是简单的搬运一下。
接口说明地址:http://lbs.tianditu.gov.cn/server/administrative.html
天地图的数据缺失部分如下:
接口信息
天地图行政区划API是一类简单的HTTP/HTTPS接口,提供由行政区划地名、行政区划编码查询中心点、轮廓、所属上级行政区划的功能。
请求:
http://api.tianditu.gov.cn/administrative?postStr={"searchWord":"北京","searchType":"1","needSubInfo":"false","needAll":"false","needPolygon":"true","needPre":"true"}&tk=您的密钥
返回:
{
"msg": "ok",
"data": [{
"lnt": 116.40100299989,
"adminType": "province",
"englishabbrevation": "BeiJing",
"nameabbrevation": "北京",
"level": 11,
"cityCode": "156110000",
"bound": "115.422051,40.978643,117.383319,39.455766",
"name": "北京市",
"english": "BeiJing Shi",
"lat": 39.90311700025,
"points": [{
"region": "117.383 40.226,117.203 40.081,116.775 40.034,116.78 39.888,116.92 39.834,116.9 39.687,116.806 39.615,116.563 39.619,116.328 39.456,116.235 39.563,115.918 39.596,115.815 39.508,115.566 39.591,115.48 39.74,115.517 39.898,115.422 39.983,115.589 40.115,115.829 40.144,115.956 40.268,115.766 40.442,115.902 40.616,116.067 40.611,116.213 40.741,116.451 40.797,116.449 40.979,116.672 40.97,116.959 40.708,117.283 40.659,117.223 40.386,117.383 40.226"
}],
"parents": {
"country": {
"adminType": "country",
"cityCode": "156000000",
"name": "中华人民共和国"
}
}
}],
"returncode": "100",
"dataversion": "20180719",
"dataInsertMess": "数据库已存在该版本,不进行导入"
}
代码
代码可见 下载天地图行政区划数据
民政部数据
民政部网站没有提供相关的接口,但是可以从查询网站调试获取。民政部的数据比较分散,需要从多个接口读取然后进行组合。
民政部的数据当前是更新到2018年的,且坐标是有偏移,需要进一步处理。
注:民政部的数据不包括港澳台地区详细数据。
获取全国县级行政区信息
请求:
curl --request GET
--url 'http://xzqh.mca.gov.cn/getInfo?code=100000&type=1'
--header 'pragma: no-cache'
--header 'referer: http://xzqh.mca.gov.cn/defaultQuery?'
--header 'user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:73.0) Gecko/20100101 Firefox/73.0'
--cookie 浏览器调试获取
返回:
结果中依次为:名称、驻地、人口(万)、面积(平方千米)、区号、代码、类型、省、地市
{
"110101": [
"东城区",
"景山街道",
"97",
"42",
"010",
"100010",
"市辖区",
"北京市",
""
],
"110102": [
"西城区",
"金融街街道",
"139",
"51",
"010",
"100032",
"市辖区",
"北京市",
""
],
...
"440983": [
"信宜市",
"东镇街道",
"136",
"3081",
"0668",
"525300",
"县级市",
"广东省",
"茂名市"
],
全国县级行政区边界
这个接口获取的是一个 TopoJSON 的数据,可以使用 ogr2ogr 程序转换为 GeoJSON 等,也可以直接使用 QGIS 打开查看。
请求:
curl --request GET
--url http://xzqh.mca.gov.cn/data/xian_quanguo.json
--header 'pragma: no-cache'
--header 'referer: http://xzqh.mca.gov.cn/defaultQuery?'
--header 'user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:73.0) Gecko/20100101 Firefox/73.0'
--cookie 浏览器调试获取
返回:
{"type":"Topology","arcs":[[[122624,100420],[28,-20],[21,-71],[41,3],[43,-83]],[[122757,100249],[47,-24],[79,-103],[6,-13],[65,-107],[-10,-64],[-3,-7],[-27,-100],[44,-36],[5,-15],[-22 ... {"arcs":[[9424]],"type":"Polygon","properties":{"NAME":"460300","QUHUADAIMA":"daodian","FillColor":""}},{"arcs":[[9425]],"type":"Polygon","properties":{"NAME":"460300","QUHUADAIMA":"daodian","FillColor":""}},{"arcs":[[9426]],"type":"Polygon","properties":{"NAME":"460300","QUHUADAIMA":"daodian","FillColor":""}},{"arcs":[[9427]],"type":"Polygon","properties":{"NAME":"460300","QUHUADAIMA":"daodian","FillColor":""}},{"arcs":[[9428]],"type":"Polygon","properties":{"NAME":"460300","QUHUADAIMA":"daodian","FillColor":""}},{"arcs":[[9429]],"type":"Polygon","properties":{"NAME":"460300","QUHUADAIMA":"daodian","FillColor":""}},{"arcs":[[9430]],"type":"Polygon","properties":{"NAME":"460300","QUHUADAIMA":"daodian","FillColor":""}}]}},"crs":{"type":"name","properties":{"name":"urn:ogc:def:crs:OGC:1.3:CRS84"}}}
政府驻地地理位置
这个接口用于获取某个地区的政府驻地坐标,用于在地图上显示区域关键点。
请求(url 中的文件名是行政区的代码):
curl --request GET
--url http://xzqh.mca.gov.cn/data/430600_Point.geojson
--header 'pragma: no-cache'
--header 'referer: http://xzqh.mca.gov.cn/defaultQuery?'
--header 'user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:73.0) Gecko/20100101 Firefox/73.0'
--cookie 浏览器调试获取
返回:
{
"type": "FeatureCollection",
"name": "点",
"features": [
{
"type": "Feature",
"properties": {
"NAME": "临湘市",
"QUHUADAIMA": "430682",
"Location": 6,
"Alignment": 1
},
"geometry": {
"type": "Point",
"coordinates": [
113.59011657158062,
29.605213651824659
]
}
},
{
"type": "Feature",
"properties": {
"NAME": "汨罗市",
"QUHUADAIMA": "430681",
"Location": 2,
"Alignment": 2
},
"geometry": {
"type": "Point",
"coordinates": [
113.20413521709955,
28.93628661571595
]
}
...
代码
代码可见 下载民政部行政区划数据
// 下载民政部行政区划数据
package main
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
"os"
"os/exec"
"strconv"
geojson "github.com/paulmach/go.geojson"
)
type (
// XZQXX 行政区信息
XZQXX struct {
Diji string `json:"diji"`
QuHuaDaiMa string `json:"quHuaDaiMa"`
Quhao string `json:"quhao"`
Shengji string `json:"shengji"`
Xianji string `json:"xianji"`
}
XZQXX2 struct {
Level int `json:"level"`
Abbr string `json:"Abbr"`
Type string `json:"Type"`
Position []float64 `json:"Position"`
EnName string `json:"EnName"`
EnAbbr string `json:"EnAbbr"`
Bound []float64 `json:"bound"`
}
)
var (
// 所有县的基本信息
xianInfo map[string][]string
// 所有县的信息
xianInfo2 map[string]XZQXX2
// 所有县geojson要素
allXian map[string][]geojson.Feature
// 所有地级市(包括直辖市)要素
allDiqu map[string][]geojson.Feature
)
// DownloadBianjie 下载边界数据
func DownloadBianjie(qhdm string) ([]byte, error) {
req, err := http.NewRequest("GET", "http://xzqh.mca.gov.cn/data/"+qhdm+".json", nil)
if err != nil {
return nil, err
}
req.Header.Set("Cookie", "浏览器调试可获取")
req.Header.Set("Pragma", "no-cache")
req.Header.Set("Referer", "http://xzqh.mca.gov.cn/defaultQuery?")
req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:73.0) Gecko/20100101 Firefox/73.0")
resp, err := http.DefaultClient.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
return nil, fmt.Errorf("错误")
}
return ioutil.ReadAll(resp.Body)
}
// TopojsonToGeojson 转换到geojson
func TopojsonToGeojson(ci XZQXX, topojsonpath, geojsonpath string) error {
_, err := os.Stat(topojsonpath)
if err != nil {
// ogr2ogr -f "GeoJSON" 输出.geojson 输入.topojson [可选 图层名]
cmd := exec.Command("C:/QGIS/QGIS 3.10/bin/ogr2ogr.exe", "-f", "GeoJSON", geojsonpath, topojsonpath)
cmd.Env = append(cmd.Env, "GDAL_DATA=C:/QGIS/QGIS 3.10/share/gdal")
cmd.Stdout = os.Stdout
err := cmd.Run()
if err != nil {
return fmt.Errorf("运行错误:%v[%v]", err, cmd.Args)
}
}
// 读取后进行清理
geojsondata, err := ioutil.ReadFile(geojsonpath)
if err != nil {
return fmt.Errorf("读取geojson出错:%v", err)
}
fc, err := geojson.UnmarshalFeatureCollection(geojsondata)
err = json.Unmarshal(geojsondata, &fc)
if err != nil {
return fmt.Errorf("解析出错:%v", err)
}
// 行政区划代码长度,直辖市中间2位是00
prefixlen := 4
if ci.QuHuaDaiMa[2:6] == "0000" {
prefixlen = 2
}
for i := 0; i < len(fc.Features); i++ {
f := fc.Features[i]
quhuadaima, err := f.PropertyString("QUHUADAIMA")
// 跳过外部区域
if err != nil ||
len(quhuadaima) != 6 || quhuadaima == "fanwei" ||
quhuadaima[0:prefixlen] != ci.QuHuaDaiMa[0:prefixlen] {
continue
}
// 判断是县级还是地市
if quhuadaima == ci.QuHuaDaiMa {
_, ok := allDiqu[ci.QuHuaDaiMa]
if !ok {
allDiqu[quhuadaima] = []geojson.Feature{*f}
} else {
// 一个地区可能有多个多边形,后面再进行合并
allDiqu[quhuadaima] = append(allDiqu[quhuadaima], *f)
}
} else {
_, ok := allXian[quhuadaima]
if !ok {
allXian[quhuadaima] = []geojson.Feature{*f}
} else {
allXian[quhuadaima] = append(allXian[quhuadaima], *f)
}
}
}
return nil
}
// geojsonprocess 转换出的 GeoJSON 数据进行处理,因为转换出来的是一个个分开的,需要将有多个部分的进行合并
func geojsonprocess(dclsj map[string][]geojson.Feature, filename string) error {
buf := bytes.NewBuffer(nil)
for daima, fv := range dclsj {
polycount := len(fv)
name, err := fv[0].PropertyString("NAME")
if err != nil {
log.Println("错误:", daima, err)
}
var feature *geojson.Feature = nil
if polycount == 1 {
feature = &fv[0]
} else {
// 将多个 多边形 合并为一个 多多边形
polygons := make([][][][]float64, polycount)
for i := 0; i < polycount; i++ {
polygons[i] = fv[i].Geometry.Polygon
}
fmpoly := geojson.NewMultiPolygonFeature(polygons...)
filecolor, _ := fv[0].PropertyString("FillColor")
fmpoly.SetProperty("FillColor", filecolor)
feature = fmpoly
}
// 设置属性
{
feature.SetProperty("名称", name)
feature.SetProperty("代码", daima)
}
sx, ok := xianInfo[daima]
if ok {
feature.SetProperty("驻地", sx[1])
num, _ := strconv.Atoi(sx[2])
feature.SetProperty("人口", num)
num, _ = strconv.Atoi(sx[3])
feature.SetProperty("面积", num)
feature.SetProperty("区号", sx[4])
feature.SetProperty("类型", sx[6])
}
sx2, ok := xianInfo2[daima]
if ok {
feature.SetProperty("简称", sx2.Abbr)
feature.SetProperty("英文名", sx2.EnName)
feature.SetProperty("英文简称", sx2.EnAbbr)
feature.SetProperty("级别", sx2.Level)
feature.BoundingBox = sx2.Bound
}
data, err := json.Marshal(feature)
if err != nil {
return err
}
buf.Write(data)
buf.WriteByte('
')
}
return ioutil.WriteFile(filename, buf.Bytes(), os.ModePerm)
}
func main() {
// 读取地级(包括直辖市)行政区划列表
data, err := ioutil.ReadFile("data/地级行政区列表.json")
if err != nil {
log.Println(err)
return
}
var qhxx []XZQXX
err = json.Unmarshal(data, &qhxx)
if err != nil {
log.Println(err)
return
}
// 读取县级行政区划数据
data, err = ioutil.ReadFile("data/全国县级行政区信息.json")
if err != nil {
log.Println(err)
return
}
xianInfo = make(map[string][]string)
err = json.Unmarshal(data, &xianInfo)
if err != nil {
log.Println(err)
return
}
// 读取全国行政区划信息数据
data, err = ioutil.ReadFile("data/行政区信息.json")
if err != nil {
log.Println(err)
return
}
xianInfo2 = make(map[string]XZQXX2)
err = json.Unmarshal(data, &xianInfo2)
if err != nil {
log.Println(err)
return
}
allXian = make(map[string][]geojson.Feature)
allDiqu = make(map[string][]geojson.Feature)
for i := 0; i < len(qhxx); i++ {
if len(qhxx[i].QuHuaDaiMa) != 6 {
continue
}
topojsonpath := "data/download/" + qhxx[i].QuHuaDaiMa + ".topojson"
geojsonpath := "data/download/" + qhxx[i].QuHuaDaiMa + ".geojson"
_, err := os.Stat(topojsonpath)
if err != nil {
data, err = DownloadBianjie(qhxx[i].QuHuaDaiMa)
if err != nil {
log.Println("下载出错", err)
continue
}
err := ioutil.WriteFile(topojsonpath, data, os.ModePerm)
if err != nil {
log.Println("下载写入", err)
continue
}
} else {
data, err = ioutil.ReadFile(topojsonpath)
}
log.Println("下载完成", qhxx[i].QuHuaDaiMa, qhxx[i].Diji)
err = TopojsonToGeojson(qhxx[i], topojsonpath, geojsonpath)
if err != nil {
log.Println("转换出错", err)
return
}
log.Println("转换完成")
}
err = geojsonprocess(allXian, "data/全国县级.geojson")
if err != nil {
log.Println("县级处理出错", err)
}
log.Println("县级处理完成")
err = geojsonprocess(allDiqu, "data/全国地级.geojson")
if err != nil {
log.Println("地级处理出错", err)
}
log.Println("地级处理完成")
}