一文教会你如何基于高德地图获取城市公交网络数据(包含经纬度) | 您所在的位置:网站首页 › 地铁站系统程序语言 › 一文教会你如何基于高德地图获取城市公交网络数据(包含经纬度) |
之前写过1篇如何基于8684公交查询网站获取城市公交网络数据的文章,但获取到的公交网络数据里是不包含经纬度信息的。 近日,有小伙伴咨询我,怎样把公交线路和各站点的经纬度信息也同步获取到,从而进行一些可视化展示。 周末闲来无事,就基于高德地图简单研究了一下,并把实现过程分享出来。 1 获取公交线路名称集合想要获取整个城市的公交线路数据,第一步是先拿到城市公交线路的名称集合,然后再基于线路名去请求各个线路的详细信息。 这一过程可以基于8684公交查询网站来实现,具体过程可参见我之前的博文。 代码如下: def get_busline_names(city_name): request_url = "https://%s.8684.cn" %(city_name) init_href = "/list1" start_html = requests.get(request_url + init_href) soup = BeautifulSoup(start_html.text, 'lxml') #以lxml的方式解析html文档 pre_list = soup.find('div', class_='tooltip-body cc-content-tooltip').find('div', class_='tooltip-inner').find_all('a') busline_names = list() for pre in pre_list: # 拼接出pre前缀公交线路的请求url url = request_url + pre['href'] pre_html = requests.get(url) pre_soup = BeautifulSoup(pre_html.text, 'lxml') busline_names_a = pre_soup.find('div', class_='list clearfix').find_all('a') for busline_name_a in busline_names_a: busline_names.append(busline_name_a.get_text()) return busline_names 2 获取各个公交线路详情8684公交查询网站是不包含公交网络的经纬度数据的,要获取经纬度数据,只能借助于地图应用来获取,比如高德地图。 获取高德地图数据,基本有3种途径: 直接调用高德地图开放出来的Web API简单易用,可以快速上手。但该途径需要注册高德地图账号,并申请AK,且有日调用次数的限制。 同时,可能某些数据未提供相应接口。 高德地图的JS APIJS API Demo示例里提供了很多数据接口,可以通过浏览器开发者工具抓包分析出后台的数据http服务接口,并得到请求的构建方法,然后模拟发送请求。 直接分析高德地图的检索请求,直接调用相关服务接口该种方法需要在高德地图上构建好检索请求,通过浏览器开发者工具抓包分析出后台的数据http服务接口,并得到请求的构建方法,然后模拟发送请求。 首先看一下高德地图的Web API页面: 发现高德地图并没有提供公交线路检索的Web API。 有个POI检索倒是可以试试,但尝试了一下之后,发现也不能满足我们的需求,比如关键字给"1路",其返回的均是1路公交线上各个站点的信息,并没有线路信息。可以看出,POI Web API关注的更多是点信息。 接着尝试第2种途径: 可以看到,JS API里提供了公交线路检索的接口。 下面就是抓包分析请求了,老规矩,打开浏览器的开发者工具: 很容易就找到了目标接口,同时观察接口返回数据,其中的polyline字段就是线路的经纬度集合,而busstops字段是该线路各个站点的信息,其中也包含了站点的经纬度信息。 接着看一下该接口的请求信息(参数、headers等): 一般来讲,参数和headers里面的大部分参数均是可选参数,我们可以尝试去掉某些参数,然后观察请求是否仍然可以正常返回。 逐步分析出该请求的headers必须包含下述两项: headers = { 'Host': 'restapi.amap.com', 'Referer': 'https://lbs.amap.com/' }请求参数如下: params = { "s": "rsv3", "key": "******", "city": "******", "pageIndex": "1", "offset": "20", "extensions": "all", "keywords": "1路" }city参数代表城市名称或者citycode,offset代表每次请求单页包含的元素数,extensions配置必须为all的时候才会有经纬度数据,keywords配置传入公交线路名称。 不应该传入1条公交线路名称,只返回1个结果吗,为啥还要配置offset呢? 首先是因为,同一个公交线路名称一般会有正、反2个方向,同时,高德地图在检索的时候,采用的是模糊搜索策略,比如你搜索"1路",“11路”、"121路"等可能也会在返回集合里,其返回的时候会根据匹配得分进行排序,一般取前2个元素(正好对应线路的2个方向)。 分析完毕,下面代码实现一下: def get_busline_info_amap(busline_names, citycode, key, col_sink, time_delay): request_url = "https://restapi.amap.com/v3/bus/linename" params = { "s": "rsv3", "key": key, "city": citycode, "pageIndex": "1", "offset": "20", "extensions": "all", "keywords": "1路" } headers = { 'Host': 'restapi.amap.com', 'Referer': 'https://lbs.amap.com/', } # 线路的set集合,保证线路无重复 buslines_loaded = set() count = 0 for line_name in busline_names: params["keywords"] = line_name res = requests.get(url=request_url, headers=headers, params=params).json() if res["status"] == "1": for busline in res["buslines"]: busline_name = busline["name"] # 若该线路未请求过,则创建请求 if busline_name not in buslines_loaded: buslines_loaded.add(busline_name) col_sink.insert_one(busline) count += 1 print("第%d条公交线路%s采集完成!" % (count, busline_name)) # 休眠time_delay秒,防止对高德服务器太高压力 time.sleep(time_delay) # 主函数 if __name__ == '__main__': key = "******" # 接口请求之间的间隔 time_delay = 0.01 city_name = "北京市" city_py = "beijing" db_name = 'web_map' col_name = 'buslines_' + city_py # MongoDB数据库所在的服务器 host = '******' port = 27017 # 获取mongodb的表句柄 col = mongo_util.get_col(db_name, col_name, host, port) busline_names = get_busline_names(city_py) # 获取北京市公交网络数据 get_busline_info_amap(busline_names, city_name, key, col, time_delay)点击运行,数据哗啦啦入库,任务完成! 第3种途径的实现方式跟第2种步骤基本一致,区别就是请求的构建方式略有不同,此处不再赘述,读者可自行实践。 需要注意的是: 高德地图返回的经纬度是火星坐标系,在进行可视化展示时,若GIS瓦片地图是WGS-84或者百度坐标系时,需要将坐标转换到对应坐标系,否则会出现线路与底图无法对齐的问题。 本文到此结束,谢谢阅读! |
CopyRight 2018-2019 实验室设备网 版权所有 |