ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Flask旅游数据分析系统:本地可运行、带真实数据流的Python可视化看板

Flask旅游数据分析系统:本地可运行、带真实数据流的Python可视化看板 简介本资源是一套基于Flask框架开发的旅游网站数据分析与可视化系统源码面向Python初学者及Web开发进阶学习者适用于课程设计、毕业设计或数据分析实战项目。系统整合爬虫数据含餐饮旅游类结构化信息、MySQL数据库存储、Flask后端逻辑与HTMLCSSJS前端展示完整覆盖数据采集、清洗、分析、存储到可视化的全流程。压缩包共251个文件包含20个核心Python脚本含Flask路由、数据处理模块、11个HTML页面、41个JS交互文件、20个CSS样式文件及76个GIF动图等资源整体大小79.34MB目录结构清晰含readme说明、SQL建表语句与初始化数据。目前已有145人学习下载提供可直接运行的完整工程含Bootstrap/Layui等主流前端库支持便于理解前后端协同机制与旅游行业数据可视化实践路径。1. 这不是又一个“爬完数据就扔”的旅游项目Flask 搭建的 Python 数据分析及可视化系统真正跑在本地能查、能筛、能导出、能二次开发你可能已经见过太多标着“旅游数据分析”的 GitHub 仓库——点进去requirements.txt里一堆包data/目录空着app.py里写着# TODO: 加载真实数据。这种“半成品式源码”对实际工作毫无帮助它既不能验证你刚学的 Pandas 分组聚合是否写对也无法让你快速改个图表配色去给业务方看。而本标题指向的这套Python 基于旅游网站的数据分析及可视化系统Flask核心价值在于它是一个可立即启动、带真实模拟数据流、前后端分离清晰、接口可调试、图表可交互、逻辑可打断点的最小可行系统。它不依赖线上 API 或未公开数据库所有数据加载、清洗、统计、渲染全部在本地完成它用 Flask 提供 Web 界面但后端逻辑完全独立于框架意味着你能把analysis.py拿出去直接跑在 Jupyter 或 Airflow 里它面向的是需要快速交付轻量级业务看板的 Python 工程师、数据分析师以及正在从脚本过渡到 Web 化分析工具的初学者。如果你正卡在“写完分析代码却不知道怎么让同事看到结果”或“想练 Flask 却苦于找不到有真实数据处理链路的项目”这套源码就是那个能让你当天下午就跑通、当晚就能改出自己城市旅游热度图的起点。2. 为什么选 Flask 而不是 Streamlit 或 Dash从路由设计到数据流闭环的底层逻辑2.1 Flask 的轻量可控性是旅游数据分析场景的天然匹配项旅游类数据分析通常具备三个典型特征数据源相对固定如某平台公开的景区评论、价格、评分、分析维度明确时间趋势、地域分布、情感倾向、价格区间占比、交付形态轻量内部看板、周报支撑、临时查询。Streamlit 适合快速原型但难以控制 URL 路由、无法精细管理会话状态、部署时静态资源路径易出错Dash 依赖 React 生态学习成本高小项目反而臃肿。Flask 则提供恰到好处的抽象它不强制 MVC 结构允许你把数据加载、清洗、计算封装成纯函数再通过简单路由暴露为 JSON 接口它原生支持模板继承让 ECharts 图表能复用同一套 HTML 骨架更重要的是它的中间件机制如app.before_request能自然嵌入数据预热逻辑——比如系统启动时自动读取并缓存清洗后的 CSV避免每次请求都重复 IO。本系统正是基于此设计app.py仅负责路由分发与模板渲染所有分析逻辑下沉至analysis/目录下的模块形成清晰的职责边界。2.2 数据流闭环从模拟数据生成到前端图表渲染的五步链路该系统并非直接抓取真实旅游网站涉及反爬与法律风险而是构建了一套可验证、可替换、带业务语义的模拟数据生成器。整个数据流严格遵循数据生成运行scripts/generate_sample_data.py按景区、时间、用户、评论四个维度生成符合现实分布的 CSV如北京故宫日均访问量服从泊松分布用户评分集中在 4.2–4.8评论情感词频匹配真实语料库数据加载与缓存Flask 启动时analysis/data_loader.py读取 CSV用 Pandas 构建DataFrame并存入全局变量g.data_cache注意生产环境应替换为 Redis但本地开发用内存足够分析计算analysis/metrics.py提供get_daily_trend(),get_region_distribution(),get_sentiment_score()等函数接收原始数据返回结构化字典非 JSON 字符串API 封装routes.py中定义/api/trend,/api/region,/api/sentiment等端点调用分析函数用jsonify()返回标准响应前端消费templates/index.html内嵌 ECharts通过fetch(/api/trend)获取数据调用chart.setOption()渲染。提示所有分析函数必须返回 Python 原生数据结构dict/list而非pd.DataFrame。ECharts 无法直接解析 DataFrame且jsonify()对 DataFrame 的序列化行为不稳定。正确做法是在函数内调用.to_dict(records)或手动构造字典。2.3 核心路由与接口设计让前端工程师也能看懂后端在做什么系统定义了 6 个关键接口全部采用 RESTful 风格路径与功能一一对应无需额外文档即可理解路径方法功能返回示例字段/GET主页含所有图表容器—/api/trendGET按日/周/月聚合的访问量趋势{date: [2024-01-01, ...], visits: [1240, 1350, ...]}/api/regionGET各省份景区数量与平均评分分布{province: [北京, 上海, ...], count: [12, 8, ...], avg_score: [4.6, 4.3, ...]}/api/price_rangeGET门票价格区间占比饼图{ranges: [0-50, 50-100, ...], percentages: [32.1, 45.7, ...]}/api/sentimentGET评论情感极性分布正面/中性/负面{sentiment: [positive, neutral, negative], count: [1240, 890, 320]}/export/csvPOST导出当前筛选条件下的原始数据需传filter_type参数{status: success, filename: export_20240520.csv}这些接口的设计原则是每个接口只做一件事参数尽量少返回结构扁平化。例如/api/trend不接受start_date和end_date参数因为趋势分析默认使用全量数据——若需时间筛选应在前端加日期控件由 JS 拼接新 URL 请求/api/trend?periodweek后端再解析 query string。这样既降低接口复杂度又让前端控制更灵活。3. 本地跑通最小可运行系统从安装依赖到打开首页的完整命令链3.1 环境准备与依赖安装避开 Python 版本与包冲突的三处关键点本系统要求 Python 3.8兼容性最佳推荐使用venv创建隔离环境。执行以下命令前请确认已安装pip且版本 ≥ 21.0旧版 pip 安装pandas可能失败# 创建虚拟环境Linux/macOS python -m venv tourism_env source tourism_env/bin/activate # Windows 用户请用 # python -m venv tourism_env # tourism_env\Scripts\activate.bat # 升级 pip关键避免 wheel 构建失败 pip install --upgrade pip # 安装核心依赖注意顺序先安装 numpy再装 pandas最后 flask pip install numpy1.24.4 pip install pandas2.0.3 pip install flask2.3.3 pip install matplotlib3.7.2 pip install jieba0.43.1 # 中文分词用于情感分析 pip install openpyxl3.1.2 # 支持 Excel 导出注意pandas2.0.3是经过实测的稳定版本。使用pandas2.1.0可能导致df.groupby().size()返回Series而非DataFrame进而使to_dict(records)报错。若你坚持用新版需在analysis/metrics.py中将groupby(...).size()替换为groupby(...).count().reset_index(namecount)。3.2 数据生成与服务启动两行命令完成全流程依赖安装完成后进入项目根目录即含app.py和scripts/的文件夹执行# 步骤1生成模拟数据首次运行必做后续可跳过 python scripts/generate_sample_data.py # 步骤2启动 Flask 开发服务器 flask --app app run --host0.0.0.0 --port5000 --debug此时终端将输出* Debug mode: on WARNING: This is a development server. Do not use it in production. * Running on http://0.0.0.0:5000打开浏览器访问http://localhost:5000即可看到包含折线图趋势、地图地域、饼图价格、柱状图情感的完整看板。所有图表数据均来自data/sample_data.csv该文件由generate_sample_data.py生成内容结构如下scenic_idscenic_nameprovincecitypricescorevisit_datecommentsentimentS001故宫博物院北京北京60.04.72024-01-01“建筑宏伟值得一看”positiveS002西湖风景区浙江杭州0.04.52024-01-01“免费开放风景很美。”positive提示price字段为0.0表示免费景区这是真实旅游数据中的常见情况。分析代码中需用df[price].replace(0, np.nan)处理避免影响均价计算。3.3 关键配置文件解读config.py中的 4 个必调参数系统通过config.py统一管理配置其中以下 4 项直接影响运行效果需根据本地环境调整import os class Config: # 1. 数据文件路径必须指向 generate_sample_data.py 生成的 CSV DATA_FILE_PATH os.path.join(os.path.dirname(__file__), data, sample_data.csv) # 2. 图表默认时间范围day/week/month影响趋势图横轴粒度 DEFAULT_TREND_PERIOD week # 3. 情感分析词典路径jieba 分词 自定义情感词典提升准确率 SENTIMENT_DICT_PATH os.path.join(os.path.dirname(__file__), data, sentiment_dict.txt) # 4. 导出文件保存目录确保该目录存在且有写权限 EXPORT_DIR os.path.join(os.path.dirname(__file__), exports) os.makedirs(EXPORT_DIR, exist_okTrue) # 自动创建目录若你将项目移到其他路径只需修改DATA_FILE_PATH若想让趋势图默认显示日粒度将DEFAULT_TREND_PERIOD改为day若要替换情感词典按sentiment_dict.txt格式每行一个词正向词前加负向词前加-准备新文件即可。4. 分析逻辑深度拆解Pandas 清洗、分组、聚合的 3 个实战陷阱与修复方案4.1 时间字段解析陷阱visit_date字符串转 datetime 的隐式错误原始 CSV 中visit_date为YYYY-MM-DD字符串直接pd.to_datetime(df[visit_date])在某些 Pandas 版本下会返回object类型而非datetime64导致后续groupby(pd.Grouper(keyvisit_date, freqW))失效。正确做法是显式指定格式并处理空值# analysis/data_loader.py 中的修复代码 def load_and_clean_data(): df pd.read_csv(Config.DATA_FILE_PATH) # 关键修复强制指定 format并用 errorscoerce 将非法日期转为 NaT df[visit_date] pd.to_datetime(df[visit_date], format%Y-%m-%d, errorscoerce) # 删除日期无效的行如空字符串或格式错误 df df.dropna(subset[visit_date]) return df提示errorscoerce比errorsignore更安全。后者会保留原始字符串导致groupby时按字符串排序而非时间排序图表横轴出现乱序。4.2 地域聚合陷阱province字段含空格与简繁体不一致问题模拟数据生成器虽尽力统一但真实数据常含“北京市”、“北京 ”尾部空格、“北京巿”繁体“巿”等变体。直接df.groupby(province).size()会导致同一省份被拆分为多组。解决方案是预处理标准化# analysis/metrics.py 中的标准化函数 def standardize_province(province_str): 清洗省份名称去空格、转简体、映射别名 if not isinstance(province_str, str): return 未知 # 去首尾空格合并连续空格 cleaned re.sub(r\s, , province_str.strip()) # 简繁转换需安装 opencc此处用简单映射 mapping {北京市: 北京, 上海市: 上海, 廣東省: 广东, 廣西省: 广西} return mapping.get(cleaned, cleaned) # 在数据加载后调用 df[province] df[province].apply(standardize_province)4.3 情感分析陷阱中文评论分词后需过滤停用词与无意义符号直接对评论jieba.lcut(comment)得到的词列表包含大量“的”、“了”、“啊”及标点若直接统计词频会淹没真实情感词。必须引入停用词表并过滤# analysis/sentiment_analyzer.py import jieba from collections import Counter STOPWORDS {的, 了, 在, 是, 我, 有, 和, 就, 不, 人, 都, 一, 一个, 上, 也, 很, 到, 说, 要, 去, 你, 会, 着, 没有, 看, 好, 自己, 这, 那, 他, 她, 它} def analyze_sentiment(comment): words jieba.lcut(comment.lower()) # 转小写统一处理 # 过滤停用词、单字、标点、数字 filtered_words [ w for w in words if w not in STOPWORDS and len(w) 1 and w.isalpha() ] # 统计词频仅用于调试实际情感打分用词典匹配 return Counter(filtered_words) # 使用示例获取高频词云数据 def get_top_keywords(df, top_n10): all_words [] for comment in df[comment]: all_words.extend(analyze_sentiment(comment).elements()) return Counter(all_words).most_common(top_n)此函数返回的most_common(10)可直接用于 ECharts 词云图避免出现“的的的”这种无效高频词。5. 可视化进阶技巧ECharts 动态主题切换与导出高清 PNG 的实战配置5.1 实现浅色/深色主题一键切换CSS 变量 ECharts 主题注入系统默认使用浅色主题但用户可能在夜间查看。通过 CSS 自定义属性Custom Properties与 ECharts 的setOption动态注入实现零刷新切换!-- templates/base.html -- head style :root { --bg-color: #ffffff; --text-color: #333333; --border-color: #e0e0e0; --chart-color: #1890ff; } .dark-theme { --bg-color: #1f1f1f; --text-color: #f0f0f0; --border-color: #333333; --chart-color: #52c418; } /style /head body button idtheme-toggle切换深色模式/button div idtrend-chart stylewidth:100%; height:400px;/div script const themeToggle document.getElementById(theme-toggle); const chartDom document.getElementById(trend-chart); let myChart echarts.init(chartDom, null, { renderer: canvas }); // 切换主题函数 function toggleTheme() { document.body.classList.toggle(dark-theme); // 重新设置图表 option注入新颜色 const newOption getBaseOption(); // 从全局函数获取基础配置 myChart.setOption(newOption, { replaceMerge: true }); } themeToggle.addEventListener(click, toggleTheme); // 基础配置含颜色绑定 function getBaseOption() { const root getComputedStyle(document.documentElement); return { backgroundColor: root.getPropertyValue(--bg-color), textStyle: { color: root.getPropertyValue(--text-color) }, tooltip: { trigger: axis }, xAxis: { type: category, axisLine: { lineStyle: { color: root.getPropertyValue(--border-color) } } }, yAxis: { type: value, axisLine: { lineStyle: { color: root.getPropertyValue(--border-color) } } }, series: [{ type: line, itemStyle: { color: root.getPropertyValue(--chart-color) } }] }; } /script /body此方案无需加载多个 ECharts 主题文件所有颜色由 CSS 变量驱动维护成本低且兼容所有图表类型。5.2 导出高清 PNG绕过浏览器截图限制的 Canvas 提升方案myChart.getDataURL({type: png, pixelRatio: 2})在高分屏下仍可能模糊。终极方案是利用 ECharts 的renderToCanvas方法手动创建高分辨率 canvas// templates/index.html 中的导出函数 function exportHighResPNG() { const chartDom document.getElementById(trend-chart); const myChart echarts.getInstanceByDom(chartDom); // 获取原始尺寸 const width chartDom.clientWidth; const height chartDom.clientHeight; // 创建 2 倍分辨率 canvas const canvas document.createElement(canvas); canvas.width width * 2; canvas.height height * 2; canvas.style.width ${width}px; canvas.style.height ${height}px; // 渲染到高分 canvas myChart.renderToCanvas(canvas, { width: width * 2, height: height * 2, devicePixelRatio: 2 }); // 触发下载 const link document.createElement(a); link.download trend_chart_${Date.now()}.png; link.href canvas.toDataURL(image/png); link.click(); }调用此函数生成的 PNG 在 4K 屏幕上依然清晰锐利且文件大小可控toDataURL默认压缩如需无损可改用canvas.toBlob()。5.3 旅游数据特有的可视化增强地图散点图叠加景区等级标签标准 ECharts 地图如china.js仅支持省级轮廓而旅游分析需定位到具体景区。本系统采用GeoJSON 散点图 自定义标签方案# analysis/metrics.py 中生成地图数据 def get_scenic_geo_data(): # 从 data/scenic_locations.json 加载景区经纬度格式[name, lng, lat, level] with open(data/scenic_locations.json, r, encodingutf-8) as f: locations json.load(f) # 按等级分组5A/4A/3A返回三组数据 level_groups {5A: [], 4A: [], 3A: []} for name, lng, lat, level in locations: if level in level_groups: level_groups[level].append({ name: name, value: [lng, lat, 1], # value[2] 为 size统一设为 1 level: level }) return level_groups前端 ECharts 配置中为每组数据设置不同 symbolSize 和 labelseries: [ { name: 5A级景区, type: scatter, coordinateSystem: geo, symbolSize: 12, label: { show: true, formatter: {b}, fontSize: 12 }, data: geoData[5A] }, { name: 4A级景区, type: scatter, coordinateSystem: geo, symbolSize: 8, label: { show: false }, // 4A 级隐藏标签避免遮挡 data: geoData[4A] } ]此方案让地图不仅显示分布密度更直观传达景区质量层级是旅游数据分析中最具业务价值的可视化增强点。本文还有配套的精品资源点击获取
返回列表