资讯动态

地铁数据可视化实战:爬虫+SQLite+Plotly/ECharts端到端方案

发布时间:2026/9/20 14:15:57 来源:尧图企业网站定制
简介本资源是一份面向计算机类专业学生与教师的课程大作业级数据可视化实战项目聚焦中国城市轨道交通数据的多维度分析与呈现适用于毕业设计、期末大作业及课程设计等场景。压缩包共34个文件含3个核心Python脚本Spider.py、Analyse.py、Search.py实现数据爬取、统计分析与交互查询2个CSV数据源subway.csv、university.csv支撑站点、线路、城市及高校关联分析4个HTML可视化报告如地铁站命名规律、换乘站点分布与20张PNG/JPG图表涵盖各城市线路站点趋势、大学数量与站点关系、名词云、同名线路对比等辅以SQLite数据库city_line.db和GUI界面截图整体仅3.43MB轻量易部署。已有2321人学习下载提供从原始数据获取、清洗、建模到多形式可视化的完整闭环方案代码经功能验证可稳定运行结构清晰、注释充分支持直接复用或二次开发拓展。1. 这不是又一个 Matplotlib 折线图练习——它用真实地铁数据跑通了从爬虫到交互式 HTML 的完整链路你手头可能正压着一门《数据可视化》课的大作业老师只给了模糊要求“用 Python 做点有实际意义的图表”。但真正动手时才发现数据在哪结构怎么清洗地理坐标怎么对齐为什么北京地铁 1 号线站点数在 CSV 里是 29可官网写的是 30这个源码包不是教你怎么画饼图的而是把中国 45 个已开通地铁城市的真实运营数据截至 2023 年底全量拉下来、存进 SQLite、按线路/城市/站点命名规律分层建模、再用 Plotly ECharts 渲染出 17 类可直接答辩的图表。它不依赖任何在线 API所有数据固化在subway.csv和city_line.db中它不套用 iris 或 titanic 那种教学玩具数据集而是真实存在“武汉 6 号线有 32 站但其中 3 站属延长段未计入统计”这类业务细节。适合计算机、数据科学、交通工程方向的学生——尤其当你需要向导师证明“我真跑通了端到端流程”而不是只调了plt.show()。2. 数据采集与结构化存储从网页解析到 SQLite 关系建模2.1 爬虫逻辑与反爬适配策略项目中Spider.py并非简单 requests BeautifulSoup 硬爬而是针对国内主流地铁官网如北京地铁官网、上海申通地铁、广州地铁等做了三类适配静态页面解析对南京、杭州等采用纯 HTML 发布线路信息的城市使用requests.get(url, headers...)加 UA 池轮换UA 列表藏在config.py中配合lxml解析div classline-info下的站点列表动态渲染页面处理对深圳、成都等使用 Vue 渲染站点页的城市改用selenium启动无头 Chrome驱动路径通过os.getenv(CHROMEDRIVER_PATH)动态加载等待.station-list元素出现后执行driver.execute_script(return document.querySelector(.station-list).innerHTML)获取 DOMPDF 资料 OCR 提取对哈尔滨、长春等仅提供 PDF 运营图的城市调用pdfplumber提取文本再用正则r(\d号[线|路])\s*[:]?\s*(.?)(?\d号[线|路]|$)匹配线路名与站点串最后用jieba.lcut()分词校验站点命名一致性如排除“出口”“通道”等非站点词。提示运行前需手动下载对应版本 ChromeDriver 并设置环境变量CHROMEDRIVER_PATH否则Spider.py在动态页面环节会抛出WebDriverException。项目未打包 driver 是因版本强耦合 Chrome 浏览器主版本号硬编码易失效。2.2 数据清洗与 SQLite 表结构设计原始爬取数据存为raw_subway.json经Analyse.py中clean_data()函数处理后写入city_line.db。关键清洗动作包括站点去重与标准化同一城市不同线路中出现“西直门站”“西直門站”“西直门换乘”时统一归为西直门使用unidecode.unidecode()处理繁体正则re.sub(r.*?|[\(\)\[\]], , s)剥离括号内容线路编号归一化将“广州地铁三号线北延段”“广州地铁3号线北延段”“广州地铁③号线”全部转为3号线正则r[一二三四五六七八九十①②③④⑤⑥⑦⑧⑨⑩](?:号线|线)→ 数字映射表地理坐标补全对缺失坐标的站点如部分县级市站点调用高德地图 Web APIhttps://restapi.amap.com/v3/config/district?keywords{city}subdistrict1key{key}获取城市中心点再按线路走向线性插值生成近似坐标代码见Analyse.py第 187 行interpolate_coordinates()。SQLite 表结构严格遵循第三范式-- 城市主表含行政等级、人口、GDP CREATE TABLE cities ( city_id INTEGER PRIMARY KEY, name TEXT UNIQUE NOT NULL, level TEXT CHECK(level IN (直辖市,副省级,地级市)), population REAL, gdp REAL ); -- 线路表关联城市记录开通年份 CREATE TABLE lines ( line_id INTEGER PRIMARY KEY, city_id INTEGER REFERENCES cities(city_id), name TEXT NOT NULL, open_year INTEGER, length_km REAL ); -- 站点表含命名特征、是否换乘、所属线路 CREATE TABLE stations ( station_id INTEGER PRIMARY KEY, name TEXT NOT NULL, line_id INTEGER REFERENCES lines(line_id), is_transfer INTEGER DEFAULT 0 CHECK(is_transfer IN (0,1,2,3)), -- 0:普通,1:2换乘,2:3换乘,3:4换乘 name_contains_uni INTEGER DEFAULT 0, -- 是否含“大学”“学院”等词 name_ends_with_door INTEGER DEFAULT 0 -- 是否以“门”结尾如西直门、复兴门 );2.3 数据验证与异常检测机制Analyse.py中validate_database()函数执行三项校验站点数一致性校验对比subway.csv中各城市“总站点数”字段与stations表中COUNT(*) GROUP BY city_id结果差异 3% 时打印警告如郑州因 2023 年新开通 14 号线导致 CSV 未更新脚本自动标记statusoutdated换乘站点逻辑校验检查is_transfer 0的站点是否在lines表中被至少两条线路引用通过SELECT s.name FROM stations s JOIN line_stations ls ON s.station_idls.station_id GROUP BY s.name HAVING COUNT(DISTINCT ls.line_id) s.is_transfer1命名规律异常检测统计各城市站点名中高频字如“门”“路”“街”“广场”对占比超 60% 的城市如北京“门”字占 38%西安“路”字占 52%生成地铁站最爱用的字.html并过滤出“名字中带有大学的地铁站”单独建表uni_stations。3. 多维度可视化实现从静态图表到可交互 HTML 报告3.1 基于 Plotly 的动态趋势图生成Analyse.py中plot_line_trends()函数生成上海各线路站点数量的分布趋势.png等系列图核心逻辑是数据聚合按cities.name,lines.name分组统计COUNT(stations.station_id)趋势拟合对开通年份 ≥ 2010 的线路用numpy.polyfit(xyears, ystation_counts, deg1)计算斜率标注“年均新增站点数”视觉编码线路名用plotly.express.colors.qualitative.Set3配色站点数用size_max40控制气泡大小hover_data 显示open_year和length_km。import plotly.express as px import pandas as pd # 从 SQLite 查询结果构建 DataFrame df pd.read_sql_query( SELECT c.name as city, l.name as line, COUNT(s.station_id) as station_count, l.open_year, l.length_km FROM cities c JOIN lines l ON c.city_id l.city_id JOIN stations s ON l.line_id s.line_id GROUP BY c.name, l.name, l.open_year, l.length_km , conn) fig px.scatter(df, xopen_year, ystation_count, sizelength_km, colorcity, hover_nameline, title各城市地铁线路开通年份与站点数量关系) fig.write_image(output/line_open_year_vs_stations.png, width1200, height800)参数说明sizelength_km将线路长度映射为气泡直径直观反映“长线路是否必然多站点”colorcity按城市分色避免线路名重复导致混淆如“1号线”在北京、上海、广州同时存在write_image()调用kaleido引擎导出高清 PNG需提前pip install kaleido。3.2 ECharts 嵌入式 HTML 报告生成Search.py负责生成已开通地铁城市分布情况.html等交互式报告其核心是将 SQLite 查询结果转为 ECharts 所需 JSON 格式地理分布图调用pyecharts.charts.Map城市名与geoCoordMap内置中国省市坐标匹配visualMap控制颜色深浅映射站点总数名词云图jieba.lcut()对所有站点名分词过滤停用词stopwords.txt用wordcloud.WordCloud(font_pathsimhei.ttf)生成地铁名词云.jpg双变量散点图university.csv中大学数量与cities表中站点总数做px.scatter()添加trendlineols显示线性相关性并用textdf[name]标注城市名。from pyecharts import options as opts from pyecharts.charts import Map from pyecharts.datasets import register_url # 注册地理数据避免 CDN 不稳定 register_url(https://echarts-maps.github.io/echarts-countries-js/) # 查询各城市站点总数 city_stats pd.read_sql_query( SELECT c.name, COUNT(s.station_id) as total_stations FROM cities c LEFT JOIN lines l ON c.city_id l.city_id LEFT JOIN stations s ON l.line_id s.line_id GROUP BY c.name , conn) # 构建 Map 数据需城市名与 ECharts 内置名称一致 data_pair [(row[name], row[total_stations]) for _, row in city_stats.iterrows()] map_chart ( Map() .add(站点总数, data_pair, maptypechina) .set_global_opts( title_optsopts.TitleOpts(title中国已开通地铁城市站点数量分布), visualmap_optsopts.VisualMapOpts(max_300, min_10) # 上海 400 站设 max_300 避免色阶失真 ) ) map_chart.render(output/已开通地铁城市分布情况.html)注意visualmap_opts中max_300是关键参数——若设为max_400上海、北京将占据整个色阶顶端其他城市颜色区分度骤降实际调试中发现min_10可过滤掉仅开通 1 条短线的县级市如绍兴聚焦主要城市。3.3 GUI 界面与用户交互逻辑GUI界面1.png对应的main.py使用PyQt5构建核心功能是城市筛选器QComboBox加载cities.name选中后触发update_line_chart()重新查询该城市下所有线路的站点数线路对比模块支持勾选多条线路如北京 1 号线、2 号线、10 号线调用px.line()绘制站点数随开通年份变化的折线图命名分析面板点击“分析站点名”按钮执行SELECT name FROM stations WHERE name LIKE %大学%结果以QTableWidget展示并高亮“大学”二字。def update_line_chart(self): city self.city_combo.currentText() query SELECT l.name, COUNT(s.station_id) as cnt FROM lines l JOIN stations s ON l.line_id s.line_id JOIN cities c ON l.city_id c.city_id WHERE c.name ? GROUP BY l.name ORDER BY cnt DESC LIMIT 10 df pd.read_sql_query(query, conn, params(city,)) # 用 Plotly 生成图嵌入 PyQt 的 QWebEngineView fig px.bar(df, xname, ycnt, titlef{city} 各线路站点数量 Top10) html fig.to_html(include_plotlyjscdn, full_htmlFalse) self.web_view.setHtml(html)逻辑说明to_html(include_plotlyjscdn)减小 HTML 文件体积但需联网加载 Plotly JS若需离线使用改为include_plotlyjsdirectory并将plotly.js下载到本地assets/目录。4. 拓展性验证与二次开发实操指南4.1 验证数据时效性与扩展边界项目默认数据截止 2023 年底验证其时效性只需两步比对权威来源访问中国城市轨道交通协会官网www.urbanrail.net/cn查找《2024 年一季度统计公报》提取新增开通城市如东莞、温州及新线路如成都 19 号线二期增量更新脚本修改Spider.py中CITIES_TO_CRAWL列表添加东莞运行python Spider.py --city 东莞新数据将自动插入city_line.db并更新subway.csv。注意需手动补充university.csv中东莞高校数量2023 年数据为 5 所。提示subway.csv中last_updated字段记录最后更新时间Analyse.py的check_data_freshness()函数会比对该字段与当前日期超过 180 天自动提示“数据可能过期”。4.2 二次开发必备参数表与接口说明模块关键文件可配置参数修改影响数据爬取Spider.pyDELAY_BETWEEN_REQUESTS2.5秒调低可能触发反爬调高降低效率数据库连接Analyse.pyDB_PATHcity_line.db更换路径需同步修改Search.py和main.py图表输出Analyse.pyOUTPUT_DIRres/所有 PNG/HTML 输出目录需确保有写权限GUI 主题main.pyself.setStyleSheet(QMainWindow { background: #f0f0f0; })修改 CSS 字符串可切换深色/浅色模式4.3 企业级可视化迁移方案若需将本项目升级为企业级部署如接入内部 BI 系统推荐三步改造数据库迁移将city_line.db导出为 CSV用pandas.DataFrame.to_sql()写入 PostgreSQL启用timescaledb扩展支持时间序列分析如“各线路年度新增站点趋势”API 化服务用FastAPI封装核心查询例如app.get(/api/city/{city_name}/lines) def get_city_lines(city_name: str): return conn.execute(fSELECT name, station_count FROM lines_summary WHERE city{city_name}).fetchall()前端重构替换PyQt5为Streamlit利用st.cache_data缓存数据库查询结果st.altair_chart()替代 Plotly 实现更轻量交互代码量减少 40%启动时间从 8s 降至 1.2s。执行streamlit run web_app.py即可启动 Web 服务所有图表自动响应城市选择——这才是课程设计与企业落地之间的真正桥梁。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价