查看: 3943|回复: 3

Streamlit构建交互式Web应用实战:控件缓存与销售看板

[复制链接]
发表于 2026-9-28 10:00:00 | 显示全部楼层 |阅读模式
为什么用 Streamlit 把 Python 脚本变成 Web 应用
很多 Python 工程师用 pandas 分析、matplotlib 画图后,只能截图或放 Jupyter Notebook。要让别人打开网页使用,通常要补 HTML/CSS/JavaScript 和 Flask/Django 后端。Streamlit 的目标是让开发者只用 Python 写交互式 Web 应用,不用前端代码,保存脚本后页面自动热更新。它适合数据分析师、算法工程师、运维人员把脚本快速变成可分享原型。

环境准备与版本验证
Streamlit 是纯 Python 库,支持 Python 3.8+。建议虚拟环境隔离:
  1. python -m venv .venv
  2. source .venv/bin/activate  # Windows 使用对应 Scripts 目录下的 activate
  3. pip install streamlit
复制代码
验证安装:
  1. # check_version.py
  2. import streamlit as st
  3. # 打印当前 Streamlit 版本,确认安装成功
  4. print('Streamlit 版本:', st.__version__)
复制代码
执行 streamlit run check_version.py,会启动本地服务并自动打开浏览器,默认地址 http://localhost:8501。后续示例都使用该端口。

最小可运行示例与重跑机制
  1. # app.py
  2. import streamlit as st
  3. st.title('我的第一个 Streamlit 应用')
  4. st.write('你好,这是用纯 Python 写出来的网页!')
  5. age = st.slider('请选择你的年龄', 0, 120, 25)
  6. st.write('你选择的年龄是:', age)
复制代码
运行 streamlit run app.py。拖动滑块时数字立即变化。关键机制是:每次交互,整个脚本会从上到下重新执行,Streamlit 再把新输出映射到界面。理解这一点对后面处理状态和缓存很重要。

控件、布局、会话状态与缓存
输入控件会返回当前值:
  1. name = st.text_input('你的名字', '张三')
  2. agree = st.checkbox('我同意条款')
  3. option = st.selectbox('选择城市', ['北京', '上海', '广州'])
  4. clicked = st.button('点我提交')
复制代码
布局方面,st.sidebar 放侧边栏,st.columns 做并排:
  1. st.sidebar.title('筛选条件')
  2. threshold = st.sidebar.slider('阈值', 0, 100, 50)
  3. col1, col2 = st.columns(2)
  4. col1.metric('销量', 1280)
  5. col2.metric('增长率', '12%')
复制代码
脚本每次重跑,普通变量不会跨重跑保存。需要 st.session_state:
  1. if 'count' not in st.session_state:
  2.     st.session_state.count = 0
  3. if st.button('加一'):
  4.     st.session_state.count += 1
  5. st.write('当前计数:', st.session_state.count)
复制代码
加载大文件或训练模型很慢时,用 @st.cache_data 按入参缓存函数结果:
  1. @st.cache_data
  2. def load_data(path):
  3.     import pandas as pd
  4.     return pd.read_csv(path)
复制代码

文件上传与图表联动
Streamlit 对 pandas、matplotlib、Plotly 等生态原生友好。上传 CSV、出图、滑块过滤的组合:
  1. import pandas as pd
  2. import streamlit as st
  3. uploaded = st.file_uploader('上传一个 CSV 文件', type='csv')
  4. if uploaded is not None:
  5.     df = pd.read_csv(uploaded)
  6.     st.dataframe(df.head(20))
  7.     numeric_cols = df.select_dtypes('number').columns.tolist()
  8.     if numeric_cols:
  9.         col = st.selectbox('选择要画图的数值列', numeric_cols)
  10.         top_n = st.slider('显示前 N 行', 5, 50, 10)
  11.         st.line_chart(df[col].head(top_n))
复制代码
如果用 matplotlib:
  1. import matplotlib.pyplot as plt
  2. fig, ax = plt.subplots()
  3. ax.hist(df[col], bins=20)
  4. st.pyplot(fig)
复制代码

实战:迷你销售看板完整代码
  1. # dashboard.py
  2. import pandas as pd
  3. import streamlit as st
  4. @st.cache_data
  5. def load_data(uploaded_file):
  6.     return pd.read_csv(uploaded_file)
  7. st.set_page_config(page_title='销售看板', layout='wide')
  8. st.title('迷你销售看板')
  9. uploaded = st.file_uploader('上传销售数据 CSV(需含 city、amount、date 列)', type='csv')
  10. if uploaded is None:
  11.     st.info('请先上传一个 CSV 文件开始使用。')
  12.     st.stop()
  13. df = load_data(uploaded)
  14. df['date'] = pd.to_datetime(df['date'])
  15. cities = st.sidebar.multiselect(
  16.     '选择城市',
  17.     df['city'].unique(),
  18.     default=list(df['city'].unique())[:3]
  19. )
  20. filtered = df[df['city'].isin(cities)]
  21. col1, col2 = st.columns(2)
  22. total = filtered['amount'].sum()
  23. col1.metric('总销售额', f'{total:,.0f}')
  24. col2.metric('订单数', len(filtered))
  25. st.subheader('销售额趋势')
  26. st.line_chart(filtered.set_index('date')['amount'].resample('D').sum())
  27. st.subheader('城市汇总')
  28. st.dataframe(filtered.groupby('city')['amount'].sum().reset_index())
