Python获取最新省市区列表并绘制中国地图(含港澳台)

简介

数据来源:




安装

pip install requests




初试

使用腾讯 API

1. 注册

2. 我的应用 → 创建应用

3. 添加 Key:Key名称随意,启用产品 WebServiceAPI,选签名校验,复制 Secret key

4. 复制 Key

5. 获取最新省市区列表并保存为JSON

import json
from hashlib import md5
from urllib.parse import urljoin, urlencode

import requests

key = 'JYRBZ-6B7WQ-SKG52-GKT6U-INYEH-OTB2B'
secret_key = 'qhiND3JeHmFJTPk0HliqClqWn1ytmHqd'
path = '/ws/district/v1/list'
base = 'https://apis.map.qq.com/'
url = urljoin(base, path)
params = dict(key=key)
params = {k: v for k, v in sorted(params.items())}  # 升序排序
sig = md5('{}?{}{}'.format(path, urlencode(params), secret_key).encode()).hexdigest()  # 签名计算
params['sig'] = sig  # 放回请求
response = requests.get(url=url, params=params)
data = response.json()
print(data)
open('data.json', mode='w', encoding='utf-8').write(json.dumps(data))

效果




响应结果

data_version:行政区划数据版本

result 的结果:

  • 行政区划
    • id:行政区划唯一标识(adcode)
    • name:简称,如“内蒙古”
    • fullname:全称,如“内蒙古自治区”
    • location:经纬度
      • lat:纬度
      • lng:经度
    • pinyin:行政区划拼音全拼的数组,如:[“nei”,“meng”,“gu”]
    • cidx:子级行政区划在下级数组中的下标位置
    • polygon:行政区划的轮廓经纬度点串,可形成多边形




直接展示

import json

data = json.load(open('data.json'))
data_version = data['data_version']
print(data_version)
provinces = data['result'][0]
citys = data['result'][1]
districts = data['result'][2]
for province in provinces:
    cidx = province['cidx']
    province_citys = citys[cidx[0]:cidx[1]]
    print(province['fullname'])
    for city in province_citys:
        print('\t', city['fullname'])
        cidx = city.get('cidx')
        if cidx:
            city_districts = districts[cidx[0]:cidx[1]]
            for district in city_districts:
                print('\t\t', district['fullname'])
# 广东省
# 	 广州市
# 		 荔湾区
# 		 越秀区
# 		 海珠区
# 		 天河区
# 		 白云区
# 		 黄埔区
# 		 番禺区
# 		 花都区
# 		 南沙区
# 		 从化区




构造字典

import json
from collections import defaultdict

data = json.load(open('data.json'))
provinces = data['result'][0]
citys = data['result'][1]
districts = data['result'][2]
province_city_district_map = defaultdict(lambda: defaultdict(list))
for province in provinces:
    cidx = province['cidx']
    province_citys = citys[cidx[0]:cidx[1]]
    for city in province_citys:
        if city['fullname'] not in province_city_district_map[province['fullname']]:
            province_city_district_map[province['fullname']][city['fullname']] = list()
        cidx = city.get('cidx')
        if cidx:
            city_districts = districts[cidx[0]:cidx[1]]
            for district in city_districts:
                province_city_district_map[province['fullname']][city['fullname']].append(district['fullname'])
print(province_city_district_map)




树结构展示

安装

pip install treelib

代码

import json

from treelib import Tree

data = json.load(open('data.json'))
data_version = data['data_version']
provinces = data['result'][0]
citys = data['result'][1]
districts = data['result'][2]
tree = Tree()
tree.create_node('中国省市区列表', data_version)  # 根节点
for province in provinces:
    cidx = province['cidx']
    province_citys = citys[cidx[0]:cidx[1]]
    tree.create_node(province['fullname'], province['id'], parent=data_version)
    for city in province_citys:
        tree.create_node(city['fullname'], city['id'], parent=province['id'])
        cidx = city.get('cidx')
        if cidx:
            city_districts = districts[cidx[0]:cidx[1]]
            for district in city_districts:
                tree.create_node(district['fullname'], district['id'], parent=city['id'])
