通过百度API获取城市公交线路坐标点及站点信息

话不多说,先挂最后的数据结果,如果这是你想要的,我们再接着看:

公交线路坐标数据&公交站点坐标数据

   

正文开始:

前期数据准备:获取城市所有公交线路名称

  使用python爬取,结果如下,代码参考:https://www.cnblogs.com/Qiuzhiyu/p/12183140.html

需要准备的js包:

<!--用于坐标系转换的js包  详见github:https://github.com/hujiulong/gcoord  --> (非必须)
<script src="https://unpkg.com/gcoord/dist/gcoord.js"></script>
<!-- jquery -->
<script src=‘jquery-1.8.3.js‘></script><!-- 百度地图API --><script type="text/javascript" src="http://api.map.baidu.com/api?v=1.2"></script>
<!-- js-xlsx包  使用以及获取方法见:https://www.cnblogs.com/liuxianan/p/js-excel.html --> (非必须,如果不需要导出数据到本地)<script src =‘xlsx.full.min.js‘></script>
<script src =‘xlsx.core.min.js‘></script>
<script>

对爬取的数据进行处理:

 /*将爬取的广州公交信息进行转换*/
    var line_data_list = []
    var line_name_list = []   //获取公交线路名称

    $.ajax(
        {
            url:encodeURI(‘guangzhou.txt‘), //提前爬取的数据
            async: false,
            success: function (guangzhou) {
                row_split =  guangzhou.split(‘\n‘)
                for(var i in row_split){
                    line_data_list.push(JSON.parse(row_split[i]))
                    var len =  JSON.parse(row_split[i]).线路名称[0].length
                    line_data_list[i].线路名称 = JSON.parse(row_split[i]).线路名称[0].substring(2,len-5) //’广州10路公交车路线‘->’10路‘
                }

                for(var i in line_data_list){
                    line_name_list.push(line_data_list[i].线路名称)
                }
            }

        }
    )

处理结果:

line_name_list =["10路", "11路", "12路", "14路", "15路", "19路", "101路", "102路",……]

接下来非常简单,只需要进行公交列表查询,这一步执行会激发后续一系列操作,获取我们想要的数据。

   // 数据导入数组开始
    //slice
    for (var i in line_name_list) {
        busline.getBusList(line_name_list[i]);
        console.log(i)
    }
    console.log("done")

但要搞懂发生了什么,还需要理解接下来的其他部分:

  首先,实例化百度地图,用于页面上的单个线路的展示,当然如果不想展示的话,这一块可以省略:

   /*获取百度地图实例*/
    var map = new BMap.Map("container");
    map.centerAndZoom(new BMap.Point(113.315224, 23.181452), 12); //广州市

  其次,创建百度地图公交信息获取类:

  在这一部分,我们设置了公交列表查询后的回调函数,公交列表查询后的回调函数中又进行了公交线路的查询,而公交线路的回调函数中进行了对公交线路数据的组织,这一系列操作最终使我们得到存储了公交线路信息的对象数组。

    // 公交信息获取类
    var busline = new BMap.BusLineSearch("广州",{
        // 展示获取的公交线路,自动生成面板到id=results的element上,不必须使用
        renderOptions:{map:map,panel:"results"},
        // 设置公交列表查询后的回调函数,注意与公交线路查询区分:     //公交列表存储多个具体的公交对象,公交对象可理解为公交线路。
        onGetBusListComplete: function(result){
            if(result) {
                          /*获取查询出的公交列表中的对象 0代表上行 1代表下行,实际上还可能存在getBusListItem(2)、getBusListItem(3)等等,
                代表的是模糊查询的结果,例如查询 10路 时,getBusListItem(0)、getBusListItem(1)返回的是10路的上下行的公交线路,
                而getBusListItem(2)、getBusListItem(3)返回的是b10路,具体可参考代码块后的贴图*/
                          let up_Line = result.getBusListItem(0);  //获取查询出的公交列表中的第一个对象,即上行线路
                let down_Line = result.getBusListItem(1); //获取查询出的公交列表中的第一个对象,即下行线路

                if(typeof up_Line === "object"){  //判断查询结果是否存在
                    busline.getBusLine(up_Line);  //执行公交线路查询
                }else{
                    console.log("查无此公交:"+result.keyword) //在控制台输出无法查询的线路名称,result.keyword 即在查询时输入的线路名
                    }
                if(typeof down_Line === "object"){
                    busline.getBusLine(down_Line);
                }else{
                    console.log("此公交无下行或不存在:"+result.keyword) //部分公交线路不存在下行线路,输出观察
                }
            }
        },
        //设置公交线路查询后的回调函数,即执行 busline.getBusLine(up_Line) 后执行的函数
        onGetBusLineComplete : function (ret) {
            let line_name = ret.name;
            let line_point = ret.getPath();  //获取公交路线坐标
            let i = ret.getNumBusStations();
            let sta_info = [];
            for(j=0;j <= i;j++){
                sta_info.push([ret.getBusStation(j)]);
            }
            get_bus_line_data(line_name,line_point,sta_info); //对数据进行组织
        }
    });

