从高德地图获取城市公交线路+站点

从高德地图获取城市公交线路+站点_第1张图片

公交线路+站点

在研究城市公共交通问题上,地面的公交网络研究算是很重要的一块,因此获取整个城市的公交线路及其站点的所有数据是非常重要的!但令人高兴的是,有关这些数据的获取其实是很方便快捷的,因为目前的众多网络地图上都包含着这些数据,你要做的只是将所需求的数据提取出来即可。
由于整个城市的公交线路数量众多,同时公交线路分单向双向两个方向。基于此,本文将首先解决如何获取城市部分公交线路(单向的)的矢量数据问题!!!
下面直接给出数据获取的详细python脚本,请开始阅读

STEP01
准备条件:在高德开放平台的官网申请并获取key值。基本流程:新用户注册–>控制台–>应用管理–>我的应用–>创建新应用–>应用名称(随你写),应用类型(你做主)–>接下来为你创建的应用添加key–>key名称(听你的)–>服务平台(Web端(JS API))–>提交。
此时key值已经成功生成!

STEP02
数据获取的逻辑思路:1、从高德地图服务器上获取数据并保存。2、解析并整理出站点数据。3、解析并整理出线路数据。4、将站点和线路数据分别转化成shp文件,坐标为wgs84,最终输出的文件以相对路径存放与python代码存于同一文件夹中。

python具体实现脚本请看下方!!!

#导入库
import requests
import pandas as pd
import numpy as np
import json
import math
import shapefile

#坐标转换,高德转WGS84
x_pi = 3.14159265358979324 * 3000.0 / 180.0
pi = 3.1415926535897932384626  # π
a = 6378245.0  # 长半轴
ee = 0.00669342162296594323  # 偏心率平方

def gcj02_to_wgs84(lng, lat):
    """
    GCJ02(火星坐标系)转GPS84
    :param lng:火星坐标系的经度
    :param lat:火星坐标系纬度
    :return:
    """
    if out_of_china(lng, lat):
        return [lng, lat]
    dlat = _transformlat(lng - 105.0, lat - 35.0)
    dlng = _transformlng(lng - 105.0, lat - 35.0)
    radlat = lat / 180.0 * pi
    magic = math.sin(radlat)
    magic = 1 - ee * magic * magic
    sqrtmagic = math.sqrt(magic)
    dlat = (dlat * 180.0) / ((a * (1 - ee)) / (magic * sqrtmagic) * pi)
    dlng = (dlng * 180.0) / (a / sqrtmagic * math.cos(radlat) * pi)
    mglat = lat + dlat
    mglng = lng + dlng
    return [lng * 2 - mglng, lat * 2 - mglat]

def _transformlat(lng, lat):
    ret = -100.0 + 2.0 * lng + 3.0 * lat + 0.2 * lat * lat + \
          0.1 * lng * lat + 0.2 * math.sqrt(math.fabs(lng))
    ret += (20.0 * math.sin(6.0 * lng * pi) + 20.0 *
            math.sin(2.0 * lng * pi)) * 2.0 / 3.0
    ret += (20.0 * math.sin(lat * pi) + 40.0 *
            math.sin(lat / 3.0 * pi)) * 2.0 / 3.0
    ret += (160.0 * math.sin(lat / 12.0 * pi) + 320 *
            math.sin(lat * pi / 30.0)) * 2.0 / 3.0
    return ret

def _transformlng(lng, lat):
    ret = 300.0 + lng + 2.0 * lat + 0.1 * lng * lng + \
          0.1 * lng * lat + 0.1 * math.sqrt(math.fabs(lng))
    ret += (20.0 * math.sin(6.0 * lng * pi) + 20.0 *
            math.sin(2.0 * lng * pi)) * 2.0 / 3.0
    ret += (20.0 * math.sin(lng * pi) + 40.0 *
            math.sin(lng / 3.0 * pi)) * 2.0 / 3.0
    ret += (150.0 * math.sin(lng / 12.0 * pi) + 300.0 *
            math.sin(lng / 30.0 * pi)) * 2.0 / 3.0
    return ret

