一个神奇的 Python 库:Streamlit,把脚本秒变 Web 应用

原创 老朱 程序员老朱 2026年6月24日 18:17 湖南 听全文

下面是一个简单数据分析:

df = pd.read_csv("销售数据.csv")
result = df.groupby("地区").agg({"销售额": "sum", "利润": "mean"})
print(result)

输出:

图片

但这个输出内容你怎么给你的老板看呢?截图通过微信发给你老板?

实际上他想要一个能打开的链接、能筛选的日期、能下载的表格,一个可视化界面。

这不是你一个人的困境。每一个做数据分析的 Python 开发者都卡在「分析能力满分,交付能力零分」的断层上——你能写出复杂的数据管道,但没法让业务方自己探索数据。

「Streamlit 就是为填这个断层而生的。」 它的设计哲学非常简单:你只需要写 Python,它帮你生成 Web 界面。

上面代码仅需简单改造就能变成一个漂亮的 Web 应用:

import streamlit as st
import pandas as pd

st.title("销售数据看板")

df = pd.read_csv("销售数据.csv")
st.dataframe(df)        # 可排序、可筛选的交互式表格
st.bar_chart(df.groupby("地区")["销售额"].sum())

通过下面shell安装、运行

pip install streamlit     # 安装
streamlit run app.py      # 运行

浏览器自动打开 http://localhost:8501。 你看到的不是一个终端输出,而是一个「完整的 Web 应用」——有标题、有表格(可以点击列头排序)、有柱状图。你没写一行 HTML。

图片

一、Streamlit 是什么?

Streamlit 是一个开源的 Python 库,能够让你「纯用 Python 代码」快速构建和分享数据 Web 应用。不需要 HTML、CSS 或 JavaScript,几分钟就能把一个 Python 脚本变成可交互的网页应用。

它尤其适合数据科学家、机器学习工程师和需要快速做原型演示的开发者。 你写的是线性 Python 脚本,但它呈现的是一个有状态的交互式 Web 应用。

二、安装

环境要求:Python 3.8 ~ 3.13。

pip install streamlit

安装完成后,验证是否成功:

streamlit hello

这会启动一个本地服务,并在浏览器中打开 Streamlit 的官方演示页面。

图片

三、第一个应用

创建一个 app.py 文件:

import streamlit as st
import pandas as pd
import numpy as np

st.title("我的第一个 Streamlit 应用")
st.write("Hello, Streamlit!")

# 生成一些随机数据并绘制折线图
chart_data = pd.DataFrame(
    np.random.randn(20, 3),
    columns=["A", "B", "C"]
)

st.line_chart(chart_data)

在终端中运行:

streamlit run app.py

图片

四、常用组件详解

4.1 文本组件

文本组件负责将信息直观地呈现给用户。不同于普通的 print(),Streamlit 的文本组件会渲染在浏览器中,并支持丰富的格式和层级结构。

st.title("这是一级标题")         # 最大号标题
st.header("这是二级标题")        # 中号标题
st.subheader("这是三级标题")     # 小号标题
st.markdown("支持 **Markdown** 语法")
st.text("纯文本内容")
st.code("print('Hello')", language="python")  # 代码块,带语法高亮
st.caption("这是一段说明性小字")
st.latex(r"e^{i\pi} + 1 = 0")   # LaTeX 公式

输出:

图片

4.2 数据展示

数据展示组件是 Streamlit 作为数据分析工具的核心优势。它们不仅展示数据,还提供了交互能力,帮助用户快速洞察规律。

data = {
    "姓名": ["张三", "李四", "王五"],
    "年龄": [25, 30, 28],
    "城市": ["北京", "上海", "广州"]
}
df = pd.DataFrame(data)
st.dataframe(df)           # 可交互的表格(支持排序、缩放)
st.table(df)               # 静态表格
st.json(data)  # JSON 格式化展示
st.metric("温度", "24°C", delta="1.5°C")  # 指标卡片,delta 表示变化量

