一、需求:
爬取交通态势API,将数据可视化为含有交通态势信息的矢量路网数据。
二、使用的工具:
Python IDLE、记事本编辑器、ArcGIS 10.2、申请的开发者KEY(免费)。
三、主要思路:
本文的思路是使用Python的requests模块爬取API的返回信息,将返回的信息数据(JSON),通过代码解析的方式存入CSV文件中,再导入ArcGIS中进行可视化处理。
四、分析阶段:
根据提供的交通态势信息API文档,注意到提供了两种获取交通态势信息的方式,一种是通过设定矩形区域(传入左下角以及右上角坐标)的方式,一种是通过设定圆形区域的方式(设定圆心坐标和半径),本文使用的是设定矩形区域的方式。 但是问题来了,平台对用户的API行为进行了限制,要求设定的矩形区域的对角线长度不超过10公里,但这是难不倒程序猿的,可以使用网格的思想来突破这一限制,如下图:
即将爬取区域分成多个网格,每个网格在平台规定的10公里范围之内即可,这样虽然增加了API的调用次数,但不得不说是较为合适的解决方案,本思想同样也适用于POI信息的爬取,在本文中笔者使用了简单的for循环来实现网格爬取,当然读者也可以参考:
百度地图POI数据爬取,突破百度地图API爬取数目“400条“的限制
这篇博文中的LocaDiv类来实现更为复杂化的网格爬取方式。
五、编写代码:
由于本文的爬虫程序比较简单,因此笔者为了方便直接使用Python自带的IDLE进行程序编写,代码如下:
import requests
import pandas as pd
import json
import time
#初始API的URL
url="https://restapi.amap.com/v3/traffic/status/rectangle?key=申请的key&extensions=all&rectangle="
#设定整个网格左下角坐标的经纬度值
baselng=116.927748
baselat=36.62361
#设定每个网格单元的经纬度宽
widthlng=0.05
widthlat=0.04
#用于储存数据
x=[]
#用于标识交通态势线段
num=0
#爬取过程可能会出错中断,因此增加异常处理
try:
#循环每个网格进行数据爬取,在这里构建了3X3网格
for i in range(0,3):
#设定网格单元的左下与右上坐标的纬度值
#在这里对数据进行处理,使之保留6位小数(不保留可能会莫名其妙出错)
startlat=round(baselat+i*widthlat,6)
endlat=round(startlat+widthlat,6)
for j in range(0,3):
#设定网格单元的左下与右上坐标的经度值
startlng=round(baselng+j*widthlng,6)
endlng=round(startlng+widthlng,6)
#设置API的URL并进行输出测试
locStr=str(startlng)+","+str(startlat)+";"+str(endlng)+","+str(endlat)
thisUrl=url+locStr
print(thisUrl)
#爬取数据
data=requests.get(thisUrl)
s=data.json()
a=s["trafficinfo"]["roads"]
#注意,提取数值需要使用XXX.get()的方式来实现,如a[k].get('speed')
#若使用a[k]['speed']来提取,或会导致KeyError错误
for k in range(0,len(a)):
s2=a[k]["polyline"]
s3=s2.split(";")
for l in range(0,len(s3)):
s4=s3[l].split(",")
x.append([a[k].get('name'),a[k].get('status'),a[k].get('speed'),num,float(s4[0]),float(s4[1])])
num=num+1
#若爬取网格较多,可使用time.sleep(秒数)来避免平台的单秒API调用次数的限制
except Exception as e:
pass
#将数据结构化存储至规定目录的CSV文件中
c = pd.DataFrame(x)
c.to_csv('E:/BigRoads.csv',encoding='utf-8-sig')#感谢网友weixin_43475766的提醒
六、CSV数据处理:
在相关目录下找到爬取的CSV文件,用记事本打开,删除第一行的内容(,0,1,2,3,4,5),否则会导致导入ArcGIS时出错。
七、交通态势信息可视化:
1、打开Arcmap,在右侧的catlog(目录)中找到爬取的CSV文件直接拖入左侧的内容列表中,如图:
2、右键点击该CSV数据,选择“显示XY数据”:
3、在弹出的设置框中,进行如下设置:
需要注意的是,本文中爬取的数据的坐标值使用的是GCJ-02坐标系,若要应用至项目中,需要转换为WGS-84坐标系,本文为了省事,且为了与在线底图对比验证,直接当作WGS84坐标来处理。点击两次确定,即可看到CSV文件成功的转换为了点要素文件。
4、接下来的一步十分重要,打开生成要素的属性表可以发现,属性表并没有FID(objectID)字段,若无该字段,该点要素将无法转换为线要素,因此需要将该要素导出为SHP文件,方法是右键单击该要素,选择数据->导出数据,如下图:
然后进行如下设置,注意要导出为shp格式:
5、接下来是将交通态势点转换为线,在toolbox中找到“点集转线”工具(数据管理工具->要素->点集转线),在弹出的设置界面进行如下设置:
注意线字段选择Field5(即代码中的num变量),排序字段选择FID。
6、等待片刻,完整的路网呈现在眼前:
看到了路网是不是一阵狂喜,但是打开属性表,似乎笑不出来了,原来的交通态势属性去哪了!!!
不要着急,接下来一步,将属性完美的找回来。
7、右键路网数据,选择连接和关联->连接,如下图:
在弹出的设置框中进行如下设置:
第二个选项可以是原始的CSV表,也可以是用来转线的点文件(即本文的jinan.shp),点击确定,再打开属性表,属性是不是回来了呢?
8、分级渲染可视化一下,美滋滋~
什么?为什么这么丑?不要在意这些细节...........