Python应用指南:利用高德地图API获取公交可达圈

news2025/1/15 8:31:07

参考文章:城市公交可达圈绘制方法(一) - 知乎 (zhihu.com)

本篇文章我们聚焦于通过公共交通出行方式(包括公交、地铁、公交+地铁的组合)来获取一定时间内可以到达的范围。为了实现这一目标,我们将使用高德地图API中的公交到达圈功能,对城市某一点的公交可达圈进行详细分析。通过这一分析,我们可以更好地理解城市的公共交通网络覆盖范围,为城市规划、交通优化和个人出行提供有力的数据支持。我们将利用高德地图API提供的强大功能,结合具体的起始点和时间参数,获取并可视化从该点出发,在指定时间内可以通过公交和地铁到达的所有区域。

先讲一下方法思路,一共三个步骤;

方法思路

  1. 确认URL位置和数据结构,并根据配置参数构建请求URL
  2. 坐标转换——高德坐标系(GCJ-02) to WGS84
  3. 点集转成csv

老规矩,通过快捷键 Ctrl + Shift + i,找到数据源的位置,然后打开这个url的链接,可以看到数据源是一个个点坐标,我们需要把点坐标提取出来,并把点的高德坐标系(GCJ-02)转为WGS84坐标;

公交到达圈-公交信息查询-示例中心-JS API 1.4 示例 | 高德地图API (amap.com)

参数设置:location(坐标)、key(高德key)、time(出行时间)、strategy(出行方式);

 config = {
        'key': '你的key',   # 高德的API的key
        'location': '118.797539,31.969705',   # 坐标可以自定义
        'time': '30',   # 时间选择范围有(1-45)都可以输入,通常我们使用(15、30、45)
        'strategy': '1'   # 如果strategy==2,strategy_name='公交+地铁';如果strategy==1,strategy_name='地铁';如果strategy==0,strategy_name='公交';
    }

这些参数要提前自定义好,这里以上海虹桥火车站为例121.320011,31.19403(GCJ-02),time参数:45(分钟),strategy:2(地铁+公交,'0': '公交','1': '地铁', '2': '公交+地铁'),key的话在高德地图开放平台上注册一个账号并创建一个应用,获取API密钥即可;

完整代码#运行环境Python 3.11

import requests
import json
import logging
import math
import csv

# 配置日志
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')

#坐标转化函数
x_pi = 3.14159265358979324 * 3000.0 / 180.0
pi = 3.1415926535897932384626  # π
a = 6378245.0  # 长半轴
ee = 0.00669342162296594323  # 偏心率平方