输出: 

图片

4.3 图表组件

Streamlit 内置了几种常用图表,也支持 Matplotlib、Plotly、Altair 等第三方图表库。

import pandas as pd
import numpy as np
import streamlit as st
data = {
    "姓名": ["张三", "李四", "王五"],
    "年龄": [25, 30, 28],
    "城市": ["北京", "上海", "广州"],
    "薪资": [15000, 18000, 16000]
}
df = pd.DataFrame(data)

# st.map 需要 latitude / longitude 列(或 lat / lon)
location_data = pd.DataFrame({
    "latitude":  [39.9042, 31.2304, 23.1291, 22.5431, 30.5728],
    "longitude": [116.4074, 121.4737, 113.2644, 114.0579, 104.0668],
    "city":      ["北京", "上海", "广州", "深圳", "成都"]
})


import matplotlib.pyplot as plt

# 内置图表(基于 Altair)
# 只选数值列做图表,避免字符串列报错
df_chart = df.set_index("姓名")[["年龄", "薪资"]]
st.line_chart(df_chart)      # 折线图
st.area_chart(df_chart)      # 面积图
st.bar_chart(df_chart)       # 柱状图
st.scatter_chart(df, x="年龄", y="薪资") # 散点图
st.map(location_data)         # 地图(需 latitude/longitude 列)

# Matplotlib
fig, ax = plt.subplots()
ax.plot([1, 2, 3], [1, 4, 2])
st.pyplot(fig)

# Plotly(交互式图表)
import plotly.express as px
fig = px.scatter(df, x="年龄", y="薪资")
st.plotly_chart(fig, use_container_width=True)

产生多种图表, 输出:

图片

4.4 输入组件

输入组件是 Streamlit 的灵魂。用户每次操作控件(如滑动、点击、输入),整个 Python 脚本都会从上到下重新执行,变量值自动更新为控件当前状态。这种 “数据流驱动” 的模式极大地简化了后端逻辑。

# 文本输入
name = st.text_input("请输入你的名字", value="")
password = st.text_input("请输入密码", type="password")
comment = st.text_area("请输入评论", height=150)

# 数字输入
age = st.number_input("请输入年龄", min_value=0, max_value=150, value=25, step=1)
score = st.slider("评分", min_value=0.0, max_value=10.0, value=5.0, step=0.5)

# 选择类
option = st.selectbox("选择城市", ["北京", "上海", "广州", "深圳"])
options = st.multiselect("选择爱好", ["阅读", "运动", "音乐", "旅游"], default=["阅读"])
checked = st.checkbox("我同意条款")
color = st.color_picker("选择颜色", "#00FFAA")

# 日期与时间
date = st.date_input("选择日期")
time = st.time_input("选择时间")

# 文件上传
uploaded_file = st.file_uploader("上传文件", type=["csv", "txt", "png", "jpg"])

# 按钮
if st.button("点击我"):
    st.success(f"你好,{name}!")

# 下载按钮
st.download_button(
    label="下载 CSV",
    data=df.to_csv(index=False).encode("utf-8"),
    file_name="data.csv",
    mime="text/csv"
)

输出:

图片

4.5 状态与反馈

优秀的应用不仅功能完备,还应该给用户清晰的操作反馈。Streamlit 提供了一套完整的反馈机制,涵盖成功、提示、警告、错误和进度追踪。

st.success("操作成功!")        # 绿色提示条
st.info("这是一条信息提示")     # 蓝色提示条
st.warning("请注意!")          # 黄色警告条
st.error("出错了!")            # 红色错误条

# 进度条与等待
with st.spinner("处理中,请稍候..."):
    time.sleep(2)
st.success("完成!")

progress_bar = st.progress(0)
for i in range(100):
    time.sleep(0.01)
    progress_bar.progress(i + 1)

# 吐司通知
st.toast("任务已完成!", icon="🎉")

# 全局异常捕获
try:
    1 / 0