路线与公交线路列表展示:

up_line数据结构示例,即公交列表的第一个对象:

线路查询后的回调函数的参数数据结构:

上一代码块最后一行代码的函数,会对线路查询后的回调函数的参数(即上图公交线路信息)存入目标数组:

    function get_bus_line_data(line_name,line_point,sta_info) {

        var sta_info_,sta_name,sta_position;
        //更改数据结构  [{}] --> {}  && 去除最后一个空数组
        sta_info_ = sta_info.slice(0,sta_info.length - 1).map(function (re) {
            return re[0]
        });
        //获取每一站点名称
        sta_name = sta_info_.map(function (re) {
            return re.name.toString()
        });
        // 获取站点坐标
        sta_position = sta_info_.map(function (re) {
            return fromBd09ToWgs84([re.position.lng,re.position.lat])
            // return [re.position.lng,re.position.lat]  若不需要转换坐标系,使用此行代码
        });

        line_data_ass.push(
            {
                name: line_name,
                line_point: line_point.map(function (re) {
                    return fromBd09ToWgs84([re.lng, re.lat])
                    // return fromBd09ToWgs84([re.lng, re.lat]) 若不需要转换坐标系,使用此行代码
                }),
                sta_name : sta_name,
                sta_point : sta_position,
            });
        console.log(line_name);  //在控制台输出成功获取的公交线路信息的名称
    }

输出的line_data_ass格式形式如图:

  这是一个对象数组,每个对象存储了一条路线的所有信息,包括线路坐标点,站点名称,站点坐标,已经包含了我们需要的所有信息。可以看到,上下行线路在名称上是有区别的。

如果只需要这一对象数组,上述代码足矣,完整代码整理如下:

<!DOCTYPE html>

<html>
<head>
    <title>获取公交信息</title>
</head>
<body>

<p><img src="http://map.baidu.com/img/logo-map.gif" /><span style="display:inline-block;width:200px;">&nbsp;</span><input type="text" value="331" id="busId" />路公交&nbsp;<input type="button" value="查询" onclick="busSearch();" /></p>

<div style="float:left;width:600px;height:500px;border:1px solid gray" id="container"></div>

<div id="results" style="float:left;width:300px;height:500px;font-size:13px;"></div>

