Python 高德地图 API v3 公交数据爬取实战:青岛 275 条线路站点与轨迹坐标获取
Python 高德地图 API v3 公交数据爬取实战:青岛 275 条线路站点与轨迹坐标获取
公共交通数据是城市规划和智慧交通建设的重要基础。通过获取公交线路的站点信息和轨迹坐标,我们可以进行线路优化、换乘分析、可视化展示等多种应用。本文将详细介绍如何使用 Python 和高德地图 Web 服务 API v3 版本来爬取青岛市 275 条公交线路的完整数据。
1. 高德地图开发者 Key 申请与配置
要使用高德地图的 Web 服务 API,首先需要申请开发者 Key。以下是详细步骤:
- 访问 高德开放平台官网 并注册开发者账号
- 进入"控制台"→"应用管理"→"创建新应用"
- 为应用命名(如"青岛公交数据分析"),选择应用类型为"Web服务"
- 在创建的应用中添加 Key,服务选择"Web服务"
获取到 Key 后,我们可以将其存储在配置文件中,或者直接作为变量使用:
# 配置高德API Key
AMAP_KEY = "你的高德API Key"
CITY = "青岛" # 目标城市
提示:高德地图的免费配额对于个人开发者和小规模应用通常足够,但如果需要大规模调用,建议关注配额限制或考虑购买企业套餐。
2. 公交线路基础信息获取
高德地图提供了 /v3/bus/linename 接口来根据线路名称查询公交信息。我们将构建一个函数来获取单条线路的详细信息:
import requests
import json
import time
import pandas as pd
def get_bus_line_info(line_name, city=CITY, key=AMAP_KEY):
"""
获取单条公交线路的详细信息
:param line_name: 公交线路名称,如"321路"
:param city: 城市名称
:param key: 高德API Key
:return: 包含线路信息的字典
"""
url = f"https://restapi.amap.com/v3/bus/linename?key={key}&city={city}&output=json&offset=1&keywords={line_name}&extensions=all"
try:
response = requests.get(url)
data = json.loads(response.text)
if data["status"] != "1" or not data.get("buslines"):
print(f"未找到线路 {line_name} 的信息")
return None
line_info = data["buslines"][0]
# 提取关键信息
result = {
"line_id": line_info["id"],
"line_name": line_info["name"],
"start_stop": line_info["start_stop"],
"end_stop": line_info["end_stop"],
"company": line_info.get("company", ""),
"distance": float(line_info["distance"]),
"start_time": line_info["start_time"],
"end_time": line_info["end_time"],
"total_price": float(line_info["total_price"]),
"via_stops": [stop["name"] for stop in line_info["busstops"]],
"stop_locations": [stop["location"] for stop in line_info["busstops"]],
"stop_sequence": [stop["sequence"] for stop in line_info["busstops"]],
"polyline": line_info["polyline"] # 线路轨迹坐标
}
return result
except Exception as e:
print(f"获取线路 {line_name} 信息时出错: {str(e)}")
return None
3. 批量获取青岛公交线路数据
青岛市的公交线路名称可以从多种渠道获取,这里我们提供一个青岛公交线路名称的示例列表:
# 青岛公交线路示例列表(实际应用中可能需要从其他渠道获取完整列表)
qingdao_bus_lines = [
"1路", "2路", "3路", "4路", "5路", "6路", "7路", "8路", "9路", "10路",
"11路", "12路", "15路", "16路", "18路", "19路", "20路", "21路", "22路",
"23路", "24路", "25路", "26路", "28路", "29路", "30路", "31路", "32路",
"33路", "36路", "101路", "102路", "103路", "104路", "105路", "106路",
"109路", "110路", "111路", "112路", "113路", "114路", "115路", "116路",
"117路", "118路", "119路", "120路", "121路", "122路", "123路", "125路",
"128路", "129路", "130路", "131路", "202路", "205路", "206路", "207路",
"208路", "209路", "210路", "211路", "212路", "213路", "214路", "215路",
"216路", "217路", "218路", "219路", "220路", "221路", "222路", "223路",
"224路", "225路", "226路", "227路", "228路", "229路", "230路", "231路",
"232路", "233路", "301路", "302路", "303路", "304路", "305路", "306路",
"307路", "308路", "309路", "310路", "311路", "312路", "313路", "314路",
"316路", "317路", "318路", "319路", "320路", "321路", "322路", "323路",
"324路", "325路", "326路", "327路", "328路", "329路", "330路", "331路",
"332路", "333路", "334路", "335路", "336路", "337路", "338路", "339路",
"340路", "341路", "342路", "343路", "361路", "362路", "363路", "364路",
"365路", "366路", "367路", "368路", "369路", "370路", "371路", "372路",
"373路", "374路", "375路", "376路", "377路", "378路", "379路", "380路",
"381路", "382路", "383路", "384路", "385路", "386路", "387路", "388路",
"389路", "390路", "501路", "502路", "503路", "504路", "505路", "506路",
"507路", "508路", "509路", "510路", "511路", "512路", "513路", "514路",
"515路", "516路", "517路", "518路", "519路", "520路", "521路", "522路",
"523路", "524路", "525路", "526路", "527路", "528路", "529路", "530路",
"531路", "532路", "533路", "602路", "603路", "604路", "605路", "606路",
"607路", "608路", "609路", "610路", "611路", "612路", "613路", "614路",
"615路", "616路", "617路", "618路", "619路", "620路", "621路", "623路",
"624路", "625路", "626路", "627路", "628路", "629路", "630路", "631路",
"632路", "633路", "634路", "635路", "636路", "637路", "638路", "639路",
"640路", "641路", "642路", "643路", "644路", "645路", "646路", "647路",
"648路", "649路", "650路", "651路", "652路", "653路", "655路", "656路",
"657路", "658路", "659路", "660路", "661路", "662路", "663路", "664路",
"665路", "666路", "667路", "668路", "669路", "670路", "671路", "672路",
"673路", "674路", "675路", "676路", "677路", "678路", "679路", "680路",
"681路", "682路", "683路", "684路", "685路", "686路", "687路", "688路",
"689路", "690路", "691路", "692路", "693路", "694路", "695路", "696路",
"697路", "698路", "699路", "761路", "762路", "763路", "765路", "766路",
"767路", "768路", "769路", "770路", "771路", "772路", "773路", "774路",
"775路", "776路", "777路", "778路", "779路", "780路", "781路", "782路",
"783路", "784路", "785路", "786路", "787路", "788路", "789路", "790路",
"791路", "792路", "793路", "794路", "795路", "796路", "797路", "798路",
"799路", "801路", "802路", "803路", "804路", "805路", "806路", "807路",
"808路", "809路", "901路", "902路", "903路", "904路", "905路", "906路",
"907路", "908路", "909路", "910路", "911路", "912路", "913路", "914路",
"915路", "916路", "917路", "918路", "919路", "920路", "921路", "922路",
"923路", "924路", "925路", "926路", "927路", "928路", "929路", "930路",
"931路", "932路", "933路", "934路", "935路", "936路", "937路", "938路",
"939路", "940路", "941路", "942路", "943路", "944路", "945路", "946路",
"947路", "948路", "949路", "950路", "951路", "952路", "953路", "954路",
"955路", "956路", "957路", "958路", "959路", "960路", "961路", "962路",
"963路", "964路", "965路", "966路", "967路", "968路", "969路", "970路",
"971路", "972路", "973路", "974路", "975路", "976路", "977路", "978路",
"979路", "980路", "981路", "982路", "983路", "984路", "985路", "986路",
"987路", "988路", "989路", "990路", "991路", "992路", "993路", "994路",
"995路", "996路", "997路", "998路", "999路"
]
接下来,我们可以编写一个函数来批量获取所有线路的信息:
def batch_get_bus_lines(line_names, city=CITY, key=AMAP_KEY, save_path=None):
"""
批量获取公交线路信息
:param line_names: 公交线路名称列表
:param city: 城市名称
:param key: 高德API Key
:param save_path: 数据保存路径(可选)
:return: 包含所有线路信息的DataFrame
"""
all_lines_data = []
failed_lines = []
for i, line_name in enumerate(line_names, 1):
print(f"正在获取线路 {i}/{len(line_names)}: {line_name}")
line_data = get_bus_line_info(line_name, city, key)
if line_data:
all_lines_data.append(line_data)
else:
failed_lines.append(line_name)
# 避免请求过于频繁,适当延时
time.sleep(0.1)
# 转换为DataFrame
df = pd.DataFrame(all_lines_data)
# 保存到文件
if save_path:
df.to_csv(save_path, index=False, encoding="utf_8_sig")
print(f"数据已保存到 {save_path}")
if failed_lines:
print(f"以下线路获取失败: {', '.join(failed_lines)}")
return df
4. 数据清洗与处理
从API获取的原始数据需要进行一些清洗和处理才能用于分析。以下是几个关键的数据处理步骤:
4.1 坐标数据处理
高德地图使用的是GCJ-02坐标系(火星坐标系),如果需要与其他地图服务(如Google地图)一起使用,可能需要转换为WGS-84坐标系。以下是坐标转换的实现:
import math
def gcj02_to_wgs84(lng, lat):
"""
GCJ-02(火星坐标系)转WGS-84
:param lng: 火星坐标系的经度
:param lat: 火星坐标系纬度
:return: WGS-84坐标系的经度,纬度
"""
a = 6378245.0 # 长半轴
ee = 0.00669342162296594323 # 扁率
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 * math.pi) + 20.0 *
math.sin(2.0 * lng * math.pi)) * 2.0 / 3.0
ret += (20.0 * math.sin(lat * math.pi) + 40.0 *
math.sin(lat / 3.0 * math.pi)) * 2.0 / 3.0
ret += (160.0 * math.sin(lat / 12.0 * math.pi) + 320 *
math.sin(lat * math.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 * math.pi) + 20.0 *
math.sin(2.0 * lng * math.pi)) * 2.0 / 3.0
ret += (20.0 * math.sin(lng * math.pi) + 40.0 *
math.sin(lng / 3.0 * math.pi)) * 2.0 / 3.0
ret += (150.0 * math.sin(lng / 12.0 * math.pi) + 300.0 *
math.sin(lng / 30.0 * math.pi)) * 2.0 / 3.0
return ret
dlat = transformlat(lng - 105.0, lat - 35.0)
dlng = transformlng(lng - 105.0, lat - 35.0)
radlat = lat / 180.0 * math.pi
magic = math.sin(radlat)
magic = 1 - ee * magic * magic
sqrtmagic = math.sqrt(magic)
dlat = (dlat * 180.0) / ((a * (1 - ee)) / (magic * sqrtmagic) * math.pi)
dlng = (dlng * 180.0) / (a / sqrtmagic * math.cos(radlat) * math.pi)
mglat = lat + dlat
mglng = lng + dlng
return [lng * 2 - mglng, lat * 2 - mglat]
4.2 轨迹坐标解析
高德API返回的轨迹坐标是一个字符串,格式为"经度1,纬度1;经度2,纬度2;..."。我们需要将其解析为坐标点列表:
def parse_polyline(polyline_str):
"""
解析高德地图的polyline字符串
:param polyline_str: 轨迹坐标字符串
:return: 包含(经度,纬度)元组的列表
"""
points = []
for point_str in polyline_str.split(";"):
if not point_str:
continue
lng, lat = map(float, point_str.split(","))
points.append((lng, lat))
return points
4.3 站点信息展开
原始数据中站点信息是以列表形式存储的,我们需要将其展开为每行一个站点的格式:
def expand_stop_info(df):
"""
展开站点信息,使每行对应一个站点
:param df: 原始数据DataFrame
:return: 展开后的DataFrame
"""
expanded_rows = []
for _, row in df.iterrows():
line_id = row["line_id"]
line_name = row["line_name"]
via_stops = row["via_stops"]
stop_locations = row["stop_locations"]
stop_sequence = row["stop_sequence"]
for stop_name, location, seq in zip(via_stops, stop_locations, stop_sequence):
lng, lat = map(float, location.split(","))
expanded_rows.append({
"line_id": line_id,
"line_name": line_name,
"stop_name": stop_name,
"longitude": lng,
"latitude": lat,
"sequence": seq
})
return pd.DataFrame(expanded_rows)
5. 数据存储与导出
处理后的数据可以存储为多种格式,以下是几种常见的存储方式:
5.1 CSV格式存储
# 保存线路基本信息
df_lines.to_csv("qingdao_bus_lines.csv", index=False, encoding="utf_8_sig")
# 保存站点信息
df_stops = expand_stop_info(df_lines)
df_stops.to_csv("qingdao_bus_stops.csv", index=False, encoding="utf_8_sig")
# 保存轨迹信息
df_trajectories = pd.DataFrame([
{"line_id": row["line_id"], "line_name": row["line_name"],
"polyline": parse_polyline(row["polyline"])}
for _, row in df_lines.iterrows()
])
df_trajectories.to_csv("qingdao_bus_trajectories.csv", index=False, encoding="utf_8_sig")
5.2 SQLite数据库存储
对于更复杂的数据管理需求,可以使用SQLite数据库:
import sqlite3
def save_to_sqlite(df_lines, db_path="qingdao_bus.db"):
"""
将公交数据保存到SQLite数据库
:param df_lines: 包含线路信息的DataFrame
:param db_path: 数据库文件路径
"""
conn = sqlite3.connect(db_path)
cursor = conn.cursor()
# 创建线路表
cursor.execute("""
CREATE TABLE IF NOT EXISTS bus_lines (
line_id TEXT PRIMARY KEY,
line_name TEXT,
start_stop TEXT,
end_stop TEXT,
company TEXT,
distance REAL,
start_time TEXT,
end_time TEXT,
total_price REAL
)
""")
# 创建站点表
cursor.execute("""
CREATE TABLE IF NOT EXISTS bus_stops (
id INTEGER PRIMARY KEY AUTOINCREMENT,
line_id TEXT,
line_name TEXT,
stop_name TEXT,
longitude REAL,
latitude REAL,
sequence INTEGER,
FOREIGN KEY (line_id) REFERENCES bus_lines (line_id)
)
""")
# 创建轨迹表
cursor.execute("""
CREATE TABLE IF NOT EXISTS bus_trajectories (
id INTEGER PRIMARY KEY AUTOINCREMENT,
line_id TEXT,
line_name TEXT,
point_index INTEGER,
longitude REAL,
latitude REAL,
FOREIGN KEY (line_id) REFERENCES bus_lines (line_id)
)
""")
# 插入线路数据
for _, row in df_lines.iterrows():
cursor.execute("""
INSERT OR REPLACE INTO bus_lines VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
""", (
row["line_id"], row["line_name"], row["start_stop"], row["end_stop"],
row["company"], row["distance"], row["start_time"], row["end_time"],
row["total_price"]
))
# 插入站点数据
df_stops = expand_stop_info(df_lines)
for _, row in df_stops.iterrows():
cursor.execute("""
INSERT INTO bus_stops (line_id, line_name, stop_name, longitude, latitude, sequence)
VALUES (?, ?, ?, ?, ?, ?)
""", (
row["line_id"], row["line_name"], row["stop_name"],
row["longitude"], row["latitude"], row["sequence"]
))
# 插入轨迹数据
for _, row in df_lines.iterrows():
points = parse_polyline(row["polyline"])
for i, (lng, lat) in enumerate(points):
cursor.execute("""
INSERT INTO bus_trajectories (line_id, line_name, point_index, longitude, latitude)
VALUES (?, ?, ?, ?, ?)
""", (
row["line_id"], row["line_name"], i, lng, lat
))
conn.commit()
conn.close()
6. 数据可视化
获取公交数据后,我们可以使用各种工具进行可视化展示。以下是使用Python的Plotly库进行可视化的示例:
6.1 公交线路地图可视化
import plotly.express as px
import plotly.graph_objects as go
def plot_bus_lines(df_lines, center_lat=36.09, center_lng=120.39, zoom=11):
"""
在地图上绘制公交线路
:param df_lines: 包含线路信息的DataFrame
:param center_lat: 地图中心纬度
:param center_lng: 地图中心经度
:param zoom: 缩放级别
"""
fig = go.Figure()
# 为每条线路添加轨迹
for _, row in df_lines.iterrows():
points = parse_polyline(row["polyline"])
lons = [p[0] for p in points]
lats = [p[1] for p in points]
fig.add_trace(go.Scattermapbox(
lon=lons,
lat=lats,
mode='lines',
line=dict(width=2, color='blue'),
name=row["line_name"],
hoverinfo='text',
hovertext=f"{row['line_name']}: {row['start_stop']} → {row['end_stop']}"
))
# 添加站点
df_stops = expand_stop_info(df_lines)
fig.add_trace(go.Scattermapbox(
lon=df_stops["longitude"],
lat=df_stops["latitude"],
mode='markers',
marker=dict(size=5, color='red'),
name='公交站点',
hoverinfo='text',
hovertext=df_stops["stop_name"]
))
# 设置地图布局
fig.update_layout(
mapbox_style="open-street-map",
mapbox=dict(
center=dict(lat=center_lat, lon=center_lng),
zoom=zoom
),
margin={"r":0,"t":0,"l":0,"b":0},
height=800
)
fig.show()
6.2 公交线路特征分析
我们可以计算并可视化一些公交线路的基本特征:
def analyze_bus_lines(df_lines):
"""
分析公交线路特征并可视化
:param df_lines: 包含线路信息的DataFrame
"""
# 计算基本统计量
avg_length = df_lines["distance"].mean()
avg_stops = df_lines["via_stops"].apply(len).mean()
avg_stop_distance = avg_length / avg_stops
print(f"平均线路长度: {avg_length:.2f} km")
print(f"平均站点数量: {avg_stops:.1f}")
print(f"平均站距: {avg_stop_distance:.2f} km")
# 线路长度分布
fig1 = px.histogram(df_lines, x="distance",
title="公交线路长度分布",
labels={"distance": "线路长度 (km)"},
nbins=30)
fig1.show()
# 站点数量分布
df_lines["stop_count"] = df_lines["via_stops"].apply(len)
fig2 = px.histogram(df_lines, x="stop_count",
title="公交线路站点数量分布",
labels={"stop_count": "站点数量"},
nbins=30)
fig2.show()
# 票价分布
fig3 = px.box(df_lines, y="total_price",
title="公交线路票价分布",
labels={"total_price": "票价 (元)"})
fig3.show()
7. 公交网络分析与换乘计算
获取完整的公交数据后,我们可以进行更复杂的网络分析,如计算换乘站点和最优路径。
7.1 构建换乘网络
首先,我们需要识别哪些站点是换乘站(被多条线路共享的站点):
def find_transfer_stops(df_stops):
"""
找出换乘站点(被多条线路共享的站点)
:param df_stops: 包含站点信息的DataFrame
:return: 换乘站点DataFrame
"""
# 统计每个站点被多少条线路使用
stop_usage = df_stops.groupby("stop_name").agg({
"line_id": "nunique",
"longitude": "first",
"latitude": "first"
}).reset_index()
# 筛选出换乘站(被2条及以上线路使用)
transfer_stops = stop_usage[stop_usage["line_id"] >= 2].sort_values(
"line_id", ascending=False)
return transfer_stops
7.2 计算线路间的换乘关系
我们可以构建一个线路间的换乘关系矩阵:
def build_line_transfer_matrix(df_stops):
"""
构建线路间的换乘关系矩阵
:param df_stops: 包含站点信息的DataFrame
:return: 换乘关系矩阵DataFrame
"""
# 获取所有线路ID和名称
lines = df_stops[["line_id", "line_name"]].drop_duplicates()
line_ids = lines["line_id"].tolist()
line_names = lines["line_name"].tolist()
# 初始化换乘矩阵
transfer_matrix = pd.DataFrame(
0, index=line_ids, columns=line_ids)
# 找出每条线路的站点集合
line_stops = {}
for line_id in line_ids:
stops = set(df_stops[df_stops["line_id"] == line_id]["stop_name"])
line_stops[line_id] = stops
# 填充换乘矩阵
for i, line1 in enumerate(line_ids):
for j, line2 in enumerate(line_ids):
if i >= j: # 矩阵是对称的,只需计算一半
common_stops = line_stops[line1] & line_stops[line2]
transfer_matrix.loc[line1, line2] = len(common_stops)
transfer_matrix.loc[line2, line1] = len(common_stops)
# 添加线路名称作为索引和列名
transfer_matrix.index = line_names
transfer_matrix.columns = line_names
return transfer_matrix
7.3 可视化换乘网络
我们可以使用NetworkX库来可视化公交线路的换乘关系:
import networkx as nx
import matplotlib.pyplot as plt
def visualize_transfer_network(transfer_matrix, min_transfers=1):
"""
可视化公交线路换乘网络
:param transfer_matrix: 换乘关系矩阵
:param min_transfers: 显示的最小换乘站点数
"""
G = nx.Graph()
# 添加节点(线路)
for line in transfer_matrix.index:
G.add_node(line)
# 添加边(换乘关系)
for i, line1 in enumerate(transfer_matrix.index):
for j, line2 in enumerate(transfer_matrix.columns):
if i < j and transfer_matrix.loc[line1, line2] >= min_transfers:
G.add_edge(line1, line2, weight=transfer_matrix.loc[line1, line2])
# 绘制网络图
plt.figure(figsize=(15, 15))
pos = nx.spring_layout(G, k=0.15, iterations=50)
# 绘制节点和边
nx.draw_networkx_nodes(G, pos, node_size=50, node_color="skyblue")
nx.draw_networkx_edges(G, pos, width=0.5, alpha=0.5, edge_color="gray")
# 添加标签(只显示部分重要线路)
degrees = dict(G.degree())
important_lines = [n for n in G.nodes() if degrees[n] >= 5]
labels = {n: n for n in important_lines}
nx.draw_networkx_labels(G, pos, labels, font_size=8)
plt.title("青岛公交线路换乘网络")
plt.axis("off")
plt.show()
8. 完整数据处理流程
将上述步骤整合为一个完整的数据处理流程:
def full_pipeline(line_names, city="青岛", key=None, save_dir="output"):
"""
完整的公交数据处理流程
:param line_names: 公交线路名称列表
:param city: 城市名称
:param key: 高德API Key
:param save_dir: 输出目录
"""
import os
os.makedirs(save_dir, exist_ok=True)
# 1. 批量获取公交线路数据
print("开始获取公交线路数据...")
df_lines = batch_get_bus_lines(line_names, city=city, key=key,
save_path=os.path.join(save_dir, "bus_lines_raw.csv"))
# 2. 展开站点信息
print("处理站点数据...")
df_stops = expand_stop_info(df_lines)
df_stops.to_csv(os.path.join(save_dir, "bus_stops.csv"),
index=False, encoding="utf_8_sig")
# 3. 保存轨迹数据
print("处理轨迹数据...")
trajectories = []
for _, row in df_lines.iterrows():
points = parse_polyline(row["polyline"])
for i, (lng, lat) in enumerate(points):
trajectories.append({
"line_id": row["line_id"],
"line_name": row["line_name"],
"point_index": i,
"longitude": lng,
"latitude": lat
})
df_trajectories = pd.DataFrame(trajectories)
df_trajectories.to_csv(os.path.join(save_dir, "bus_trajectories.csv"),
index=False, encoding="utf_8_sig")
# 4. 保存到SQLite数据库
print("保存到数据库...")
save_to_sqlite(df_lines, os.path.join(save_dir, "qingdao_bus.db"))
# 5. 分析换乘站点
print("分析换乘站点...")
transfer_stops = find_transfer_stops(df_stops)
transfer_stops.to_csv(os.path.join(save_dir, "transfer_stops.csv"),
index=False, encoding="utf_8_sig")
# 6. 构建换乘矩阵
print("构建换乘矩阵...")
transfer_matrix = build_line_transfer_matrix(df_stops)
transfer_matrix.to_csv(os.path.join(save_dir, "transfer_matrix.csv"),
encoding="utf_8_sig")
# 7. 可视化
print("生成可视化...")
plot_bus_lines(df_lines)
analyze_bus_lines(df_lines)
visualize_transfer_network(transfer_matrix)
print("数据处理完成!")
9. 实际应用与扩展
获取的公交数据可以应用于多种场景:
- 公交线路优化 :分析线路重叠、站点分布,提出优化建议
- 换乘规划 :基于换乘网络开发公交出行规划工具
- 可达性分析 :计算不同区域通过公交出行的便利程度
- 时空分析 :结合运营时间分析公交服务的时空覆盖
- 可视化大屏 :构建公交运营监控可视化系统
对于大规模应用,可以考虑以下扩展:
- 定时自动更新数据(每日/每周)
- 结合实时公交API获取车辆位置信息
- 集成其他交通方式数据(地铁、共享单车等)
- 开发Web应用或移动应用提供公交查询服务
更多推荐
所有评论(0)