tree.show()
# ├── 广东省
# │   ├── 东莞市
# │   ├── 中山市
# │   ├── 佛山市
# │   │   ├── 三水区
# │   │   ├── 南海区
# │   │   ├── 禅城区
# │   │   └── 顺德区

统计,有某些区名是重复的

from collections import Counter

counter = Counter([tree[node].tag for node in tree.expand_tree(mode=Tree.DEPTH, sorting=False)])
print(counter)
# Counter({'东区': 6, '鼓楼区': 4, '市中区': 4, '北区': 4, '和平区': 3, '新华区': 3, '城区': 3, '郊区': 3, '铁西区': 3, '中山区': 3, '南区': 3, '朝阳区': 2, '通州区': 2, '河东区': 2, '长安区': 2, '桥西区': 2, '复兴区': 2, '新城区': 2, '青山区': 2, '松山区': 2, '铁东区': 2, '海州区': 2, '太平区': 2, '龙潭区': 2, '西安区': 2, '向阳区': 2, '南山区': 2, '东山区': 2, '宝山区': 2, '大同区': 2, '新兴区': 2, '普陀区': 2, '金山区': 2, '西湖区': 2, '江北区': 2, '永定区': 2, '泰山区': 2, '白云区': 2, '龙华区': 2, '城中区': 2, '大安区': 2, '西区': 2, '城关区': 2, '新市区': 2, '中正区': 2, '信义区': 2, '中西区': 2})




tkinter展示

import json
from tkinter import *
from tkinter import ttk
from collections import defaultdict

data = json.load(open('data.json'))
provinces = data['result'][0]
citys = data['result'][1]
districts = data['result'][2]
province_fullnames = []
province_city_district_map = defaultdict(lambda: defaultdict(list))
for province in provinces:
    province_fullnames.append(province['fullname'])
    cidx = province['cidx']
    province_citys = citys[cidx[0]:cidx[1]]
    for city in province_citys:
        if city['fullname'] not in province_city_district_map[province['fullname']]:
            province_city_district_map[province['fullname']][city['fullname']] = list()
        cidx = city.get('cidx')
        if cidx:
            city_districts = districts[cidx[0]:cidx[1]]
            for district in city_districts:
                province_city_district_map[province['fullname']][city['fullname']].append(district['fullname'])

last_province = ''  # 上次选择的省
last_city = ''  # 上次选择的市


def select_province(event):
    """选择了省"""
    global last_province
    province = province_combobox.get()
    city_combobox['value'] = [i for i in province_city_district_map[province].keys()]
    if last_province != province:
        city_combobox.set('')
        district_combobox.set('')
    last_province = province


def select_city(event):
    """选择了市"""
    global last_city
    province = province_combobox.get()
    city = city_combobox.get()
    district_combobox['value'] = province_city_district_map[province][city]
    if last_city != city:
        district_combobox.set('')
    last_city = city


win = Tk()
win.title('中国省市区列表')
win.geometry('280x130')
win.eval('tk::PlaceWindow . center')
province_combobox = ttk.Combobox(win, value=province_fullnames)
province_combobox.bind('<<ComboboxSelected>>', select_province)
province_combobox.pack(fill=BOTH, expand=True)
city_combobox = ttk.Combobox(win)
city_combobox.bind('<<ComboboxSelected>>', select_city)
city_combobox.pack(fill=BOTH, expand=True)
district_combobox = ttk.Combobox(win)
district_combobox.pack(fill=BOTH, expand=True)
statusbar = Label(win, text='数据版本:{}'.format(data['data_version']), bd=1, relief=SUNKEN, anchor=W, name='statusbar')
statusbar.pack(side=BOTTOM, fill=X)
win.mainloop()

效果




绘制成图

获取数据

import json
from hashlib import md5
from urllib.parse import urljoin, urlencode