def gcj02_to_wgs84(lng, lat):
    """
    将GCJ02坐标系(火星坐标系)转换为WGS84坐标系
    :param lng: 火星坐标系的经度
    :param lat: 火星坐标系的纬度
    :return: WGS84坐标系的经纬度列表
    """
    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):
    """
    辅助函数,用于计算纬度偏移
    :param lng: 经度
    :param lat: 纬度
    :return: 纬度偏移值
    """
    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):
    """
    辅助函数,用于计算经度偏移
    :param lng: 经度
    :param lat: 纬度
    :return: 经度偏移值
    """
    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: 如果在中国范围内返回False,否则返回True
    """
    return not (lng > 73.66 and lng < 135.05 and lat > 3.86 and lat < 53.55)

def lines_wgs84(coords):
    """
    将一系列GCJ02坐标转换为WGS84坐标
    :param coords: GCJ02坐标列表,每个坐标为 "经度,纬度" 格式的字符串
    :return: WGS84坐标列表
    """
    wgs84_coords = []
    for coord in coords:
        lng, lat = map(float, coord.split(','))
        wgs84_coords.append(gcj02_to_wgs84(lng, lat))
    return wgs84_coords

def build_url(config):
    """
    构建请求URL
    :param config: 配置字典
    :return: 完整的请求URL
    """
    base_url = 'https://lbs.amap.com/AMapService/v3/direction/reachcircle'
    params = {
        'key': config['key'],
        'location': config['location'],
        'time': config['time'],
        's': 'rsv3',
        'extensions': 'all',
        'output': 'json',
        'strategy': config['strategy'],
        'callback': 'jsonp_89634_',
        'platform': 'JS',
        'logversion': '2.0',
        'appname': 'https%3A%2F%2Flbs.amap.com%2Fdemo%2Fjavascript-api%2Fexample%2Fbus-info%2Farrival-range',
        'csid': 'B6FE1E8C-C71D-4EDB-9261-2CBCD8A0C433',
        'sdkversion': '1.4.27'
    }
    query_string = '&'.join([f'{k}={v}' for k, v in params.items()])
    return f"{base_url}?{query_string}"

def main(config):
    # 构建URL
    url = build_url(config)

    # 设置请求头
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36 Edg/129.0.0.0',
        'Referer': 'https://lbs.amap.com/demo/javascript-api/example/bus-info/arrival-range',
        'Cookie': 'AMAPID=d365685e5855236e1224b874d3d5528f; passport_login=MTcyMzA0NzUzLGFtYXBBVGo4T0h1R1IsZW9odmR2bTJhY21iY2FjaXpjNTZkZmlqcGNobXR0Y3ksMTcyNjcxNzM2MyxNbUZtTVdVek5qWmtNRFV6T0dVNFpEUmxZVFZtTWpFNE1EYzFZalUxTXpVPQ%3D%3D; gray_auth=2; isg=BH9_D-UqJLpNOyOjsUs-Ceo0DlMJZNMGzI2-3hFNHS51IJuiGTUrVPIyZnDeY6t-; tfstk=gnDqqA64FKp4UqvQVueaY0RZSQeYd-YBSAa_jcmgcr4m5CUiaVgyDPiMkVkar2cbG-wD_RoE7tMb1jigjzga5mwDDG2ZPc2sG-AOIP4Su5G_h-2ascuV1nHZXOrijVKY5ndSDmeTIeTI7pixDQ6wUVM4muVo2kzgjpNsmxCgIeTBFaITzkyilRzFQ_ouylrcSt0gZ_48ft2go5blZk4uSR0goaquYk7GIS40E3rTrP2gobrmmcXzASxCb8QkRQd8iym0zOXEvoPD4m11BOC3DSaHpz6gVYr4gymmHhnLcuDSUWN5fUwovbg04JJVJoloY-qZBHfa75kYUzueKOE-iqku_Yt9K0w4bW2gaGXi48z8axwHKar-ZmGiHqSNIoHjd5zLahXT18DQtX0VXHnunl0T9ATdHrmivvhQLK7L0bmUUgScWuVmRAhVS1V02uzB43S6dcPx6AvtT1CTZJEzRnZf61F02uzB435O67qL4ytbc'
    }

    # 发送HTTP请求获取数据
    try:
        response = requests.get(url, headers=headers)
        response.raise_for_status()
        logging.info("请求成功")

        # 解析JSONP响应
        data = response.text.strip('jsonp_89634_(').strip(')')
        data = json.loads(data)

        # 打印数据
        logging.info(json.dumps(data, indent=4, ensure_ascii=False))

        # 处理多边形数据
        coordinates = []

        for i, polygon in enumerate(data['polylines']):
            outer_coords = polygon['outer'].split(';')
            outer_points = lines_wgs84(outer_coords)
            for point in outer_points:
                coordinates.append([f"多边形 {i + 1} 外轮廓", point[0], point[1]])
            logging.info(f"多边形 {i + 1} 的外轮廓点 (WGS84): {outer_points}")

            if polygon['inners']:
                for j, inner_coords in enumerate(polygon['inners']):
                    inner_points = lines_wgs84(inner_coords.split(';'))
                    for point in inner_points:
                        coordinates.append([f"多边形 {i + 1} 内轮廓 {j + 1}", point[0], point[1]])
                    logging.info(f"多边形 {i + 1} 的内轮廓点 {j + 1} (WGS84): {inner_points}")

        # 导出CSV文件
        with open('reach_circle.csv', mode='w', newline='', encoding='utf-8-sig') as file:
            writer = csv.writer(file)
            writer.writerow(['多边形名称', 'X坐标', 'Y坐标'])
            writer.writerows(coordinates)

        logging.info("CSV文件已保存为 reach_circle.csv")

    except requests.RequestException as e:
        logging.error(f"请求失败: {e}")
    except json.JSONDecodeError as e:
        logging.error(f"JSON解析失败: {e}")

if __name__ == "__main__":
    # 用户自定义参数
    config = {
        'key': '你的key',   # 高德的API的key
        'location': '121.320011,31.19403',   # 坐标可以自定义
        'time': '45',   # 时间选择范围有(1-45)都可以输入,通常我们使用(15、30、45)
        'strategy': '2'   # 如果strategy==2,strategy_name='公交+地铁';如果strategy==1,strategy_name='地铁';如果strategy==0,strategy_name='公交';
    }
    main(config)

脚本运行结束,就会生成一个名为 reach_circle.csv 的CSV文件,其中包含多边形的名称、X坐标和Y坐标,并且文件编码为UTF-8;

我们把结果添加到GIS里做可视化,先添加xy坐标,即【显示xy数据】,然后在工具里检索【点集转线】,把点集转成线层;

最后在ArcToolbox,【数据管理工具】→【要素】→【要素转面】,注意:线要素中的线必须是闭合的;

这样我们就得到了从虹桥火车站出发,45分钟内地铁+公交的可达范围。由图可知,我们可以清晰地看到虹桥火车站周边的公共交通网络布局以及各个方向上的可达性情况。

  • 向西最远可以到达徐泾新区,这一区域包括了多个住宅区和商业综合体。
  • 向东最远可以到达世纪大道,世纪大道是浦东新区的核心地带,汇集了众多高端商务楼宇和购物中心。
  • 向北可以到达七宝老街,七宝老街坐拥悠久的历史文化和独特的江南水乡风貌,可以满足旅客45分钟直达。
  • 向南可以到达丰庄,丰庄可是上海市普陀区的一个重要节点社区,拥有丰富的居民生活设施和便利的交通条件。

文章仅用于分享个人学习成果与个人存档之用,分享知识,如有侵权,请联系作者进行删除。所有信息均基于作者的个人理解和经验,不代表任何官方立场或权威解读。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2214744.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

在 Android 应用程序中实现与WebSocket 服务器的实时通信

&#x1f604;作者简介&#xff1a; 小曾同学.com,一个致力于测试开发的博主⛽️&#xff0c;主要职责&#xff1a;测试开发、CI/CD 如果文章知识点有错误的地方&#xff0c;还请大家指正&#xff0c;让我们一起学习&#xff0c;一起进步。 &#x1f60a; 座右铭&#xff1a;不…

spring-boot学习(2)

上次学习截止到拦截器 1.构建RESfun服务 PathVariable通过url路径获取url传递过来的信息 2.MyBatisPlus 第三行的mydb要改为自己的数据库名 第四&#xff0c;五行的账号密码改成自己的 MaooerScan告诉项目自己的这个MyBatisPlus是使用在哪里的&#xff0c;包名 实体类的定义…

PL/SQL Developer15和Oracle Instant Client安装配置详细图文教程

一、下载介质 1、Oracle Instant Client Oracle Instant Client Downloads | Oracle 中国 2、PL/SQL DEVELOPER PL/SQL Developer - Allround Automations Free trial - Allround Automations 二、安装介质。 1、安装plsqldev1504x64.msi。 一路默认下一步。 选择输入许可信…

实跑 YOLO V11在 OAK内部运行的效果

哈喽&#xff0c;各位OAK中国的朋友们! 大家好我是张伯生 今天&#xff0c;我想给大家演示一下最新发布的Yolo V11神经网络 下面我将演示的一个程序是&#xff1a;同时在我们的OAK相机上跑Yolo V11和RGB-D&#xff0c;也就是彩色相机和深度图的一个叠加的一个效果 RGB-D和Yo…

java_for循环

基本语法 for 关键字&#xff0c;表示循环控制for 有四要素: (1)循环变量初始化(2)循环条件(3)循环操作(4)循环变量迭代循环操作 , 这里可以有多条语句&#xff0c;也就是我们要循环执行的代码如果 循环操作(语句) 只有一条语句&#xff0c;可以省略 {}, 建议不要省略 流程图 …

电气学习知识点

文章目录 NPN和PNP输出 NPN和PNP输出 NPN和PNP&#xff08;两种不同类型的三极管&#xff09;都是集电极输出。&#xff08;集电极开路输出&#xff09; 下图b:基极、c集电极、e发射极 NPN示意图&#xff08;集电极连接负载 — 正方形&#xff09; NPN的电流流向是从集电极…

Elasticsearch设置 X-Pack认证,设置账号和密码

前言 以下Elasticsearch版本&#xff1a;7.9.3 ES自带的X-Pack密码验证&#xff1a; X-Pack是elasticsearch的一个扩展包&#xff0c;将安全&#xff0c;警告&#xff0c;监视&#xff0c;图形和报告功能捆绑在一个易于安装的软件包中&#xff0c;所以我们想要开启账号密码验证…

Scala入门基础(10.1)高阶函数2

一.reduce 二.reduceLeft-reduceRight 三.flod 四.sorter函数 五.sortWith 一.reduce 作用&#xff1a;reduce是一种集合操作&#xff0c;用于对集合中的元素进行聚合操作&#xff0c;返回一个单一的结果。它通过指定的二元操作(即取两个元素进行操作)对集合中的所有元素进…

力扣刷题-算法基础

hello各位小伙伴们,为了进行算法的学习,小编特意新开一个专题来讲解一些算法题 1.移除元素. - 力扣(LeetCode) 本题大概意思是给定一个数组和一个数val删除与val相同的元素,不要改变剩余元素的顺序,最后返回剩余元素的个数。 我们在这里使用双指针,这里的双指针并不是…

npm 加速,命令行修改国内镜像源【附带国内最新几个镜像】超简约版~

为什么要配置国内镜像源&#xff1f; npm 的官方源服务器在国外&#xff0c;对于国内开发者来说&#xff0c;下载速度可能会比较慢&#xff0c;甚至可能会出现下载失败的情况。而国内的镜像源服务器通常会对官方源的包进行同步&#xff0c;并且在国内部署&#xff0c;这样可以…

使用OneAPI+Ollama+Dify搭建一个兼容OpenAI的API发布及AI应用开发系统(三)Dify的安装及配置

在GitHub中的AI工作流短代码平台中&#xff0c;Dify获星一直名列前茅&#xff0c;目前已达48K星&#xff0c;其工作稳定性也是非常的高&#xff0c;在这里我们介绍一下Dify的安装。 由于Dify的结构非常的复杂&#xff0c;我们这里介绍Docker的方式进行安装&#xff0c;硬件的最…

Oracle+11g+笔记(7)-数据库空间管理

Oracle11g笔记(7)-数据库空间管理 7、数据库空间管理 存储空间是数据库系统中非常重要的资源&#xff0c;无论是数据库中的对象还是数据库中的数据都需要空间进行存储&#xff0c;一旦 数据库空间被全部占用&#xff0c;那么该数据库系统就不能再接受任何对象和数据&#xf…

浙大数据结构:09-排序2 Insert or Merge

这道题我们采用先判断是不是insert如果不是再用merge算一下 机翻 1、条件准备 首先存元素个数n&#xff0c;然后oldnum存原始数组&#xff0c;newnum存新数组 #include <iostream> #include<vector> #include<algorithm> using namespace std; #define e…

SSD | (三)NAND闪存(上)

文章目录 &#x1f4da;闪存基本原理&#x1f407;存储单元及相关操作&#x1f407;闪存类型&#x1f407;闪存组织结构&#x1f407;擦、写、读操作&#x1f407;阈值电压分布图 &#x1f4da;闪存基本原理 &#x1f407;存储单元及相关操作 闪存是一种非易失性存储器&#x…

ArkTS中的几个易错问题

问题1&#xff1a;copyWithin的乱用问题 由于鸿蒙开发者很多可能是安卓转的&#xff0c;在安卓侧尤其是kotlin写手觉得copyOfRange很好用&#xff0c;复制数组的某一段数据就用copyOfRange&#xff0c;而copyWithin其实不是同等作用。 下面是AI对copyWithin的解释&#xff1a…

SpringBoot教程(三十二) | SpringBoot集成Skywalking链路跟踪

SpringBoot教程&#xff08;三十二&#xff09; | SpringBoot集成Skywalking链路跟踪 Skywalking是什么&#xff1f;Skywalking与JDK版本的对应关系Skywalking下载Skywalking 数据存储Skywalking 的启动部署探针方式一&#xff1a;IDEA 部署探针方式二&#xff1a;Java 命令行启…

101 - Lecture 7

回顾冯诺依曼模型&#xff08;von Neumann Model&#xff09;&#xff0c;这是现代计算机体系结构的基础。以下是该模型的关键概念&#xff1a; 1.通用计算机&#xff1a; • 冯诺依曼提出的计算机是通用机器&#xff08;general- purpose&#xff09;&#xff0c;可以通过可…

如何防止架构师PM化?

目录标题 导读引言&#xff1a;什么是架构师PM化架构师PM化的特点亲力操刀的实质性工作越来越少更喜欢拉会催进度越来越难直接回答问题喜欢流程 架构师PM化的危害对项目的危害对组织的危害对架构师个人的危害对研发同学的危害 如何防止架构师PM化组织上要提倡做实事个人上要做点…

MySQL UDF提权原理

文章目录 前言一、MySQL架构二、什么是UDF三、UDF提权原理四、MSF实战参考 前言 看了许多视频和文章&#xff0c;对UDF提权讲得都不是很清楚&#xff0c;遂搜索了一下MySQL的基础知识&#xff0c;总结了一下&#xff0c;供各位初学的师傅参考。 一、MySQL架构 首先&#xff…

Broken pipe异常分析及处理

问题出现&#xff1a;生产上运行的系统业务正常&#xff0c;当在查询数据时&#xff0c;出现后台异常&#xff0c;检查后台日志出现Broken Pipe异常&#xff1b; 如图示&#xff1a; Broken Pipe定义&#xff1a;通常发生在服务器端尝试向已关闭的套接字&#xff08;客户端/端…