简介
数据来源:
安装
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()
对比百度地图