def out_of_china(lng, lat):
    """
    判断是否在国内,不在国内不做偏移
    :param lng:
    :param lat:
    :return:
    """
    return not (lng > 73.66 and lng < 135.05 and lat > 3.86 and lat < 53.55)
    
#获取原始数据
def get_single_line(mykey,city_name,line_name):
    '''
    下载单向公交线路数据
    :param city_c: 城市名称
    :param line_c: 线路名称,如11路、12路
    :return: 一条公交线路数据,追加到已存的数据后面
    '''
    url = "https://restapi.amap.com/v3/bus/linename?s=rsv3&extensions=all&key={}&output=json&" \
          "city={}&offset=1&keywords={}&platform=JS".format(mykey,city_name, line_name)
    try:
        print("开始获取{}数据".format(line_name))
        response = requests.get(url).json()
        dt = {}
        if response["buslines"]:
            print("服务器成功返回数据")
            if len(response["buslines"]) == 0:
                print("返回的内容没有数据")
            else:
                for mn in range(len(response["buslines"])):
                    # 提取公交线路名称
                    dt["line_name"] = response["buslines"][mn]["name"]
                    #获取线路沿线的经纬度,以便生成线路
                    dt["polyline"] = response["buslines"][mn]["polyline"]
                    #获取公交线路的最早、最晚运营时间
                    dt["start_time"] = response["buslines"][mn]["start_time"]
                    dt["end_time"] = response["buslines"][mn]["end_time"]
                    #获取公交线路的首末站站点名称
                    dt["start_stop"] = response["buslines"][mn]["start_stop"]
                    dt["end_stop"] = response["buslines"][mn]["end_stop"]
                    #获取公交线路的首末站站点距离
                    dt["distance"] = response["buslines"][mn]["distance"]
                    #获取公交的起始价和全程价
                    dt["basic_price"] = response["buslines"][mn]["basic_price"]
                    dt["total_price"] = response["buslines"][mn]["total_price"]
                    #获取站点的名称和经纬度
                    st_name = []
                    st_coords = []
                    for i in response["buslines"][mn]["busstops"]:
                        station_name = i["name"]
                        station_corrds = i["location"]
                        st_name.append(station_name)
                        st_coords.append(station_corrds)
                    dt["station_name"] = st_name
                    dt["station_coords"] = st_coords
                    #保存数据
                    print("{}数据爬取成功".format(line_name))
                    data = pd.DataFrame([dt])
                    data.to_csv(r"./{}_bus_data.csv".format(city_name), mode="a", header=False, encoding="gbk")
        else:
            print("内容返回失败")
            #记录失败数据
            with open(r"./error.txt",mode="a") as f:
                f.write("{}数据爬取失败".format(line_name))
    except:
        #记录失败数据
        print("{}数据爬取失败".format(line_name))
        with open(r"./error.txt", mode="a") as f:
            f.write("{}数据爬取失败".format(line_name))

