简介:这份资源是面向数据科学家与机器学习工程师的Streamlit入门实践包,针对初学者在安装与运行环节常遇到的依赖缺失、版本不兼容、下载缓慢等问题,提供一套可直接运行的参考源码。压缩包共4个文件,以2个py脚本为主,分别用于演示应用与安装测试,另含1个txt依赖清单和1个inscode配置文件,整体仅4KB,轻量易取。已有80人学习下载,适合刚接触Streamlit、希望快速验证环境配置是否正确的开发者。读者可借助可运行源码对照排查安装失败原因,理解环境变量设置与本地服务启动流程,并参考依赖清单完成库版本管理;测试脚本还能帮助验证安装结果是否符合预期,为后续将数据分析过程转化为交互式Web应用打下基础。
1. 从一份可运行源码说起:Streamlit 到底解决了谁的痛点
如果你写过数据分析脚本,大概率经历过这样的场景:本地跑得好好的pandas处理逻辑,想给同事看一眼结果,对方却连 Python 环境都没有。发个截图吧,筛选条件改不了;导出 Excel 吧,交互全丢了。Streamlit 就是冲着这个场景来的——它把 Python 脚本直接变成可交互的 Web 应用,不用写 HTML、CSS、JavaScript,也不用碰 Flask 或 Django 的路由和模板。这份「Streamlit 安装运行指南」附带的可运行源码,本质上是一个最小可跑的工程骨架,帮你跳过环境配置的玄学阶段,直接看到streamlit run之后浏览器里弹出的那个页面是怎么来的。它适合两类人:一是做数据分析、算法验证、内部工具开发的从业者,想快速把脚本包装成能点的界面;二是刚接触 Web 应用但不想学前端的 Python 开发者。源码包里通常包含入口脚本、依赖清单和一份说明,拿到手就能跑,跑通之后再拆开看每一行在干什么。
2. 环境准备与依赖安装:把 Python 版本和包管理器的账算清楚
2.1 为什么 Python 版本和虚拟环境不能省
Streamlit 对 Python 版本有明确要求,常见做法是 3.8 到 3.11 之间,太老的版本会在安装pyarrow或numpy时直接编译失败,太新的版本偶尔会遇到某些依赖还没放出预编译轮子(wheel),导致pip install卡在源码编译环节。我一般会先用python --version确认当前解释器版本,如果系统里同时装了多个 Python,务必确认pip和python指向同一个。虚拟环境这一步很多人嫌麻烦,但血泪经验是:Streamlit 依赖的protobuf、click、tornado等包版本敏感,直接装在全局环境里,过两天跑另一个项目就可能把版本顶掉,到时候报错信息能让你查半天。用venv或conda隔离,是成本最低的后悔药。
# 确认 Python 版本,建议 3.8 - 3.11 python --version # 创建虚拟环境(以 venv 为例) python -m venv streamlit_env # 激活虚拟环境 # Windows: streamlit_env\Scripts\activate # macOS / Linux: source streamlit_env/bin/activate # 升级 pip,避免旧版解析依赖出问题 pip install --upgrade pip这段命令的逻辑很直白:先看版本,再建隔离区,最后把包管理器本身升到较新版本。参数上唯一需要注意的是venv的路径,如果你把虚拟环境建在项目目录下,记得把streamlit_env/加进.gitignore,不然源码包提交时会带上一堆无关文件。激活之后命令行提示符前面会出现环境名,看到这个再往下走。
2.2 安装 Streamlit 与源码包依赖的两种方式
源码包一般会附带一个requirements.txt,里面锁定了 Streamlit 的版本以及项目用到的其他库,比如pandas、numpy、plotly之类。常见做法是先装 Streamlit 本体,再根据清单补齐依赖。如果你拿到的源码包里没有requirements.txt,那就手动装streamlit,然后跑起来看报错缺什么再补什么。这里有个细节:Streamlit 的版本更新较快,不同版本之间 API 有细微差别,比如st.experimental_rerun在某些版本里已经改成st.rerun,源码里如果用了旧写法,新版本跑起来会直接抛AttributeError。所以优先按源码包指定的版本装,别盲目追新。
# 方式一:有 requirements.txt 的情况 pip install -r requirements.txt # 方式二:手动安装核心包 pip install streamlit pandas numpy # 验证安装是否成功 streamlit --versionpip install -r requirements.txt会逐行读取依赖并安装,如果某一行指定了streamlit==1.28.0这样的精确版本,pip 就会去拉那个版本。手动安装时pip install streamlit默认拿最新稳定版,适合你只是想先跑个 Hello World 试试水。streamlit --version能打印出版本号,说明命令行工具已经注册到当前环境,这一步过了再谈运行。
2.3 依赖冲突的排查思路
装依赖时最常见的翻车现场是版本冲突,报错信息里会出现ERROR: Cannot install ... because these package versions have conflicting dependencies。这时候别急着一条条卸,先用pip check看当前环境里哪些包互相不满意,再用pip list对照源码包里的版本要求。如果源码包明确写了streamlit==1.28.0和pandas==2.0.3,那就严格按这个组合来,不要自作主张升到pandas 2.1。另一个高频问题是protobuf版本,Streamlit 依赖它做序列化,版本高了低了都可能报TypeError或Descriptor相关错误,遇到这种直接按源码包锁定的版本重装即可。
3. 运行源码与核心文件拆解:从streamlit run到页面渲染
3.1 启动命令与端口参数
源码包拿到手,入口文件通常叫app.py或main.py,在项目根目录下执行streamlit run 文件名就能启动。默认情况下它会监听8501端口,并在终端打印出本地访问地址和网络访问地址。如果你本机8501被占了,或者想同时跑多个 Streamlit 应用,就得手动指定端口。还有一个容易忽略的参数是--server.address,默认绑在localhost,如果你想让同一局域网内的同事访问,需要改成0.0.0.0,但注意这样会把服务暴露出去,内部工具场景下要评估一下网络环境。
# 默认启动,端口 8501 streamlit run app.py # 指定端口和监听地址 streamlit run app.py --server.port 8600 --server.address 0.0.0.0 # 关闭自动打开浏览器 streamlit run app.py --server.headless true--server.port后面跟端口号,选一个没被占用的即可。--server.address 0.0.0.0表示监听所有网卡,适合容器内运行或需要外部访问的场景。--server.headless true在服务器上跑的时候很有用,避免它试图调用图形界面打开浏览器而报错。这些参数也可以写进项目根目录的.streamlit/config.toml文件里,省得每次敲一长串。
3.2 入口脚本的典型结构与执行逻辑
Streamlit 的执行模型和传统 Web 框架不一样,它不是「请求-路由-响应」那套,而是每次用户交互都从头到尾重新执行一遍脚本。这意味着你写在脚本顶层的代码,比如读数据、训练模型,每次点击按钮都会重跑。源码包里通常会看到st.cache_data或st.cache_resource装饰器,就是用来缓存这些重操作,避免每次交互都重新加载。下面是一个典型入口脚本的骨架,你可以对照自己手里的源码看结构是否一致。
import streamlit as st import pandas as pd # 页面配置,必须放在所有 st 命令之前 st.set_page_config(page_title="数据看板", layout="wide") # 用缓存装饰器包裹耗时的数据加载函数 @st.cache_data def load_data(path): # 读取 CSV,实际项目中可能是数据库查询或 API 调用 return pd.read_csv(path) # 侧边栏筛选控件 st.sidebar.header("筛选条件") category = st.sidebar.selectbox("选择类别", ["全部", "A", "B", "C"]) # 主区域 st.title("数据概览") df = load_data("data.csv") # 根据筛选条件过滤 if category != "全部": df = df[df["category"] == category] # 展示表格和指标 st.dataframe(df) st.metric("总记录数", len(df))st.set_page_config必须放在最前面,否则会报StreamlitAPIException。@st.cache_data装饰的函数,只要入参不变,第二次执行时直接返回缓存结果,参数变了才重新计算。st.sidebar下的控件会渲染到左侧栏,st.selectbox返回当前选中的值。主区域里st.dataframe渲染交互式表格,st.metric显示大号数字指标。整个脚本从上到下执行,每次筛选条件变化,脚本重跑,但load_data因为有缓存不会重复读文件。
3.3 源码包中常见文件的作用
一份完整的可运行源码通常不止一个app.py,还会包含数据文件、工具模块、配置文件等。下面这张表帮你快速定位每个文件该看什么。
| 文件/目录 | 作用 | 阅读优先级 |
|---|---|---|
app.py/main.py | 入口脚本,定义页面布局和交互逻辑 | 最高 |
requirements.txt | 依赖清单,锁定版本 | 高 |
data/或*.csv | 示例数据,用于跑通流程 | 中 |
utils.py/helpers.py | 封装的工具函数,如数据清洗、绘图 | 中 |
.streamlit/config.toml | 主题、端口、服务器配置 | 低,排错时看 |
README.md | 运行说明和参数解释 | 高,先扫一遍 |
拿到源码后,建议先读README.md和requirements.txt,把环境搭起来跑通,再回头逐行看app.py。如果app.py里引用了utils.py里的函数,就顺着 import 语句跳过去看实现。数据文件一般放在data/目录下,如果路径写的是相对路径,确保你在项目根目录执行启动命令,否则会报FileNotFoundError。
4. 避坑与常见问题排查:那些让你怀疑人生的报错
4.1 端口被占用导致启动失败
现象:执行streamlit run app.py后终端报OSError: [Errno 98] Address already in use或者一直卡在启动界面。原因:默认的8501端口已经被另一个 Streamlit 实例或其他程序占用。解决:换一个端口启动,比如streamlit run app.py --server.port 8600;或者先用lsof -i :8501(macOS/Linux)或netstat -ano | findstr 8501(Windows)找到占用进程,确认无用后结束它。
4.2 缓存装饰器用错导致数据不更新
现象:改了 CSV 文件内容,刷新页面后表格还是旧数据。原因:@st.cache_data默认根据函数入参做缓存键,如果入参没变,即使文件内容变了也不会重新读。解决:在load_data函数里加一个_version参数,每次改数据时手动改一下版本号;或者用st.cache_data.clear()在页面上加个按钮手动清缓存。更稳妥的做法是把文件修改时间作为入参传进去。
4.3 中文显示乱码或字体缺失
现象:图表里的中文变成方块,或者st.title里的中文正常但matplotlib图表里乱码。原因:Streamlit 页面本身用浏览器字体渲染中文没问题,但matplotlib默认字体不含中文。解决:在绘图代码里指定中文字体,比如plt.rcParams["font.sans-serif"] = ["SimHei"],或者改用plotly、altair这类基于浏览器渲染的图表库,它们对中文支持更好。
4.4 依赖版本冲突导致ImportError
现象:pip install -r requirements.txt装完,运行时报ImportError: cannot import name 'xxx' from 'yyy'。原因:某个包的版本和源码预期不一致,常见于protobuf、click、altair。解决:先pip check看冲突报告,再对照requirements.txt里的版本号逐个核对,用pip install 包名==版本号强制对齐。如果源码包没给版本号,去翻README.md或提交记录里的环境说明。
4.5 文件路径写死导致换机器就跑不起来
现象:在自己电脑上跑得好好的,换台机器或换到服务器上就报FileNotFoundError。原因:源码里用了绝对路径,比如C:\Users\xxx\data.csv或/home/xxx/project/data.csv。解决:把路径改成基于__file__的相对路径,例如os.path.join(os.path.dirname(__file__), "data", "data.csv"),这样无论项目放在哪个目录下都能正确定位数据文件。
5. 进阶技巧:用st.session_state和配置项把应用做稳
跑通基础流程之后,真正让 Streamlit 应用从「能跑」变成「好用」的,往往是对st.session_state和配置项的运用。st.session_state是一个跨交互周期保持状态的字典,因为 Streamlit 每次交互都重跑脚本,普通变量会被重置,而session_state里的值会保留。典型场景是多步表单、分页浏览、购物车这类需要记住用户选择的逻辑。我一般会在脚本开头初始化需要的状态键,避免KeyError。
import streamlit as st # 初始化 session_state,只在第一次运行时执行 if "step" not in st.session_state: st.session_state.step = 1 if "user_choice" not in st.session_state: st.session_state.user_choice = None # 根据 step 渲染不同内容 if st.session_state.step == 1: st.write("第一步:选择类别") choice = st.radio("类别", ["A", "B", "C"]) if st.button("下一步"): st.session_state.user_choice = choice st.session_state.step = 2 st.rerun() elif st.session_state.step == 2: st.write(f"你选择了:{st.session_state.user_choice}") if st.button("返回"): st.session_state.step = 1 st.rerun()这段代码的关键在于if "step" not in st.session_state这个判断,它保证初始化只做一次。st.rerun()主动触发脚本重跑,让页面切换到下一步。如果不加st.rerun(),按钮点击后虽然状态改了,但页面不会立即刷新,用户会以为没反应。另一个进阶点是.streamlit/config.toml,可以把主题色、端口、上传文件大小限制都写进去,团队协作时统一配置,省得每个人环境不一样。
# .streamlit/config.toml [server] port = 8600 maxUploadSize = 50 [theme] primaryColor = "#1f77b4" backgroundColor = "#ffffff" font = "sans serif"maxUploadSize单位是 MB,默认 200,如果应用涉及大文件上传,适当调大。theme下的颜色值用十六进制,改完重启 Streamlit 生效。这些配置跟着源码包一起提交,别人拉下来就是一致的外观和行为。
验证一个 Streamlit 应用是否稳定,我习惯做三件事:一是把requirements.txt里的版本号全部锁定,用pip freeze > requirements_lock.txt生成一份精确清单;二是在无缓存模式下跑一遍,确认没有隐藏的状态依赖;三是把app.py里的硬编码路径全部替换成相对路径,换目录测试。从那以后我每次拿到新的 Streamlit 源码包,都强制走一遍「建虚拟环境 → 锁版本 → 换目录跑」的流程,翻车次数少了很多。希望帮到你。
本文还有配套的精品资源,点击获取