<!--获取坐标系转换js包    详见github:https://github.com/hujiulong/gcoord  -->
<script src="https://unpkg.com/gcoord/dist/gcoord.js"></script>
<!--本地加载jquery-->
<script src=‘jquery-1.8.3.js‘></script>
<script type="text/javascript" src="http://api.map.baidu.com/api?v=1.2"></script>
<!--本地加载js-xlsx包  使用以及获取方法见:https://www.cnblogs.com/liuxianan/p/js-excel.html-->
<script src =‘xlsx.full.min.js‘></script>
<script src =‘xlsx.core.min.js‘></script>
<script>

    /*将爬取的广州公交信息进行转换*/
    var line_data_list = []
    var line_name_list = []   //获取公交线路名称

    $.ajax(
        {
            url:encodeURI(‘guangzhou.txt‘),
            async: false,
            success: function (guangzhou) {
                row_split =  guangzhou.split(‘\n‘)
                for(var i in row_split){
                    line_data_list.push(JSON.parse(row_split[i]))
                    var len =  JSON.parse(row_split[i]).线路名称[0].length
                    line_data_list[i].线路名称 = JSON.parse(row_split[i]).线路名称[0].substring(2,len-5)
                    //’广州10路公交车路线‘->’10路‘
                }

                for(var i in line_data_list){
                    line_name_list.push(line_data_list[i].线路名称)
                }
            }

        }
    )

    /*获取百度地图实例*/
    var map = new BMap.Map("container");
    map.centerAndZoom(new BMap.Point(113.315224, 23.181452), 12); //广州市

    var line_data_ass = []  //存储最终数据的集合

    function get_bus_line_data(line_name,line_point,sta_info) {

        var sta_info_,sta_name,sta_position;
        //更改数据结构  [{}] --> {}  && 去除最后一个空数组
        sta_info_ = sta_info.slice(0,sta_info.length - 1).map(function (re) {
            return re[0]
        });
        //获取每一站点名称
        sta_name = sta_info_.map(function (re) {
            return re.name.toString()
        });
        // 获取站点坐标
        sta_position = sta_info_.map(function (re) {
            return fromBd09ToWgs84([re.position.lng,re.position.lat])
            // return [re.position.lng,re.position.lat]  若不需要转换坐标系,使用此行代码
        });

        line_data_ass.push(
            {
                name: line_name,
                line_point: line_point.map(function (re) {
                    return fromBd09ToWgs84([re.lng, re.lat])
                    // return fromBd09ToWgs84([re.lng, re.lat]) 若不需要转换坐标系,使用此行代码
                }),
                sta_name : sta_name,
                sta_point : sta_position,
            });
        console.log(line_name);  //在控制台输出成功获取的公交线路信息的名称
    }

    // 公交信息获取类
    var busline = new BMap.BusLineSearch("广州",{
        // 展示获取的公交线路,自动生成面板到id=results的element上,不必须使用
        renderOptions:{map:map,panel:"results"},
        // 设置公交列表查询后的回调函数,注意与公交线路查询区分,公交列表存储多个具体的公交对象,公交对象可理解为公交线路。
        onGetBusListComplete: function(result){
            if(result) {
                /*获取查询出的公交列表中的对象 0代表上行 1代表下行,
                实际上还可能存在getBusListItem(2)、getBusListItem(3)等等,代表的是模糊查询的结果,
                例如查询 10路时,getBusListItem(0)、(1)返回的是10路的上下行的公交线路,
                而(2)(3)返回的是b10路,具体可参考代码块后的贴图*/

                //获取查询出的公交列表中的第一个对象,即下行线路
                let up_Line = result.getBusListItem(0);
                //获取查询出的公交列表中的第一个对象,即下行线路
                let down_Line = result.getBusListItem(1);
                if(typeof up_Line === "object"){  //判断查询结果是否存在
                    busline.getBusLine(up_Line);  //执行公交线路查询
                }else{
                    //在控制台输出无法查询的线路名称,result.keyword 即在查询时输入的线路名
                    console.log("查无此公交:"+result.keyword)
                }
                if(typeof down_Line === "object"){
                    busline.getBusLine(down_Line);
                }else{
                    //部分公交线路不存在下行线路,输出观察
                    console.log("此公交无下行或不存在:"+result.keyword)
                }
            }
        },
        //设置公交线路查询后的回调函数,即执行 busline.getBusLine(up_Line) 后执行的函数
        onGetBusLineComplete : function (ret) {
            let line_name = ret.name;
            let line_point = ret.getPath();  //获取公交路线坐标
            let i = ret.getNumBusStations();
            let sta_info = [];
            for(j=0;j <= i;j++){
                sta_info.push([ret.getBusStation(j)]);
            }
            get_bus_line_data(line_name,line_point,sta_info); //对数据进行组织
        }
    });

    /*------------------执行层------------------------------------*/

    // 数据导入数组开始
    //slice
    for (var i in line_name_list.slice(0,5)){
        busline.getBusList(line_name_list[i]);
        console.log(i)
    }
    console.log("done")

    /*-------------------功能函数---------------------------------*/

    /*页面操作调用的函数*/
    function busSearch(){
        var busName = document.getElementById("busId").value;
        busline.getBusList(busName);
    }

    /*坐标转换函数*/
    function fromBd09ToWgs84(arr) {
        var result = gcoord.transform(
            arr,    // 经纬度坐标
            gcoord.BD09,                 // 当前坐标系
            gcoord.WGS84                   // 目标坐标系
        );
        return result;
    }

</script>
</body>
</html>

如何导出?

  很多情况下,如果只是把数据存储到JavaScript的一个数组中,是远远不够的。接下来将会提供将这些数据导出到本地excel的方式,最终获取在开头展示的数据文件。

  接下来的步骤会比较恶心了,因为通过百度API获取公交数据需要一定的时间,所以如果在页面加载过程中就认为已获取了所有所需的数据,直接进行导出或者解析的话,程序会报错。因为在页面执行到提取数据的代码时,往往我们所需的数据还没有完全传送过来,特别是在一个城市有数千条公交线路的时候。

  对于这一问题,解决方案是:在数据完全获取后,即都已存入line_data_ass之后,再F12调出控制台执行导出数据的JavaScript代码。

