全国地铁数据可视化平台:Python+Flask+高德地图实战解析

📅 发布时间:2026/9/9 8:57:12
全国地铁数据可视化平台:Python+Flask+高德地图实战解析
全国地铁数据可视化这个选题我用一个周末做了个原型又在答辩前打磨了两周最后拿到了优秀毕业设计。这个题目给我的感觉是技术栈足够全能覆盖爬虫、后端、前端、算法四个方向又不至于像纯算法课题那样容易翻车。今天我把整个项目的设计思路、关键代码、踩坑记录全部拆开来讲希望能给正在选毕设题目或者准备复刻这个方向的同学一些参考。先说结论这个题目的核心不在于“爬数据”也不在于“画图表”而在于如何把全国几十个城市、上千条线路、上万个站点的数据组织好、分析透、展示漂亮。数据量不大但维度多非常适合用 Python Flask 高德地图 这套组合来实现。我用的技术栈是爬虫用 requests 高德地图 API数据处理用 pandas numpy后端接口用 Flask SQLite你也可以换 MySQL前端可视化用 ECharts 高德地图 JS API Bootstrap机器学习部分用 KMeans 做站点聚类、用线性回归做简单的客流预测。1. 项目整体设计与技术选型思路1.1 核心需求解析平台要解决什么问题拿到这个题目第一件事不是打开 IDE 写代码而是先把“平台”这个词拆开想清楚。评委眼里的“数据可视化分析平台”不是写几个图表页面就行它至少要有三个层次数据能取回来、数据能算明白、数据能看得懂。数据能取回来对应爬虫模块要解决“地铁数据从哪里来、怎么存”的问题。数据能算明白对应数据分析模块要能用统计方法回答“哪个城市地铁最发达”“哪条线路最拥挤”“哪些站点是换乘枢纽”这类问题。数据能看得懂对应可视化模块要能在网页上通过地图、图表直观呈现分析结果。这个逻辑清晰了你的系统架构自然就出来了答辩的时候讲起来也顺。1.2 为什么选 Python Flask 高德地图这套组合选型这件事很多同学纠结了很久。我见过有人用 Django有人用 Spring Boot还有人用 Vue 全套加 Node.js。但我的建议非常明确如果这是你的毕业设计不是实习项目选你最熟悉、生态最成熟、遇到问题搜得到答案的。Python Flask 就是这种组合。Flask 比 Django 轻量太多一个 app.py 就能跑起来路由和模板渲染逻辑一目了然对于中小型可视化平台来说完全够用。而且 Flask 和 Python 是原生一家人你爬虫写好了、pandas 处理好了直接丢给 Flask 暴露成接口不需要跨语言调用。高德地图的定位就更直接了——我们就在国内高德的 POI兴趣点数据里地铁站信息是免费开放的而且支持行政区划检索、关键字检索、多边形检索等多种方式比直接去爬地铁官网的 HTML 页面稳定得多。1.3 方案优势与避坑预期这套方案最大的优势在于风险可控。纯爬虫的题目容易踩反爬的坑纯可视化的题目容易做成“换皮大屏”没技术含量纯机器学习的题目容易在模型效果上翻车。而“爬虫 数据分析 可视化 少量机器学习”的结构每一块都有了每一块难度都适中任何一个环节出问题都有回退方案。比如说如果你在答辩前发现某些城市的数据没抓到没关系你的系统设计里已经支持了“数据文件导入”的功能手动补一份 CSV 进去就能演示。再比如如果高德地图 JS API 在你的浏览器上显示有问题你还有 ECharts 的地图作为备选展示方案不至于当场尬住。这种容错性是选题目时最需要考虑的事。2. 系统架构与功能模块拆解2.1 前后端分离还是模板渲染很多同学在开始写毕设之前会纠结一个问题要不要搞前后端分离我的建议是如果只是做毕设完全不需要。Flask 的 Jinja2 模板引擎已经足够强大你在后端处理好的数据通过 render_template 传参给模板前端用 ECharts 直接读数据渲染图表代码量最少调试最简单。当然如果你的平台上手能力很强或者你的毕设导师对架构要求比较高也可以选择 Flask 提供 JSON 接口 前端用 fetch 异步取数的“伪前后端分离”模式。也就是说页面还是由 Flask 渲染但图表数据是通过 /api/xxx 接口异步加载的。这种方式做出来架构清晰答辩的时候也好讲而且不会引入 Node.js 那套工程化复杂度。我自己的项目用的就是后者。2.2 数据流向与模块划分整个平台的数据流是单向的爬虫模块把高德地图返回的 JSON 数据结构化后写入 SQLite → 数据处理模块读取数据库用 pandas 做清洗、聚合、特征工程 → Flask 后端从处理好的结果中提取 API 响应 → 前端 ECharts 和高德地图组件把数据渲染成可视化页面。按这个数据流我把项目分成了五个包spider/爬虫模块负责高德 API 调用、数据解析、入库。data/存放 SQLite 数据库文件、CSV 临时文件、静态资源。analysis/数据分析与机器学习模块输出统计指标、聚类结果、预测结果。app.pyFlask 主程序注册路由、加载模板、提供 API。templates/和static/前端页面和静态文件。这个结构的好处是答辩的时候你能很清楚地说清楚“哪个包实现了什么功能”不会出现“代码全堆在一个文件里”这种尴尬情况。2.3 核心功能列表我最终交付的平台包含 6 个主要页面和 8 个数据接口首页/总览大屏展示城市总数、线路总数、站点总数、日均客流估算等核心指标。城市榜单按站点数量、线路数量、开通时间排序的全国地铁城市 Top 20。线路分析选取任意城市查看该城市各线路的站点数量、长度排序、开通时间轴。站点分析站点详情页展示所在线路、经纬度、换乘信息并标注是否为换乘枢纽。客流预测选取指定线路基于历史数据用线性回归预测下一站点的客流趋势。站点聚类基于站点周围 POI 数据用 KMeans 算法把站点划分为生活型、办公型、交通枢纽型、景区型。每个功能的背后都有对应的分析逻辑和数据支撑不是画空架子。这一部分在最开始就要想清楚因为页面的设计、数据结构的设计全都要往前端需求反推。3. 核心环节一高德地图地铁数据采集3.1 数据源选择与 API 调研做爬虫模块之前我对比过几个数据源地铁官网的站点信息、维基百科的线路词条、天眼查的轨道公司信息以及高德地图的 POI 接口。最终选高德原因有三。第一高德的 POI 数据里地铁站点的名称、经纬度、所属城市、地址信息非常规范可以直接拿来用。第二高德提供了 Web 服务 API不需要模拟浏览器不用担心被 JS 加密卡住只需要一个 key 就能调。第三高德支持按行政区划递归查询你只要把城市列表准备好就能抓到全国的数据不需要挨个城市找官网。补充一点高德开放平台申请 key 是免费的个人开发者就可以。我去申请的时候大概几分钟就下来了key 的形式是一串字符调用 API 的时候放在参数里就行。3.2 用高德 POI 检索地铁站高德地图的“关键字搜索”接口请求地址是https://restapi.amap.com/v3/place/text关键参数有key你的开发者密钥。keywords搜索关键字我这里固定为“地铁站”。city城市名称或 adcode。offset每页记录数最大 100。page页码总共最多可以翻页到 100 页实际地铁站远用不到 100 页但逻辑要写好。extensions如果传all会返回 POI 的详细信息。我用这个接口写了一个通用的采集函数。这里有一个隐藏的坑高德的地铁站 POI 并不等于“车站出入口”它返回的实际上是站点主体位置。所以每个站的经纬度只有一组你要做站点坐标展示这个精度就够了。如果你需要出入口信息那得去爬高德地图网页版的前端接口难度会大不少不建议在毕设里碰。核心爬虫代码如下import requests import json import time import pandas as pd # 高德地图 Web服务 key申请地址https://lbs.amap.com/ AMAP_KEY your_key_here def fetch_subway_stations(city: str) - list: 抓取指定城市的地铁站POI数据 results [] page 1 while True: url https://restapi.amap.com/v3/place/text params { key: AMAP_KEY, keywords: 地铁站, city: city, citylimit: true, offset: 100, page: page, extensions: all } resp requests.get(url, paramsparams, timeout10) data resp.json() pois data.get(pois, []) if not pois: break for poi in pois: results.append({ city: city, name: poi.get(name), address: poi.get(address, ), location: poi.get(location, ), type: poi.get(type, ), adcode: poi.get(adcode, ) }) page 1 # 避免触发高德的频率限制间隔0.2秒 time.sleep(0.2) return results这个函数的逻辑很简单就是循环翻页直到某一页没有 POI 返回为止。我在实际跑的时候北京大约能抓到 400 个左右的 POI上海 350 个左右广州 200 个左右数据量很合理。3.3 线路与站点关系数据获取这里要注意高德 POI 接口能拿到“站点”信息但拿不到“站点属于哪条线路”和“线路有哪些站点”。所以我在实现时做了一个折中方案——用 list 接口单独抓一次城市的地铁线路。高德有专门的“公交线路” API全称是“公交路线规划”需要传 city 和 offset/ page。但它的线路数据主要面向公交规划地铁部分不一定覆盖全。稳妥的做法是从高德 POI 中抓站点从城市地铁官网的新闻稿或维基百科词条中抓“XX线共N站”的统计数字用于榜单展示。为什么这么设计因为如果你的可视化只需要“站点分布地图”和“城市线路总数”那 POI 官网统计已经够了。如果你要做很细的“某号线全程站名图”那需要去爬百度百科或维基百科的词条表格而且每个城市的结构都不一样开发量大维护成本高不值得在毕设里做。所以我最终的线上数据策略是地铁站点坐标100% 来自高德 POI城市开通地铁线路数和线路首通年份来自公开统计资料我手动整理了一份 CSV 放进了 data/ 目录。这条策略答辩时讲清楚导师不会挑刺反而会觉得你理解了“数据和业务取舍”的关系。3.4 数据清洗与入库抓下来的原始 POI 数据有一个很烦的问题名称不统一比如“人民广场站”“人民广场”混杂有的 POI 名称带“地铁站”三个字有的不带。数据清洗阶段我统一做了这样几件事把名称里的“地铁站”“轨道交通”等冗余词去掉只保留标准站名。把经纬度字符串类似116.397428,39.90923拆开转成浮点数并存成两列lng和lat。去掉重复站点。按city name做去重保留第一条。按城市统计出线路数、站点数计算城市地铁密度站点数除以城市面积。数据入库用 SQLite相当于一个轻量级的数据仓库。建表语句大概长这样CREATE TABLE IF NOT EXISTS station ( id INTEGER PRIMARY KEY AUTOINCREMENT, city TEXT NOT NULL, name TEXT NOT NULL, lng REAL NOT NULL, lat REAL NOT NULL, address TEXT, type TEXT, adcode TEXT ); CREATE TABLE IF NOT EXISTS city_stat ( city TEXT PRIMARY KEY, line_count INTEGER, station_count INTEGER, first_year INTEGER, area_km2 REAL );SQLite 对单机应用来说完全够用而且它是文件型的答辩前直接把项目打包带走就行不需要现场装数据库服务。我是先创建city_stat表导入手动整理的统计资料然后再往station表里去灌爬虫结果。4. 核心环节二数据分析与机器学习模块4.1 城市地铁发展指数计算拿到数据后的第一步分析就是给全国的城市算一个简单的“地铁发展指数”。我用了几组指标站点总量线路总量首条线路开通年份代表发展历史中心城区人口用于做密度归一化然后把每个指标做 Min-Max 标准化加权重合成一个 0~100 的指数。排序后北京、上海、广州、深圳、成都基本占据了前五名。这个结果不意外但它的意义在于你的系统里有一个“可解释的分析结论”而不是干巴巴的数字表。这个指数的计算公式很简单def calc_metro_index(row, col, weights): # 先做 min-max 标准化 min_val df[col].min() max_val df[col].max() norm (row[col] - min_val) / (max_val - min_val 1e-6) return norm * weights[col]权重我调了很多版比如站点数权重 0.3、线路数 0.3、首通年份近度 0.2、人口密度修正 0.2。到了后期我甚至想把“换乘站数量”也纳入指数计算这样枢纽城市会排得更高。但为了控制工作量最后用了四维版本。这个指数在首页大屏上以“城市排名”的竖直条形图展示效果非常直观。4.2 站点类型聚类把 KMeans 用在地铁场景机器学习模块是整个项目的“含金量担当”也是答辩时最容易被追问的地方。我用的是最经典的无监督学习算法——KMeans做站点的功能类型聚类。思路是这样的每个地铁站所在区域的 POI 类型决定了它是一座“通勤型枢纽站”还是一个“生活型社区站”。我给每一个站点定义了三组特征work_score周围 500 米范围内写字楼、产业园、科技园区 POI 数量。life_score周围 500 米范围内住宅小区、超市、便利店、菜市场 POI 数量。tour_score周围 500 米范围内景点、公园、历史文化类 POI 数量。关于“周围 500 米怎么算”高德 POI 搜索接口支持around多边形/圆内搜索参数。我用每个地铁站的经纬度作为圆心半径为 1000 米搜索商务楼宇、住宅区、旅游景区三类 POI然后分别计数。注意1 公里的半径相对合理因为地铁站的辐射范围本来就是 1 公里级别。特征算好后KMeans 聚类就很简单from sklearn.preprocessing import StandardScaler from sklearn.cluster import KMeans features df[[work_score, life_score, tour_score]].values scaler StandardScaler() features_scaled scaler.fit_transform(features) kmeans KMeans(n_clusters4, random_state42) df[cluster] kmeans.fit_predict(features_scaled)我试了 n_clusters 从 3 到 6 的效果最后选的 4 类。把每一类的中心点打出来看发现这个聚类结果非常有意思第一类站点集中在 CBD 周边work_score 显著高第二类集中在大规模居住区life_score 高第三类是景区周边站点tour_score 高第四类是混合型站点三项指标相对均衡。我把这个结果做了“站点类型分布饼图”然后再把每个类型的站点散点画到高德地图上红点代表办公型、绿点代表生活型、蓝点代表景区型、紫点代表混合型。答辩现场评委问了两个问题第一为什么不用 DBSCAN我说选 KMeans 是因为它简单、可解释性强而且我可以把聚类中心展示出来解释每一类的含义DBSCAN 虽然不需要指定类别数但调参难度更高毕设的工程量不适合。第二特征选择是否合理我说特征来源于高德 POI 分类虽然不完美但代表性强而且这种“基于实际业务场景构建特征”的思路是通用数据分析的核心方法。这两个回答直接加分。4.3 客流趋势预测线性回归做示范客流预测这个模块我一开始是排斥的因为公开的真实客流数据很难拿到。后来想通了这个模块更重要的是“演示预测方法”而不是“预测准不准”。所以我用了一个简化方案——用高德 API 拿到的站点周边公交站数量、道路数量、写字楼密度等数据模拟出该站的“相对客流指数”然后用过去 12 个月的模拟客流数据做趋势外推用线性回归预测下个月的客流指数。这里的关键是你要在论文里讲清楚“这是一个基于公开数据的近似模型”不要假装自己拿到了地铁公司的内部数据。诚实交代数据来源和局限性反而显得研究态度扎实。线性回归用 sklearn 写只要几行from sklearn.linear_model import LinearRegression # train_x: [[1], [2], [3], ..., [12]] 月份 # train_y: 前12个月的客流指数 model LinearRegression() model.fit(train_x, train_y) future_x [[13]] # 下个月 pred model.predict(future_x)为了可视化我把历史数据画成折线把预测值画成一个“未来点”或者延伸虚线放置在 ECharts 的图表里效果是“前面曲线 后面虚线”一眼就能看出趋势。这个模块虽然不复杂但它完整展示了一个数据分析的标准流程构造指标 → 历史数据 → 模型训练 → 预测 → 可视化。5. 核心环节三Flask 后端与可视化页面实现5.1 Flask 路由与接口设计Flask 后端的代码我放在了app.py里整体风格是“路由 数据处理”分离。一个典型的路由是这样from flask import Flask, render_template, jsonify import sqlite3 import pandas as pd import json app Flask(__name__) def query_sql(sql): conn sqlite3.connect(data/metro.db) df pd.read_sql_query(sql, conn) conn.close() return df app.route(/) def index(): return render_template(index.html) app.route(/api/summary) def api_summary(): city_count query_sql(SELECT COUNT(DISTINCT city) AS cnt FROM station)[cnt][0] line_count query_sql(SELECT SUM(line_count) AS cnt FROM city_stat)[cnt][0] station_count query_sql(SELECT COUNT(*) AS cnt FROM station)[cnt][0] return jsonify({city_count: city_count, line_count: line_count, station_count: station_count})Flask 的接口返回 JSON前端用 ECharts 的fetch接口拉数据。这样有一个好处如果某个接口的数据计算时间较长前端可以显示 loading 动画体验比一次性渲染整个页面好得多。5.2 前端可视化方案ECharts 高德地图 JS可视化是“全国地铁数据可视化分析平台”的门面做得丑技术再强也白搭。我前端的核心库选了 ECharts因为它对地图、折线图、柱状图、散点图的支持都是一流的而且中文文档非常全。高德地图的 JS API 在模板页面中通过script标签引入关键配置是引入安全密钥script srchttps://webapi.amap.com/maps?v2.0keyYOUR_KEYpluginAMap.ToolBar/script然后初始化地图对象。为了让站点数据在地图上显示我用了AMap.Marker加自定义的content模板或者用聚合点AMap.MarkerClusterer避免几百个站点挤在一起。实际效果是页面上展示全国地图用户点任何一个城市地图视角会飞过去露出该市的站点散点。ECharts 图表部分我用得最多的是这几个bar条形图城市地铁站点数排名 Top 20。pie饼图站点类型聚类分布。line折线图客流趋势预测。scatter散点图全国站点分布密度。gauge仪表盘首页的总览评分或客流指数。给 ECharts 数据的时候注意后端要返回 Python 的list或dict前端直接JSON.parse即可。我踩过一个坑pandas 的to_json默认返回的是字符串如果直接把df.to_json(orientrecords)传到模板前端拿到的会是字符串需要再调一次JSON.parse()。后来我统一在 Flask 里用json.loads(df.to_json(orientrecords))转成 Python 对象前端就不再处理字符串了。5.3 前后端联调与性能优化平台页面前后端联调的过程中最需要关注的不是功能而是性能。我从高德 API 抓回来的数据并不大站点总量也就几千条但是如果每个图表请求都去重新爬取数据那肯定慢。所以我的核心优化策略是所有数据在项目初始化时一次性抓取入库后续所有分析全部从 SQLite 读取不再调用外部 API。这样系统的响应速度基本在毫秒级演示的时候不会有等待焦虑。另外ECharts 在首次渲染时如果数据量特别大建议开启animation: false或者large: true模式。特别是散点图几百上千个点不优化的话有些普通笔记本会卡。我把散点图的数据量控制在 500 个以内采用随机采样或者聚类中心点展示兼顾流畅度和完整性。5.4 高德地图与 ECharts 的联动技巧这个联动是整篇项目里比较亮的一个设计我强烈建议做进去。具体做法是通过一个下拉选择器用户在页面上选择城市JS 把选中的城市名作为参数传给高德地图地图的setCenter和setZoom方法把视野移动到对应的城市边界和缩放级别同时 ECharts 的柱状图也更新为该城市内部各线路的站点数。核心的联动代码大概长这样function switchCity(cityName) { // 更新高德地图视角 map.setZoomAndCenter(11, getCityCenter(cityName)); // 更新右侧柱状图数据 fetch(/api/line_stat?city encodeURIComponent(cityName)) .then(res res.json()) .then(data { myChart.setOption({ xAxis: { data: data.lines }, series: [{ data: data.counts }] }); }); }联动做出来之后评委的注意力会被“平台化”的交互效果吸引答辩效果直接拉满。我的体会是评委看毕设并不指望你真的造出多牛的系统但如果你能让他看到一个清晰的交互闭环比如“点击城市 → 地图刷新 → 图表变化 → 分析结论更新”他会认为你的工程能力是过关的。6. 常见问题与排查技巧实录6.1 高德地图 API 调用频繁报错怎么办在我开发的过程中最烦人的问题是高德 API 的 QPS 限制。免费 key 的 QPS 一般是 3也就是每秒最多 3 个请求。我写爬虫时如果没做好限速批量抓城市数据的时候很容易出现CUQPS_HAS_EXCEEDED_THE_LIMIT错误。解决办法在爬虫的 while 循环里在两次请求之间主动加time.sleep(0.3)确保每秒只发 3 个请求。更稳妥的做法是把城市列表拆成几批每批抓完休息 10 秒再继续。另外如果你申请的是 Web 服务 key记得在控制台里配置白名单否则本地调试本地 IP 没问题一旦部署到服务器上就可能被拒绝访问。6.2 ECharts 地图不显示省份边界这个问题很多同学都遇到过。ECharts 5 以后的版本不再自带地图 GeoJSON 数据如果你要画地图必须自己去下载全国的 GeoJSON然后在代码里echarts.registerMap(china, chinaJson)。没有注册地图的话地图散点图或者柱状地图会直接白屏。我的解决方案是主页的全国站点分布用高德地图 JS API 来做不依赖 ECharts 地图只有城市榜单那种纯柱状图/条形图才用 ECharts。这样从根本上绕开了 GeoJSON 的加载问题。不过如果你的设计里一定要用 ECharts 的地图可以到公开的 GeoJSON 资源站下载省市数据注意选择跟你的项目匹配的坐标系精度大部分国内资源站用的都是 GCJ-02 坐标和高德的坐标体系是一致的。6.3 坐标偏移问题高德坐标与 WGS-84 的坑如果你在地图上叠加了外部数据源比如从 OpenStreetMap 爬到的数据很可能会遇到一个常见问题站点位置偏移了几百米。这是因为高德地图用的是 GCJ-02 坐标系火星坐标系而 OSM 和 GPS 原始数据用的通常是 WGS-84 坐标系。两者之间不是简单的加减必须经过火星坐标转换算法。毕设阶段我的建议是所有数据统一用高德自己的坐标系不要混用。爬虫直接拿高德 POI 的 location 字段地图直接用高德 JS API这样就不用处理任何坐标系转换。如果一定要混用去找一个公开的坐标转换的 Python 库例如coord_convert类库网上有很多实现可以做到批量转换。6.4 答辩现场演示翻车急救清单这个部分没有别人会告诉你但我觉得每个做毕设的人都应该提前演练一遍。答辩当天的演示环境一般不是你自己的电脑可能是教室的投影仪或者评委的笔记本所以做两手准备是必须的。我的做法是提前在本地起好 Flask 服务并且把数据库和爬虫缓存都准备好保证即使不联网也能演示大部分功能。把核心页面装到一个独立目录里直接双击start.bat启动不依赖 IDE不需要安装额外的包。写一个静态版的demo.html把图表提前渲染成静态图片放在页面上万一现场服务起不来就展示静态页面截图照样能讲完整个项目。第一点最重要。因为如果你在答辩现场调用高德 API而现场网络环境不稳定或者 key 所在 IP 白名单被限制了页面很可能直接白屏。我更推荐提前把高德地图的页面截图存下来演示时展示截图加口头描述再配合本地 ECharts 图表做实时切换这样既安全又有说服力。6.5 关键教训控制数据库字段类型与大小写SQLite 新手常犯的错误是字段类型很随意。我的建议是所有统计指标字段统一用 INTEGER 或 REAL所有文本字段统一用 TEXT不要用 VARCHAR。另外SQLite 对字段名大小写不敏感但 Python 的 dict 是大小写敏感的所以你在写query_sql()函数时永远用df[col_name]的字母和你建表时的字母保持一致否则很容易翻车。我遇到过一次很隐蔽的 bug建表时字段叫StationCount写查询时用了station_count结果 pandas 读出来一个空列但 SQLite 并没有报错。这种错误调试起来非常痛苦所以干脆在建表前就统一好命名规范我整个项目全部使用小写加下划线一劳永逸。7. 扩展与后续优化建议如果你的时间比较充裕或者想在这个项目的基础上继续深挖我有几个方向可以供你选择。第一个方向是接入真实客流数据。地铁公司不会把内部数据开放出来但一些研究机构或数据竞赛平台会有城市轨道交通客流量的脱敏数据集你可以用它替换掉我设计里的模拟客流指数让客流预测模块变得“有据可查”。第二个方向是引入时间维度分析比如把站点的 POI 数据按年份做切片研究“地铁站周边商业形态的演变”。这个方向需要有历史 POI 数据源高德的静态 API 拿不到可以找开放数据平台做补充。第三个方向是做一个用户系统支持注册登录、收藏常坐线路、定制个人通勤看板虽然业务复杂度上去了但工程完整性会更高适合想在毕设里体现全栈能力的同学。我在做扩展的时候还试过把机器学习模型换成聚类加降维也就是用 PCA 对特征降维后拿去做二维散点可视化这个做出来的交互体验更好站点在平面图上的分布一目了然。最后再分享一个小技巧由于毕设项目通常要跑通整个链路你最好从第一天开始就把数据清洗和字段名规范固定下来不要中途频繁改表结构。我因为中途改了两次数据库结构和字段名导致前面的爬虫、分析、可视化代码全部要同步改白白浪费了大概两天的时间。先定好 schema再写代码进度反而快得多。