except Exception as e:
    st.exception(e)    # 展开显示完整的 traceback

输出:

图片

4.6 布局组件

默认情况下,Streamlit 组件按顺序垂直排列。布局组件让你能够像画板一样自由组织页面结构,将应用从“长文档”升级为“仪表盘”。

# 侧边栏
with st.sidebar:
    st.header("侧边栏")
    option = st.radio("导航", ["首页", "数据", "关于"])

# 列布局
col1, col2, col3 = st.columns(3)
with col1:
    st.metric("收入", "¥12,000", "8%")
with col2:
    st.metric("支出", "¥5,800", "-12%")
with col3:
    st.metric("净利润", "¥6,200", "21%")

# 容器
container = st.container(border=True)
container.write("这是带边框的容器")

# 可展开区域
with st.expander("点击查看详情"):
    st.write("这里是详细内容")

# 多标签页
tab1, tab2, tab3 = st.tabs(["概况", "图表", "数据"])
with tab1:
    st.write("概况页面内容")
with tab2:
    st.line_chart(np.random.randn(30, 3))
with tab3:
    st.dataframe(df)

输出:

图片

4.7 缓存与性能

理解 Streamlit 的执行模型(每次交互全量重跑)是性能优化的前提。如果没有缓存,每次滑块拖动或按钮点击都会重新加载几十 MB 的 CSV 或重新训练模型,应用会变得极其卡顿。

@st.cache_data 会缓存函数返回值,脚本重新运行时如果参数未变则直接返回缓存结果,避免重复加载数据或重复计算。

# 告诉 Streamlit:如果 URL 没变,就不重新读取
@st.cache_data  
def load_data(url):
    # 模拟耗时加载,实际项目中为 pd.read_csv(url)
    return pd.read_csv(url)

# 第一次运行会下载并缓存,后续滑块变动时直接返回缓存
df = load_data("https://example.com/large-dataset.csv")

# 带 TTL 的缓存(适用于动态数据)
@st.cache_data(ttl=600)  # 10 分钟后自动刷新
def fetch_live_data():
    return requests.get("https://api.example.com/live").json()

五、会话状态(Session State)

为什么需要会话状态?

Streamlit 的“重跑”机制虽然简化了逻辑,但也带来了一个棘手问题:本地变量会在每次交互后重置。比如你写了一个 count = 0,点击按钮 count += 1,页面刷新后 count 又被设回 0。这就无法实现“计数器”、“购物车”、“多步骤表单向导”等需要跨交互记忆的场景。

典型应用场景

  • 页面导航:用 st.session_state.page 记录当前所在页面,点击侧边栏菜单时切换。

  • 表单向导:分步收集用户信息,每一步将输入保存到 session_state,最后统一提交。

  • 防重复提交:通过 st.session_state.submitted 布尔值控制按钮的可用状态。

Streamlit 默认在每次交互时从头执行脚本。当你需要跨交互保存变量时(比如计数器),就需要 st.session_state

# 初始化计数器(确保首次访问时存在)
if"count"notin st.session_state:
    st.session_state.count = 0

# 计数按钮 - 每次点击触发 +1
if st.button("➕ 点击 +1"):
    st.session_state.count += 1

st.metric("点击次数", st.session_state.count)

# 重置按钮 - 将计数归零
if st.button("🔄 重置"):
    st.session_state.count = 0

# 小技巧:利用 session_state 实现“首次运行”标记
if"first_run"notin st.session_state:
    st.session_state.first_run = True
    st.info("👋 欢迎首次访问!")
else:
    st.write(f"你已经访问了 {st.session_state.count} 次")

# 清除特定状态(用于退出登录或清空表单)
# del st.session_state["user_info"]

st.session_state 本质上是一个字典,但支持属性访问(st.session_state.count 等价于 st.session_state["count"])。

结语

本文主要讲解streamlit的基本安装及简单示例,着重介绍了该项目能够使用的各种组件,现在 你可以通过各组件构建简单的web应用了。

更多推荐