前言
昨天在网上瞎逛的时候,看到了一个概念——交通生活圈,经过一番查阅后,约模知道了它的意思:在现有交通状况下,在一定的时间内乘坐现有交通工具你能抵达的范围(ps.通常是指驾车)。 简单来说,就是:“30分钟内你能走多远?” 正好某德地图上也有类似的数据,效果如下:
它包含了20分钟、30分钟、45分钟、60分钟、90分钟这5类数据,它范围即对应的交通生活圈。感觉很厉害的鸭子~
于是,我决定自己探索一番…
一、获取数据
1. 交通生活圈数据
打开浏览器的F12调试工具,监听网络请求:
其接口地址为:
https://report.amap.com/ajax/life/circle.do
有3个参数,对应的说明如下:
参数 | 说明 |
---|
那么,可以定义获取数据的函数:
def get_data(disID): ''' 获得交通生活圈数据 ''' url = 'https://report.amap.com/ajax/life/circle.do' headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; Win64; x64; rv:84.0) Gecko/20100101 Firefox/84.0', 'Accept': 'application/json, text/javascript, */*; q=0.01', 'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2', 'X-Requested-With': 'XMLHttpRequest', 'Connection': 'keep-alive', 'TE': 'Trailers', } hour = time.strftime('%H',time.localtime(time.time())) # 当前小时 params = ( ('districtId', disID), ('dir', '0'), ('timeIndex', hour), ) res = requests.get(url, headers=headers, params=params) data = res.json() return data
返回的数据为JSON格式,为一个列表,包含5个子列表,每个列表分别表示20分钟、30分钟、45分钟、60分钟、90分钟的数据。 本以为到这里就大功告成了,然而我们发现districtId为类似“B0FFFDS1JU”的字符串编码,不便于直接利用,因此需要找到它的来源。
2. 城市区域数据
同样是通过F12抓包分析,可以找到一个请求,它可以返回每个城市对应的区域及相关信息(包括了我们苦苦寻找的districtId)。那么,便可以定义相应的函数:
def get_id(cityID): ''' 获得城市区域ID ''' url = 'https://report.amap.com/ajax/life/districts.do' headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; Win64; x64; rv:84.0) Gecko/20100101 Firefox/84.0', 'Accept': 'application/json, text/javascript, */*; q=0.01', 'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2', 'X-Requested-With': 'XMLHttpRequest', 'Connection': 'keep-alive', 'Referer': 'https://report.amap.com/life.do?city=420100', 'TE': 'Trailers', } params = ( ('cityCode', cityID), ) res = requests.get(url, headers=headers, params=params) data =res.json() return data
通过传入城市ID,便可得到其下区域的相关信息:
如出一辙,传入的参数为城市ID,这并不直观,我们无法很快知道每个城市对应的ID是什么。 正所谓:“探索尚未结束,同志仍需努力…”
3. 城市数据
如法炮制,我们找到了获取城市数据的接口,并定义如下函数:
def get_city(): ''' 获取城市信息(城市名、城市ID等) ''' url = 'https://report.amap.com/ajax/getCityInfo.do' headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; Win64; x64; rv:84.0) Gecko/20100101 Firefox/84.0', 'Accept': 'application/json, text/javascript, */*; q=0.01', 'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2', 'X-Requested-With': 'XMLHttpRequest', 'Connection': 'keep-alive', } res = requests.get(url, headers=headers) data = res.json() return data
其结果如是:
4. 完整代码
为了更加方便地获取数据,将以上函数整合在一起,完整的代码如下:
# -*- coding: utf-8 -*- """ Created on Mon Dec 21 15:14:42 2020 @author: kimol_love """ import os import time import json import requests def get_city(): ''' 获取城市信息(城市名、城市ID等) ''' url = 'https://report.amap.com/ajax/getCityInfo.do' headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; Win64; x64; rv:84.0) Gecko/20100101 Firefox/84.0', 'Accept': 'application/json, text/javascript, */*; q=0.01', 'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2', 'X-Requested-With': 'XMLHttpRequest', 'Connection': 'keep-alive', } res = requests.get(url, headers=headers) data = res.json() return data def get_id(cityID): ''' 获得城市区域ID ''' url = 'https://report.amap.com/ajax/life/districts.do' headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; Win64; x64; rv:84.0) Gecko/20100101 Firefox/84.0', 'Accept': 'application/json, text/javascript, */*; q=0.01', 'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2', 'X-Requested-With': 'XMLHttpRequest', 'Connection': 'keep-alive', 'Referer': 'https://report.amap.com/life.do?city=420100', 'TE': 'Trailers', } params = ( ('cityCode', cityID), ) res = requests.get(url, headers=headers, params=params) data =res.json() return data def get_data(disID): ''' 获得交通生活圈数据 ''' url = 'https://report.amap.com/ajax/life/circle.do' headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; Win64; x64; rv:84.0) Gecko/20100101 Firefox/84.0', 'Accept': 'application/json, text/javascript, */*; q=0.01', 'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2', 'X-Requested-With': 'XMLHttpRequest', 'Connection': 'keep-alive', 'TE': 'Trailers', } hour = time.strftime('%H',time.localtime(time.time())) # 当前小时 params = ( ('districtId', disID), ('dir', '0'), ('timeIndex', hour), ) res = requests.get(url, headers=headers, params=params) data = res.json() return data if __name__ == '__main__': # 获取城市信息 cityInfo = get_city() # 输入城市及片区 while True: cityName = input('请输入城市:') flag = 0 for city in cityInfo: if cityName == city['name']: cityID = city['code'] disIDs = get_id(cityID) if len(disIDs) == 0: flag = 1 else: flag = 2 break if flag == 0: # 如果没有该城市 print('未找到相关城市!') elif flag == 1: # 如果该城市没有数据 print('该城市无数据!:') elif flag == 2: break print('-'*20) print(('0==>所有').ljust(10)) for i in range(len(disIDs)): print(('%d==>%s'%(i+1, disIDs[i]['name'])).ljust(10)) print('-'*20) while True: index = int(input('请选择:')) if index not in range(len(disIDs)+1): print('输入错误!:') else: break # 下载数据 if not os.path.exists('./data'): os.mkdir('./data') if index == 0: # 全部下载 if not os.path.exists('./data/%s'%cityName): os.mkdir('./data/%s'%cityName) for i in range(len(disIDs)): disID = disIDs[i]['id'] data = get_data(disID) data.append(disIDs[i]['center']) # 加入中心点 data = json.dumps(data) with open('./data/%s/%s.json'%(cityName,disIDs[i]['name']), 'w') as f: f.write(data) print('"%s"获取成功!'%disIDs[i]['name']) else: disID = disIDs[index-1]['id'] data = get_data(disID) data.append(disIDs[index-1]['center']) # 加入中心点 data = json.dumps(data) with open('./data/%s.json'%disIDs[i]['name'], 'w') as f: f.write(data) print('"%s"获取成功!'%disIDs[i]['name'])
注:为了便于后续地分析,我们将数据append了一个列表(区域的中心位置),因此data一共包含6个列表:5类数据+中心点位置。
俗话说得好,好用不好用,拉出来run一run:
电闪雷鸣之间,只见所有的数据默默地躺入了我温暖的怀抱~ 至此,数据获取的探索便可暂告于段落。
二、30分钟交通生活圈
1. 数据分析
有了数据,通过分析我们便可知道30分钟自己能“走”多远了。这里我们用到了Python中的folium库,它是一个交互式地图库,允许我们调用地图接口进行可视化分析。其安装方法如下:
pip install folium
首先,定义读取数据的函数:
def read_data(path, Type=30): ''' 读取交通生活圈数据(有20分钟、30分钟、45分钟、60分钟、90分钟) ''' typeMap = {20:0, 30:1, 45:2, 60:3, 90:4} with open(path, 'r') as f: data = f.read() data = json.loads(data) center = data[-1] data = data[typeMap[Type]] return (center, data)
读取数据(以成都的牛王庙为例):
center, data = read_data('./data/成都/牛王庙.json') data.append(data[0]) for i in range(len(data)): # 交换经纬度,很重要 data[i] = [data[i][1],data[i][0]]
data.append(data[0])是为了使数据形成一个闭环,这样方便在地图上表示出来。 定义地图,并设定相关参数:
Map=folium.Map(location=[center[1],center[0]], zoom_start=11, tiles='http://webrd02.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=7&x={x}&y={y}&z={z}', attr='default' )
在地图上标出起始点:
folium.Marker([center[1],center[0]], popup=folium.Popup('牛王庙',max_width=1000), tooltip='出发点' ).add_to(Map)
在地图上画出30分钟交通生活的区域:
folium.Polygon(data, color='#7C9F59', fill=True).add_to(Map)
将地图保存到本地:
Map.save('30分钟交通生活圈.html')
打开HTML之后,效果如下:
绿色区域意味着,在当前的交通情况下,我从牛王庙出发,我可以到达的范围,即30分钟我能“走”多远~
2. 完整代码
这一部分的完整代码如下:
# -*- coding: utf-8 -*- """ Created on Mon Dec 21 18:58:34 2020 @author: kimol_love """ import json import folium def read_data(path, Type=30): ''' 读取交通生活圈数据(有20分钟、30分钟、45分钟、60分钟、90分钟) ''' typeMap = {20:0, 30:1, 45:2, 60:3, 90:4} with open(path, 'r') as f: data = f.read() data = json.loads(data) center = data[-1] data = data[typeMap[Type]] return (center, data) if __name__ == '__main__': center, data = read_data('./data/成都/牛王庙.json') data.append(data[0]) for i in range(len(data)): # 交换经纬度,很重要 data[i] = [data[i][1],data[i][0]] Map=folium.Map(location=[center[1],center[0]], zoom_start=11, tiles='http://webrd02.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=7&x={x}&y={y}&z={z}', attr='default' ) folium.Marker([center[1],center[0]], popup=folium.Popup('牛王庙',max_width=1000), tooltip='出发点' ).add_to(Map) folium.Polygon(data, color='#7C9F59', fill=True).add_to(Map) Map.save('30分钟交通生活圈.html')
写在最后
至此,我们大致知道了30分钟自己能“走”多远了~
这里主要是从交通通行情况的角度出发,如果非得说坐飞机、坐火箭、坐大炮啥的。别问我,问了我也不知道(手动捂脸)~
其实,这个数据还可以尝试从更多地角度分析,比如可以计算出30分钟最大抵达半径,并进一步比较不同城市的大小等等。如果有感兴趣的小伙伴,可以试试哦。
我是kimol君,咋们下次再会~
创作不易,大侠请留步… 动起可爱的双手,来个赞再走呗 (๑◕ܫ←๑)
原文地址:想知道自己30分钟能“走”多远嘛?_kimol君的博客-优快云博客
后记
近期有很多朋友通过私信咨询有关Python学习问题。为便于交流,点击蓝色自己加入讨论解答资源基地