在控制台执行代码之前,还需要下列准备:

    /*
    ①为了配合js-xlsx包导出数据,对数据进行进一步的组织。
    ②准备必要的导出函数。
    */

    // 数据组织
    data_line_point=[[‘line_id‘,‘line_name‘,‘lng‘,‘lat‘,‘p_id‘]];
    data_station_point = [‘line_id‘,‘line_name‘,‘sta_name‘,‘lng‘,‘lat‘,‘sta_id‘];
    function createData(){

        for(var i in line_data_ass){
            for(var j in line_data_ass[i].line_point){
                data_line_point.push([
                    i,
                    line_data_ass[i].name,
                    line_data_ass[i].line_point[j][0],
                    line_data_ass[i].line_point[j][1],
                    j
                    // , line_data_ass[i].dir
                ])}

            for(var j in line_data_ass[i].sta_point){
                data_station_point.push([
                    i,
                    line_data_ass[i].name,
                    line_data_ass[i].sta_name[j],
                    line_data_ass[i].sta_point[j][0],
                    line_data_ass[i].sta_point[j][1],
                    j
                    // , line_data_ass[i].dir
                ]);
            }
        }
    }

    /*基于excel_js的函数*/
    //代码来源:https://www.cnblogs.com/liuxianan/p/js-excel.html

        function openDownloadDialog(url, saveName)
    {
        if(typeof url == ‘object‘ && url instanceof Blob)
        {
            url = URL.createObjectURL(url); // 创建blob地址
        }
        var aLink = document.createElement(‘a‘);
        aLink.href = url;
        aLink.download = saveName || ‘‘; // HTML5新增的属性,指定保存文件名,可以不要后缀,注意,file:///模式下不会生效
        var event;
        if(window.MouseEvent) event = new MouseEvent(‘click‘);
        else
        {
            event = document.createEvent(‘MouseEvents‘);
            event.initMouseEvent(‘click‘, true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
        }
        aLink.dispatchEvent(event);
    }

    function sheet2blob(sheet, sheetName) {
        sheetName = sheetName || ‘sheet1‘;
        var workbook = {
            SheetNames: [sheetName],
            Sheets: {}
        };
        workbook.Sheets[sheetName] = sheet;
        // 生成excel的配置项
        var wopts = {
            bookType: ‘xlsx‘, // 要生成的文件类型
            bookSST: false, // 是否生成Shared String Table,官方解释是,如果开启生成速度会下降,但在低版本IOS设备上有更好的兼容性
            type: ‘binary‘
        };
        var wbout = XLSX.write(workbook, wopts);
        var blob = new Blob([s2ab(wbout)], {type:"application/octet-stream"});
        // 字符串转ArrayBuffer
        function s2ab(s) {
            var buf = new ArrayBuffer(s.length);
            var view = new Uint8Array(buf);
            for (var i=0; i!=s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF;
            return buf;
        }
        return blob;
    }

等所有数据载入到line_data_ass中后,在控制台执行以下代码:

   //执行数据组织函数
    createData();
    //导出excel
    var sheet = XLSX.utils.aoa_to_sheet(data_line_point);
    var sheet2 = XLSX.utils.aoa_to_sheet(data_station_point);
    openDownloadDialog(sheet2blob(sheet), ‘导出.xlsx‘);
    openDownloadDialog(sheet2blob(sheet2), ‘导出1.xlsx‘);

  执行完后,不出意外数据就可以成功导出了。

不得不提的话:

如果你按着步骤运行这一程序,同时想要提取的公交线路又很多的时候,可能会出现以下几个问题:

1.针对以下问题,可能的原因是:可以通过百度地图API获取到相应的busLine对象,但却没有相应的数据,例如查询广州的"从化19路密石班车",就会出现这样的情况。

2.单独查找时存在的公交线路,在程序运行过程中却报出:"查无此公交:XXX"。这一问题目前还没有很好的解决方案,不知道是哪里出了BUG,一个解决思路是:一次性请求较少量的公交线路数据。这样会比较少出错。

3.查找的公交线路不存在,但百度地图的模糊查找会找出名称相识的路线,例如,输入”化16路“,得到的是”16路“。这一问题尝试过通过字符串的indexOf方法判断,代码如下。但这又会导致输入”12A路”时,“12a路”的数据无法获取。不过好像百度地图公交线路的名称中英文字符多是小写,所以把输入中的英文统一改为小写或许可以解决这个问题。有点麻烦,而且不一定有用,另外这一错误最终导致的后果只是导出的数据中多了一条重复线路,无伤大雅,后期也不难处理,所以就算了。

if(typeof up_Line === "object" && up_Line.name.indexOf(result.keyword) !== -1){...}z

参考资料 :

百度js3.0 API文档:http://lbsyun.baidu.com/cms/jsapi/reference/jsapi_reference_3_0.html

小茗同学(如何使用JavaScript实现纯前端读取和导出excel文件):https://www.cnblogs.com/liuxianan/p/js-excel.html

求知鱼(爬取某城市公交钱路--xpath过滤):https://www.cnblogs.com/Qiuzhiyu/p/12183140.html

酸奶小妹(【百度地图API】如何制作公交线路的搜索?如331路):https://www.cnblogs.com/milkmap/archive/2011/09/16/2178553.html

前端小白一个,代码写得巨辣鸡。如果能帮到你很高兴,各位有兴趣的老哥请多多批评指正,欢迎讨论!!!!

原文地址:https://www.cnblogs.com/console-chan/p/12399020.html

时间: 2024-10-16 05:31:41

通过百度API获取城市公交线路坐标点及站点信息的相关文章

【转】百度API获取城市名地名(附源码)

在做一个软件时,用到了定位功能.网上有很多关于google 的GPS定位,但网上关于google定位都没有用, 搜索下原因:(这里建议大家在中国就尽量不使用系统自带的定位) 因为Google的服务器不在中国(就算能网上关于定位的代码能用,那也非常的慢,除非你的应用是在国外使用)    由于网络等原因所以定位一般会失败 于是转向使用百度api来定位. 所用到的百度API参考地址. 取得位置的百度官方sdk参考 Android定位SDK 由坐标获取地址方法参考 Geocoding API 的 7.逆

百度api获取天气

<?php$city="武汉";$content = file_get_contents("http://api.map.baidu.com/telematics/v3/weather?location=$city&output=json&ak=5slgyqGDENN7Sy7pw29IUvrZ");print_r(json_decode($content)); ?> 百度api获取天气,布布扣,bubuko.com

百度API获取位置范围内的周边服务

百度地图API是一套为开发者免费提供的基于百度地图的应用程序接口,包括JavaScript.iOS.Andriod.静态地图.Web服务等多种版本,提供基本地图.位置搜索.周边搜索.... [html] view plain copy <script type="text/javascript" src="http://api.map.baidu.com/api?v=2.0&ak=(百度API key,可免费申请)"></script>

百度地图获取数据库点的坐标,并定时刷新到页面上

后台代码 先创建marker点的实体类(并利用Spring注解功能实现自动自动建表) 1 package com.sdtg.ditu.bean; 2 3 import javax.persistence.Column; 4 import javax.persistence.Entity; 5 import javax.persistence.GeneratedValue; 6 import javax.persistence.Id; 7 import javax.persistence.Tabl

爬虫——python——百度地图经纬度查询——经纬度查看地点地名——利用百度API获取地名经纬度——爬取所有的中国地址

import requests address = '40.8587960,86.866991' url = 'http://api.map.baidu.com/geocoder?output=json&key=f247cdb592eb43ebac6ccd27f796e2d2&location=' + str(address) response = requests.get(url) answer = response.json() print('得到反解数据', answer) 使用py

公交线路免费api接口代码

描述:本接口主要是根据城市名称 +  线路名称 模糊查找城市公交线路信息. 开源api接口:http://openapi.aibang.com/bus/lines?app_key=f41c8afccc586de03a99c86097e98ccb&city="+cityName+"&q="+line 其中cityName = URLEncoder.encode(cityName,"utf-8") line = URLEncoder.encod

百度地图公交线路查询,并绘制到地图上并获取所有路径经纬度点(可供echarts 路径图使用)

github地址 https://github.com/a1115040996/MyHTML/tree/gh-pages/BDMap 源代码 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.o

DELPHI调用百度定位API(根据IP获取城市及GPS信息等)

缘由:因智能助理在用户说出“天气如何”时,需要自动获取城市,所以这里需要根据用户IP自动获取城市,所以有了这篇文章 QQ508882988 //根据百度API,根据来访IP自动获取出该IP所在的位置及更多信息,参数IP为空时,会使用当前访问者的IP地址作为定位参数 //sServerAK为用户密钥 string 必选,在lbs云官网注册的access key,作为访问的依据,定期从http://lbsyun.baidu.com/apiconsole/key获取 //参考http://lbsyun

IOS中使用百度地图定位后获取城市坐标,城市名称,城市编号信息

IOS中使用百度地图定位后获取城市坐标,城市名称,城市编号信息 /**当获取到定位的坐标后,回调函数*/ - (void)didUpdateBMKUserLocation:(BMKUserLocation *)userLocation{ BMKCoordinateRegion region; region.center.latitude  = userLocation.location.coordinate.latitude; region.center.longitude = userLoca