#得到站点数据
def get_station():
    data = pd.read_csv(r"./{}_bus_data.csv".format(city_name),encoding="gbk",engine="python",
                     names=["id","line_name","polyline","start_time","end_time","start_stop","end_stop",
                            "distance","basic_price","total_price","station_name","station_coords"])
    df = data[["line_name",'station_coords', 'station_name']]
    #将字符串处理并分割成列表
    df["station_coords"] = df["station_coords"].apply(lambda x: x.replace("[", "").replace("]", "").replace("\'", "").split(", "))
    df["station_name"] = df["station_name"].apply(lambda x: x.replace("[", "").replace("]", "").replace("\'", "").split(", "))
    #将单元格的列表数值进行竖铺
    sta_name = np.hstack(df["station_name"])
    sta_coords = np.hstack(df["station_coords"])
    li_name = np.hstack(df["line_name"].repeat(list(map(len,df["station_name"]))))
    #将线路、站点名称、站点经纬度进行对应匹配
    station_data = pd.DataFrame(np.column_stack((li_name,sta_name,sta_coords)),columns=["line_name","station_name","station_coords"])
    #分别提取经度、纬度
    station_data["lng"] = station_data["station_coords"].apply(lambda x: x.split(",")[0])
    station_data["lat"] = station_data["station_coords"].apply(lambda x: x.split(",")[1])
    # 删除相同的站点
    station_data = station_data.drop_duplicates(["station_name","lng","lat"])
    #重新设置索引,使得索引从0 开始,1为间隔
    station_data = station_data.reset_index(drop=True)
    #转化坐标
    station_data["lng84"] = 0.00
    station_data["lat84"] = 0.00
    for i in range(len(station_data)):
        station_data["lng84"][i] = gcj02_to_wgs84(float(station_data["lng"][i]),float(station_data["lat"][i]))[0]
        station_data["lat84"][i] = gcj02_to_wgs84(float(station_data["lng"][i]),float(station_data["lat"][i]))[1]
    #station_data.to_csv(r"./{}_subway_station_data.csv".format(city_name),encoding="gbk")
    #转化为shp文件
    w = shapefile.Writer(r"./{}/station.shp".format(city_name))
    w.field("line_name","C")
    w.field("station_name","C")
    w.field("lng","C")
    w.field("lat","C")
    w.field("lng84","C")
    w.field("lat84","C")
    for i in range(len(station_data)):
        w.point(station_data["lng84"][i],station_data["lat84"][i])
        w.record(station_data["line_name"][i],station_data["station_name"][i],station_data["lng"][i],
                 station_data["lat"][i],station_data["lng84"][i],station_data["lat84"][i],encode = "gbk")
    w.close()

#获取线路数据
def get_line():
    data = pd.read_csv(r"./{}_bus_data.csv".format(city_name), encoding="gbk", engine="python",
                       names=["id", "line_name", "polyline", "start_time", "end_time", "start_stop", "end_stop",
                              "distance", "basic_price", "total_price", "station_name", "station_coords"])
    data["polyline"] = data["polyline"].apply(lambda x: x.split(";"))
    #转化坐标
    for i in range(len(data["polyline"])):
        list = []
        all_point = data["polyline"][i]
        for j in range(len(all_point)):
            lng = all_point[j].split(",")[0]
            lat = all_point[j].split(",")[1]
            list.append(gcj02_to_wgs84(float(lng),float(lat)))
        data["polyline"][i] = list

    # 转化为shp文件
    w = shapefile.Writer(r"./{}/line.shp".format(city_name))
    w.field("line_name", "C")
    w.field("start_time", "C")
    w.field("end_time","C")
    w.field("start_stop","C")
    w.field("end_stop","C")
    w.field("distance", "C")
    w.field("basic_price", "C")
    w.field("total_price", "C")
    for i in range(len(data)):
        w.line([data["polyline"][i]])
        w.record(data["line_name"][i],data["start_time"][i],data["end_time"][i],data["start_stop"][i],
                 data["end_stop"][i],data["distance"][i],data["basic_price"][i],data["total_price"][i], encode="gbk")
    w.close()

if __name__ == "__main__":
    #将下面的key替换为自己申请的key
    key = "ac21976ec"
    #将城市名称改为自己需要获取的城市的名称,如北京市,只要填写北京,如果填写北京市可能会报错
    city_name = "北京"
    #将线路名称改为你需要的线路名称
    all_line_name = ['10路','11路',"12路","13路","14路","15路","16路","17路","18路","19路","102路",
                     "103路","108路","105路","106路","107路"]
    for line_name in all_line_name:
        get_single_line(key,city_name,line_name)
    get_station()
    get_line()

通过运行以上代码,你所需要的某个城市的某条公交线路及站点的shp数据都可以迅速实现手到数来!

从高德地图获取城市公交线路+站点_第2张图片

你可能感兴趣的:(交通矢量数据获取,python,数据分析,大数据)