Streamlit 入门:用 Python 快速搭数据看板与内部工具
之前做数据分析相关的小需求时,经常遇到一种情况:模型或 SQL 已经跑通了,业务方要的是「能点一点、能看图」的界面,而不是再要一份 Jupyter 笔记本。用 React + 后端从零搭一套,周期往往比分析本身还长。后来试了 Streamlit,发现用纯 Python 就能把交互页面拉起来,适合原型、内部工具和轻量看板。这篇把入门路径和几个常见场景整理一下,附带可以直接跑的实战代码。
Streamlit 是什么
Streamlit 是一个面向数据应用的 Python 框架。你写普通的 Python 脚本,用 st.button、st.slider 这类 API 描述界面,保存后执行 streamlit run app.py,浏览器里就会出现可交互页面。
和常见方案的大致对比:
| 方案 | 适合什么 | 不太适合什么 |
|---|---|---|
| Streamlit | 快速原型、内部看板、模型演示 | 复杂权限、多页面 SPA、精细 UI |
| Dash / Plotly | 偏图表、回调式交互 | 非数据类业务后台 |
| Flask/FastAPI + 前端 | 正式产品、定制交互 | 一两天内要出界面 |
| Jupyter + Voila | 已有笔记本、科研分享 | 长期维护的内部系统 |
核心特点可以概括成三点:
- 脚本即应用:没有传统前后端分离那套工程骨架,改代码、刷新页面就能看到变化。
- 组件丰富:表单、图表、文件上传、表格、地图等都有封装,和 Pandas、Matplotlib、Plotly 配合比较顺。
- 部署简单:本地一条命令;上线可以用 Streamlit Community Cloud、Docker,或丢到公司内网服务器。
需要注意的边界:它不是通用 Web 框架。多用户权限、复杂路由、像素级 UI 定制,建议还是走 FastAPI + 前端,或者把 Streamlit 当「内部工具层」而不是对外产品。
环境准备与第一个页面
安装
pip install streamlit pandas matplotlib建议单独建虚拟环境,避免和别的项目依赖打架。项目里可以再加 requirements.txt:
streamlit>=1.30
pandas>=2.0
matplotlib>=3.8最小可运行示例 — 保存为 hello.py:
import streamlit as st
st.set_page_config(page_title="Hello Streamlit", page_icon="📊", layout="wide")
st.title("第一个 Streamlit 应用")
name = st.text_input("你的名字")
if name:
st.write(f"你好,{name}!")
age = st.slider("年龄", min_value=18, max_value=80, value=25)
st.info(f"你选择了 {age} 岁")终端执行:
streamlit run hello.py默认会打开 http://localhost:8501。改 .py 文件并保存后,页面右上角可以选「Always rerun」,代码变更会自动刷新——这是开发时很省时间的一点。
核心概念:跑通一个应用要懂什么
1. 执行模型
Streamlit 从上到下整脚本重跑(rerun)。用户点按钮、拖滑块,都会触发脚本重新执行。所以:
- 耗时的数据加载要配合
@st.cache_data或@st.cache_resource缓存。 - 需要在多次 rerun 之间保留的状态,放进
st.session_state。
import streamlit as st
import pandas as pd
@st.cache_data
def load_data():
# 模拟慢查询:只会在首次或参数变化时执行
return pd.read_csv("https://raw.githubusercontent.com/plotly/datasets/master/iris.csv")
df = load_data()
st.dataframe(df.head())cache_data 适合 DataFrame、计算结果;cache_resource 适合数据库连接、模型对象这类不可序列化资源。
2. 布局
col1, col2, col3 = st.columns([1, 2, 1])
with col1:
st.metric("用户数", "1,204", "+12%")
with col2:
st.line_chart([1, 3, 2, 5, 4])
with col3:
st.button("导出")
with st.sidebar:
st.header("筛选")
region = st.selectbox("区域", ["华东", "华南", "华北"])layout="wide" 适合看板;侧边栏放筛选条件,主区域放图表,是常见套路。
3. Session State
按钮计数、多步表单、登录态雏形,都依赖 session state:
import streamlit as st
if "count" not in st.session_state:
st.session_state.count = 0
if st.button("点我 +1"):
st.session_state.count += 1
st.write(f"当前计数:{st.session_state.count}")没有 session state 的话,每次 rerun 变量都会归零,交互逻辑很难写。
4. 常用组件速查
| 组件 | 典型用途 |
|---|---|
st.file_uploader | 上传 CSV/Excel,做临时分析 |
st.selectbox / st.multiselect | 维度筛选 |
st.date_input | 时间范围 |
st.dataframe / st.data_editor | 表格展示与轻量编辑 |
st.pyplot / st.plotly_chart | 绑图 |
st.download_button | 导出处理结果 |
st.tabs | 同一页多视图 |
st.expander | 折叠高级选项 |
应用场景:什么时候值得用
1. 数据分析看板
运营、产品、老板要看的指标,数据源往往是 MySQL、ClickHouse 或定时导出的 CSV。用 Streamlit 包一层查询 + 图表,比每周手工做 Excel 省事。
适合:日活、转化漏斗、库存、客服工单统计等读多写少的场景。
2. 机器学习 / 算法演示
训练好的 sklearn、PyTorch 模型,需要给非技术同事试输入、看输出。Streamlit 上传图片、填特征、点「预测」,几分钟能搭 demo,答辩或评审时很实用。
3. 内部运维与配置工具
例如:批量改配置预览、日志关键词检索、一次性数据修复前的「先预览再执行」。权限控在内网即可,不必上完整后台。
4. 快速验证产品想法
新功能要不要做,先拿假数据或抽样数据做个可点击原型,比静态 PPT 更有说服力。验证完了再决定是否投入正式前后端开发。
不太建议 sole 用 Streamlit 的情况
- 面向 C 端用户、要强品牌 UI 的产品页
- 复杂 RBAC、审计日志、工作流审批
- 高并发写入(Streamlit 更偏展示与轻交互,不是高吞吐 API 服务)
实战一:销售数据看板(CSV + 筛选 + 图表)
下面是一个完整单文件示例,不依赖外部数据库。把代码保存为 sales_dashboard.py,同目录放一份 sales.csv(或让脚本自动生成示例数据)。
import streamlit as st
import pandas as pd
import matplotlib.pyplot as plt
st.set_page_config(page_title="销售看板", layout="wide")
@st.cache_data
def get_sales_data():
# 若没有本地文件,生成示例数据
try:
return pd.read_csv("sales.csv", parse_dates=["date"])
except FileNotFoundError:
import numpy as np
rng = pd.date_range("2025-01-01", periods=90, freq="D")
regions = np.random.choice(["华东", "华南", "华北"], size=90)
amounts = np.random.randint(800, 5000, size=90)
return pd.DataFrame({"date": rng, "region": regions, "amount": amounts})
df = get_sales_data()
st.title("区域销售看板")
with st.sidebar:
st.header("筛选")
regions = st.multiselect("区域", sorted(df["region"].unique()), default=list(df["region"].unique()))
date_range = st.date_input(
"日期范围",
value=(df["date"].min().date(), df["date"].max().date()),
)
mask = df["region"].isin(regions)
if len(date_range) == 2:
start, end = pd.Timestamp(date_range[0]), pd.Timestamp(date_range[1])
mask &= (df["date"] >= start) & (df["date"] <= end)
filtered = df.loc[mask]
col1, col2, col3 = st.columns(3)
col1.metric("总销售额", f"¥{filtered['amount'].sum():,.0f}")
col2.metric("日均", f"¥{filtered.groupby('date')['amount'].sum().mean():,.0f}")
col3.metric("记录数", len(filtered))
st.subheader("趋势")
daily = filtered.groupby("date", as_index=False)["amount"].sum()
st.line_chart(daily, x="date", y="amount")
st.subheader("区域占比")
region_sum = filtered.groupby("region")["amount"].sum()
fig, ax = plt.subplots()
region_sum.plot(kind="bar", ax=ax, color="#4C78A8")
ax.set_ylabel("销售额")
st.pyplot(fig)
st.subheader("明细")
st.dataframe(filtered.sort_values("date", ascending=False), use_container_width=True)
csv_bytes = filtered.to_csv(index=False).encode("utf-8-sig")
st.download_button("下载筛选结果", csv_bytes, "filtered_sales.csv", "text/csv")运行:
streamlit run sales_dashboard.py这个例子覆盖了:缓存、侧边栏筛选、metric 卡片、折线图、Matplotlib 柱状图、表格导出。实际项目里把 get_sales_data 换成 pd.read_sql 或调用内部 API 即可。
实战二:上传 CSV 做临时分析
业务同事经常丢一份 Excel 过来问「帮我看看异常值」。用上传组件可以在不写死文件路径的情况下处理:
import streamlit as st
import pandas as pd
st.title("CSV 快速分析")
uploaded = st.file_uploader("上传 CSV", type=["csv"])
if uploaded is None:
st.stop()
df = pd.read_csv(uploaded)
st.write(f"共 {len(df)} 行,{len(df.columns)} 列")
st.dataframe(df.head(20))
numeric_cols = df.select_dtypes("number").columns.tolist()
if not numeric_cols:
st.warning("没有数值列,无法做统计")
st.stop()
col = st.selectbox("选择分析列", numeric_cols)
c1, c2 = st.columns(2)
with c1:
st.write("描述统计")
st.write(df[col].describe())
with c2:
st.write("分布")
st.bar_chart(df[col].value_counts().head(20))
threshold = st.number_input("异常阈值(大于此值标红)", value=float(df[col].quantile(0.95)))
outliers = df[df[col] > threshold]
st.subheader(f"超过 {threshold} 的记录({len(outliers)} 条)")
st.dataframe(outliers)st.stop() 可以在没有上传文件时提前结束脚本,避免下面代码报错——这种写法在 Streamlit 里很常见。
实战三:简单预测 Demo(sklearn)
假设你有一个训练好的分类模型,想给同事试用:
import streamlit as st
import pandas as pd
from sklearn.datasets import load_iris
from sklearn.ensemble import RandomForestClassifier
import joblib
st.title("鸢尾花分类 Demo")
@st.cache_resource
def load_model():
iris = load_iris()
X, y = iris.data, iris.target
model = RandomForestClassifier(n_estimators=50, random_state=42)
model.fit(X, y)
return model, iris.target_names, iris.feature_names
model, target_names, feature_names = load_model()
st.write("输入四个特征,点击预测:")
cols = st.columns(4)
values = []
for i, name in enumerate(feature_names):
with cols[i]:
values.append(st.number_input(name, value=5.0))
if st.button("预测"):
pred = model.predict([values])[0]
proba = model.predict_proba([values])[0]
st.success(f"预测类别:**{target_names[pred]}**")
st.bar_chart(pd.Series(proba, index=target_names))生产环境会把 load_model 改成 joblib.load("model.pkl"),特征输入也可以从上传的 CSV 批量预测。演示和评审够用了。
多页面与项目结构
单文件写到 300 行以上就开始难维护。Streamlit 支持 multipage app:在项目里建 pages/ 目录,每个文件自动变成侧边导航的一项。
my_app/
├── app.py # 首页
├── pages/
│ ├── 1_概览.py
│ ├── 2_明细.py
│ └── 3_设置.py
├── utils/
│ └── data.py # 共用查询、缓存函数
└── requirements.txtapp.py 里放总览和公共 set_page_config;utils/data.py 集中放 @st.cache_data 的数据加载,避免每个页面重复查库。
文件名前的数字控制排序,1_、2_ 这种前缀是官方约定。
部署与协作上的一点经验
本地给同事试用:同一局域网内,启动时加:
streamlit run app.py --server.address 0.0.0.0 --server.port 8501同事访问 http://你的IP:8501。内网工具够用了,别直接暴露公网。
Docker(简化版):
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8501
CMD ["streamlit", "run", "app.py", "--server.address", "0.0.0.0", "--server.port", "8501"]和正式系统的关系:我一般会把它定位成「分析层 / 工具层」——数据仍由数仓或 API 提供,Streamlit 只负责展示和轻量操作;真要对外发布、要 SLA 的服务,再迁到标准 Web 栈。
常见问题
Q:改代码后页面没变化?
看右上角是否开启 rerun;有时浏览器缓存,强刷一下。若用了 @st.cache_data,改的是被缓存函数内部的逻辑,需要清缓存(菜单 Clear cache)或改函数参数。
Q:为什么我的变量在按钮里更新了,下次又没了?
用 st.session_state,不要指望普通局部变量在 rerun 之间保留。
Q:能接 MySQL 吗?
可以,sqlalchemy + pandas.read_sql,查询函数加 @st.cache_data(ttl=300) 控制缓存五分钟,避免每次拖动滑块都打库。
Q:和 Gradio 怎么选?
Gradio 更偏「模型输入输出」几屏搞定;Streamlit 更偏「多图表、多筛选的数据应用」。做 LLM 聊天 Demo 两者都能做,看团队更熟哪个。
写在最后
Streamlit 解决的不是「做一个完整互联网产品」,而是「让 Python 手头的分析结果尽快变成可点的界面」。内部看板、评审 Demo、一次性数据处理,这几个场景我用得最多。若你已经在用 Pandas 或 sklearn,上手成本很低,建议从一个真实小需求开始——比如把上周那份 CSV 报告换成可筛选的页面,比照着文档抄 hello world 更有体感。