import requests

key = 'JYRBZ-6B7WQ-SKG52-GKT6U-INYEH-OTB2B'
secret_key = 'qhiND3JeHmFJTPk0HliqClqWn1ytmHqd'
path = '/ws/district/v1/getchildren'
base = 'https://apis.map.qq.com/'
url = urljoin(base, path)
params = dict(key=key, get_polygon=2)
params = {k: v for k, v in sorted(params.items())}  # 升序排序
sig = md5('{}?{}{}'.format(path, urlencode(params), secret_key).encode()).hexdigest()  # 签名计算
params['sig'] = sig  # 放回请求
response = requests.get(url=url, params=params)
data = response.json()
print(data)
open('polygon.json', mode='w', encoding='utf-8').write(json.dumps(data))

安装

pip install basemap

绘制

import json

import matplotlib.pyplot as plt
from matplotlib.patches import Polygon
from mpl_toolkits.basemap import Basemap


def get_mass_center(xy):
    """计算多边形重心"""
    area = 0.0
    x, y = 0.0, 0.0
    for i in range(len(xy)):
        lat = xy[i][0]
        lng = xy[i][1]
        if i == 0:
            lat1 = xy[-1][0]
            lng1 = xy[-1][1]
        else:
            lat1 = xy[i - 1][0]
            lng1 = xy[i - 1][1]
        fg = (lat * lng1 - lng * lat1) / 2.0
        area += fg
        x += fg * (lat + lat1) / 3.0
        y += fg * (lng + lng1) / 3.0
    x = x / area
    y = y / area
    return x, y


# 读取
data = json.load(open('polygon.json'))
province_polygon_map = dict()
for province in data['result'][0]:
    province_polygon_map[province['name']] = province['polygon']

# 中文
plt.rcParams['font.sans-serif'] = ['SimHei']  # 微软雅黑
plt.rcParams['axes.unicode_minus'] = False  # 正确显示负号

# 绘制
m = Basemap(
    llcrnrlon=77, llcrnrlat=14,  # 左下角经纬度
    urcrnrlon=140, urcrnrlat=51,  # 右上角经纬度
    projection='lcc',  # 地图投影方式为朗伯等角圆锥投影
    lat_0=33,  # 纬度中心
    lon_0=100  # 经度中心
)
m.fillcontinents(color='white')  # 填充大陆

for province, polygons_list in province_polygon_map.items():
    xy_list = []  # 行政区多个多边形的所有点
    for polygons in polygons_list:
        xy = []
        for i in range(len(polygons))[::2]:  # 经纬度多边形
            xy_list.append((polygons[i], polygons[i + 1]))
            xy.append(m(polygons[i], polygons[i + 1]))
        plt.gca().add_patch(Polygon(xy))
    x, y = get_mass_center(xy_list)  # 多边形重心
    x = x - 1.2  # 手动修正
    y = y - 0.5
    plt.annotate(province, xy=m(x, y))  # 填上省份
    print(province, x, y)
plt.annotate('海南', xy=m(108.0, 19.0))  # 不知道为什么API获取的海南好像有问题,手动填入

plt.xticks([])  # 去掉x轴
plt.yticks([])  # 去掉y轴
plt.axis('off')  # 去掉坐标轴
plt.savefig('1.jpg', dpi=300, bbox_inches='tight')  # 保存图片
plt.show()

对比百度地图




参考文献

  1. WebService API | 腾讯位置服务
  2. 国家统计局 - 统计用区划和城乡划分代码
  3. 2021最新省市区 Gitee
  4. 最全最新中国省,市,地区json及sql数据 GitHub
  5. Python树结构库treelib
  6. Matplotlib Basemap Toolkit Documentation
  7. python采用Basemap绘制完美中国地图
  8. python 不规则多边形计算重心
  9. How to compute the centroid of a polygon in Python
  10. Shapely Ddocumentation
  11. 判断点是否在多边形内的Python实现及小应用(射线法)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

XerCis

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值