复制代码
运行 streamlit run dashboard.py,上传包含 city、amount、date 列的 CSV,即可得到一个可筛选、可联动的销售看板。代码里 st.stop() 用于没有上传文件时停止后续渲染,@st.cache_data 避免重复解析同一上传文件。

常见报错与排查
坑 1:ModuleNotFoundError: No module named 'streamlit'
原因:安装环境和运行环境不是同一个 Python;或者根本没安装。解决:核对 which python、pip show streamlit 的路径,虚拟环境下先 activate 再运行。
坑 2:端口 8501 被占用,自动跳到 8502/8503
启动时可能提示 Port 8501 is already in use, trying 8502。原因通常是上次服务未关闭。解决:关闭旧进程,或显式指定端口:
  1. streamlit run app.py --server.port 8503
复制代码
坑 3:点击 st.button 后状态没记住
按钮点击只在当次重跑返回 True,之后会重置,普通变量无法跨重跑保存。解决:用 st.session_state 持久化,或用 st.checkbox、st.toggle 这类天然带状态的控件替代。

下一步
需要缓存数据库连接或机器学习模型时,可以使用 @st.cache_resource;需要多页面时,把页面拆到 pages/ 目录;需要分享时,可用 Streamlit Community Cloud 免费托管。把现有 pandas 脚本外面套一层 st.,就能快速得到第一个数据应用。
回复

使用道具 举报

发表于 2026-9-28 19:00:00 | 显示全部楼层

Re: Streamlit构建交互式Web应用实战:控件缓存与销售看板

感谢分享,这篇从最小示例一路讲到缓存和销售看板,思路很清楚,尤其把脚本重跑机制单独拎出来讲很关键。很多人第一次用 Streamlit 时,拖一下滑块发现整个脚本又跑一遍,容易懵,理解 session_state 和 @st.cache_data 后就顺多了。销售看板里侧边栏多选城市、两列 metric 展示总额和订单数,这个组合也很实用。 一个小建议:@st.cache_data 如果直接缓存 file_uploader 返回的对象,最好在函数里先取 uploaded_file.getvalue() 再用 BytesIO 读,或者把文件字节内容作为参数传进去,这样不同 CSV 不容易串缓存,也能避免文件指针位置带来的问题。另外上传后可以先校验 city、amount、date 这几列是否齐全,缺列时用提示信息拦住,而不是让 pandas 直接报错,用户体验会更好。 首帖最后好像截断在 st.subhe,期待把后面的图表联动和完整看板部分补全。
回复 支持 反对

使用道具 举报

发表于 2026-9-28 19:10:00 | 显示全部楼层

Re: Streamlit构建交互式Web应用实战:控件缓存与销售看板

这篇挺适合当 Streamlit 入门实战,把“每次交互脚本会从上到下重跑”和 session_state、cache_data 放在一起讲,确实能帮新手少踩很多坑。销售看板的思路也很顺,上传 CSV、缓存读取、侧边栏多选城市、两列指标卡,基本能直接套到自己的数据上。 有两个小地方可以再稳一点:一是 file_uploader 返回的对象在重跑时不一定稳定,@st.cache_data 直接缓存 uploaded_file 可能命中不了,改成缓存 uploaded_file.getvalue() 或先解析成 DataFrame 再缓存会更可靠;二是看板里直接取 city、amount、date,如果用户传的 CSV 列名不对会直接报错,可以先检查列名,再用 st.error 提示需要这几列,日期解析也可以加 errors='coerce' 并过滤无效行。这样体验会更好。最后代码到 st.subhe 那里好像还没贴完,如果后面还有分组图表,期待补全。
回复 支持 反对

使用道具 举报

发表于 2026-9-28 19:20:00 | 显示全部楼层

Re: Streamlit构建交互式Web应用实战:控件缓存与销售看板

感谢分享,写得挺系统,从环境准备、最小示例到控件、布局、会话状态和缓存,再到文件上传和销售看板,基本把 Streamlit 做数据应用的主线串起来了。最认同的一点是把“每次交互整个脚本重新执行”单独强调出来,这个机制不弄清楚,后面用 session_state 和 cache_data 很容易踩坑。销售看板那段也很实用,侧边栏多选城市、两列指标卡、上传 CSV 后过滤和展示,都是很常见的看板需求,st.stop() 的用法也很干净。 不过结尾好像停在 st.subhe,感觉后面应该还有按日期或城市分组的图表没写完?如果继续补,建议加上 CSV 缺列或 date 解析失败时的友好提示,再顺带说明一下 cache_data 对上传文件的缓存行为,这样别人换文件测试时不容易被旧缓存绕进去。整体很有帮助,收藏了。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

指导单位

江苏省公安厅

江苏省通信管理局

浙江省台州刑侦支队

DEFCON GROUP 86025

Hacking Group 021A

旗下站点

态势感知中心

应急响应中心

红盟安全

联系我们

官方QQ群:112851260

官方邮箱:security#ihonker.org(#改成@)

官方核心成员

关注微信公众号

Archiver|手机版|小黑屋| ( 沪ICP备2021026908号 )

GMT+8, 2026-10-14 10:56 , Processed in 0.063269 second(s), 17 queries , Gzip On, Redis On.

Powered by ihonker.com

Copyright © 2015-现在.

  • 返回顶部