Python 高德地图 API v3 公交数据爬取实战:青岛 275 条线路站点与轨迹坐标获取

公共交通数据是城市规划和智慧交通建设的重要基础。通过获取公交线路的站点信息和轨迹坐标,我们可以进行线路优化、换乘分析、可视化展示等多种应用。本文将详细介绍如何使用 Python 和高德地图 Web 服务 API v3 版本来爬取青岛市 275 条公交线路的完整数据。

1. 高德地图开发者 Key 申请与配置

要使用高德地图的 Web 服务 API,首先需要申请开发者 Key。以下是详细步骤:

  1. 访问 高德开放平台官网 并注册开发者账号
  2. 进入"控制台"→"应用管理"→"创建新应用"
  3. 为应用命名(如"青岛公交数据分析"),选择应用类型为"Web服务"
  4. 在创建的应用中添加 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. 实际应用与扩展

获取的公交数据可以应用于多种场景:

  1. 公交线路优化 :分析线路重叠、站点分布,提出优化建议
  2. 换乘规划 :基于换乘网络开发公交出行规划工具
  3. 可达性分析 :计算不同区域通过公交出行的便利程度
  4. 时空分析 :结合运营时间分析公交服务的时空覆盖
  5. 可视化大屏 :构建公交运营监控可视化系统

对于大规模应用,可以考虑以下扩展:

  • 定时自动更新数据(每日/每周)
  • 结合实时公交API获取车辆位置信息
  • 集成其他交通方式数据(地铁、共享单车等)
  • 开发Web应用或移动应用提供公交查询服务
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