Streamlit 实战:看板、表单与模型部署的网站集合

发布时间:2026/10/20 11:47:01
Streamlit 实战:看板、表单与模型部署的网站集合
简介这是一套基于Streamlit制作的Web应用示例合集面向Python开发者、数据分析师和数据可视化爱好者帮助大家通过现成代码快速上手Streamlit无需深入学习HTML、CSS等前端技术就能搭建出交互式数据页面适合快速验证想法、搭建内部工具或学习数据应用开发流程。整包包含7个文件总大小518KB其中有两个Python脚本负责核心功能逻辑三张JPG图片作为界面展示素材另配一份说明文档与依赖清单列出项目结构、运行方式及所需库列表便于直接运行学习和二次修改。目前已有两千七百二十二人学习这份示例集。示例覆盖调色板生成、文件夹浏览、图片展示等典型场景并体现了页面布局、交互控件、数据加载与显示等常见写法借助说明文档可快速完成环境配置观察Streamlit的“代码即界面”核心思想之后替换数据或组件就能改写出自己的数据看板、工具站点或原型对入门和日常工作参考都很有价值。1. 网站集合的价值Streamlit 让你用纯 Python 兑现交互页面Streamlit 是一个把 Python 脚本直接变成网页的库而这个项目是一套用 Streamlit 写好的网站集合数据看板、表单录入、模型预测这些最常见场景都包含在内。真实情况是分析师手里的 csv 和模型离“能被同事点两下”的网页就差一个前端距离学 HTML、CSS、JS 成本太高Streamlit 把这条路压缩到只写 Python。这套集合的价值是把侧边栏筛选、表格排序、按钮触发、结果回显这些反复出现的交互套路做成可改的模板。适合赶交付的后端开发者、刚接触 Web 的数据岗以及需要在团队内部快速搭工具的人。改改数据源和字段名就能让页面跑起来。2. 集合里装了什么看板、表单、模型 Demo 的三种基本形态这个集合不是一个大而全的应用而是按交互形态拆成一堆独立页面。理解它最有效的方式是把它按“信息流向”分成三类数据从文件流向图表的是看板数据从用户流向存储的是表单数据从模型流向结果是预测 Demo。每一类在 Streamlit 里的写法差异很大混着用就会出问题单独拆开反而能复用。2.1 看板类st.bar_chart 与 st.dataframe 的组合套路集合里数量最多的就是看板类页面整体骨架都是“读数据 → 筛选 → 画图 → 展示表格”。一个最简实现如下import pandas as pd import streamlit as st st.cache_data def load_data(): # 集合里的示例数据是 csv路径建议用相对路径 return pd.read_csv(data/sales.csv) df load_data() st.title(销售看板) st.bar_chart(df.groupby(region)[amount].sum()) st.dataframe(df.head(200), use_container_widthTrue)逻辑说明st.bar_chart 直接接收 DataFrame 或 Series省去手动配置 matplotlib 的坐标轴和配色st.dataframe 渲染的是带排序、缩放和滚动条的表格文件比较大的时候能按需加载不会一上来就卡死页面。参数说明use_container_widthTrue 让表格撑满外层容器避免缩在左侧窄窄一列head(200) 限制展示条数作用是防止大文件把前端拖垮。这个组合是看板页的基本盘。集合里有些页面会升级成 st.plotly_chart效果更接近商业报表带 tooltip、缩放、框选但依赖体积大、首次加载也慢。我的习惯是只展示趋势用 st.bar_chart 和 st.line_chart需要拖拽和悬停看明细再换 plotly。替换时注意 plotly 接收的是 figure 对象而不是 DataFrame直接喂数据会报错。2.2 表单交互类st.form 与 st.session_state 的状态管理表单类页面承担“录入 → 提交 → 回显”的角色典型场景是资产登记、参数配置。最容易犯的错是把输入框直接散落在页面顶层这样用户每次点一下控件脚本就从第一行重跑前面填的内容全部重置。集合里的正确写法是把控件包进 st.formimport streamlit as st if records not in st.session_state: st.session_state.records [] with st.form(asset_form): name st.text_input(资产名称) owner st.selectbox(负责人, [A组, B组, C组]) submitted st.form_submit_button(登记) if submitted: st.session_state.records.append({name: name, owner: owner}) st.success(已登记当前共 %d 条 % len(st.session_state.records))逻辑说明st.form 内部的所有控件在用户操作时不会立刻触发重跑只有按下 form_submit_button表单里所有值才一次性返回这保证了填写过程中其他控件保持原样。st.session_state 用来保存跨重跑的记录因为普通 Python 变量在每次脚本重跑后都会重新初始化只有写进 session_state 才能留住。参数说明with st.form(asset_form) 的字符串是表单唯一标识同一个页面上多个表单不能重名form_submit_button 可以加 typeprimary 让按钮高亮用 use_container_width 控制宽度。集合里的表单页还会和 st.data_editor 配合比如让用户直接在一个可编辑表格里改数据提交后统一覆盖原 DataFrame。st.data_editor 返回的是表格当前值配合 session_state 存档对内部工具来说比一个个输入框更高效。2.3 模型部署类加载模型与预测回显模型部署类页面负责把训练好的模型接上页面左侧给特征右侧出结果。这一类页面真正的难点不是模型本身而是模型文件路径怎么管理、结果怎么格式化才不会让用户误解。一个常见骨架import joblib import streamlit as st model_path st.sidebar.text_input(模型目录, model/reg.pkl) model joblib.load(model_path) x1 st.sidebar.slider(特征A, 0, 100, 50) x2 st.sidebar.number_input(特征B, value1.0) if st.sidebar.button(开始预测): pred model.predict([[x1, x2]])[0] st.metric(预测结果, round(float(pred), 2))逻辑说明joblib.load 把训练好的模型读进内存slider 和 number_input 分别对应离散和连续特征的输入st.metric 把结果渲染成带标签的指标卡比直接写 st.write 更像产品。参数说明model_path 用 text_input 的好处是不改代码就能切换模型文件但要注意这里的路径是相对“启动目录”而不是“脚本目录”这个差别是路径踩坑的第一来源。预测结果 round 成两位小数避免一长串浮点把用户看懵。集合里更完整的 Demo 还会加上 st.file_uploader让用户上传 csvpandas 读取后批量预测再用 st.download_button 把结果下载。这套流程对不想碰命令行的同事很友好但大文件上传速度慢我一般提醒超过几十 MB 还是先放到服务器本地路径再加载。页面类型核心组件适用场景看板类st.bar_chart / st.dataframe报表展示、趋势分析表单类st.form / st.session_state登记录入、参数配置模型类joblib st.metric推理预测、结果回显三类页面覆盖了内部工具八成的需求。想快速上手这套集合的话不用一开始读全部代码直接挑一个单文件运行改改数据路径就能看到效果比从头读一百行再动手更省时间。3. 把集合跑起来环境搭建、启动命令与 config.toml 配置拿到集合包第一步不是打开编辑器而是先把环境搭干净再谈运行。Streamlit 对 Python 版本不算挑剔但依赖库之间偶尔会有版本冲突用虚拟环境隔离能省掉一大半玄学问题。配置层面则有三件事要做创建虚拟环境、用正确方式启动、把主题和端口写进配置文件。3.1 虚拟环境与依赖安装顺序先把项目拆到本地然后进目录建虚拟环境。我一般按这个顺序执行cd streamlit-project python -m venv venv source venv/bin/activate pip install -r requirements.txtWindows 下把 source venv/bin/activate 换成 venv\Scripts\activate。两个容易被忽略的点一是必须先激活再 pip install否则包装进全局环境之后换项目会互相污染二是 requirements.txt 里有 pandas、numpy 这类带编译的包时直接用 pip 的默认 wheel不要自己去源码编译。环境一旦弄脏最干脆的办法是把 venv 目录整个删掉重建而不是手动装装拆拆那才真的浪费时间。requirements.txt 里通常会把 streamlit 写成固定版本比如 streamlit1.x.x。如果你看到没锁版本强烈建议自己补上。Streamlit 的 API 在版本升级时偶尔会改比如部分图表函数的参数变化集合里的代码按某个旧版写好后在新环境跑可能出现 warning 甚至直接报错。锁定版本等于给项目留了后悔药。3.2 启动的三种方式单文件、多页面与外部访问集合里不同用途的页面有不同启动方式。单文件启动是最常用的streamlit run app_dashboard.py启动后终端会显示本地地址浏览器自动打开。如果集合用了多页面结构Streamlit 会把 pages/ 目录下的所有 py 文件自动识别为子页面启动时只需指定主入口streamlit run 01首页.py这时左侧会出现页面列表点一下就能切换。第三种是允许局域网访问加上 --server.addressstreamlit run app_dashboard.py --server.address0.0.0.0 --server.port8501参数说明--server.address0.0.0.0 表示监听所有网卡同一局域网里的机器能用服务器 IP 访问默认只绑定 localhost外部机器连不进来。--server.port 指定监听端口默认 8501多个项目并发跑就要手动换。需要特别提醒这种裸启动方式没有任何鉴权内部用可以对外提供服务一定要放在可控内网或者前面套一层反向代理统一控制访问否则相当于把页面和数据直接暴露出去。3.3 config.toml主题、端口与 CORS 配置除了命令行Streamlit 还支持配置文件位置固定在项目的 .streamlit/config.toml 下。集合里最常见的配置[theme] primaryColor #4F8BF9 [server] port 8502 runOnSave true [browser] gatherUsageStats false配置改完要重启进程才生效。theme 下的 primaryColor 会改变所有按钮和选中状态的颜色适合把页面统一成公司品牌色server.port 的作用和 --server.port 一样两边同时存在时命令行优先runOnSavetrue 会在编辑器保存文件后自动刷新浏览器本地开发很舒服但部署到正式环境最好关掉避免代码保存时页面被反复重载。还有一个需要注意的坑把页面放到容器或反向代理后面时浏览器访问路径和服务器监听路径可能不一致需要通过启动命令或配置正确设置路由前缀。集合本身不包含部署环境的配置因为内部工具通常直接跑在内网服务器上难度不大。真正对外发布时我会让反向代理把特定访问路径转发到本地 8501 端口不把 Streamlit 进程直接暴露在公网地址上。4. 拆一个完整案例从 CSV 到可筛选的交互看板为了讲清这套集合的实际用法我挑一个销售看板 Demo 从头拆一遍。这个页面基本覆盖了集合里看板类的所有关键技巧缓存、筛选联动、指标卡、导出。把这一套吃透看板类页面基本就通了。4.1 数据加载与缓存st.cache_data 的两种写法集合里的看板页面几乎都有一个加载数据的函数用 st.cache_data 装饰器包起来import pandas as pd import streamlit as st st.cache_data(ttl600) def load_orders(pathdata/orders.csv): df pd.read_csv(path) df[order_date] pd.to_datetime(df[order_date]) return df逻辑说明Streamlit 页面每次交互都会从第一行执行到最后一行如果不加缓存用户点一下侧边栏筛选整个 csv 就重新读一遍数据超过几万行就会明显卡顿。st.cache_data 会根据函数参数和函数体内容生成缓存键参数没变时直接返回缓存结果ttl600 表示缓存有效期 10 分钟到期后重新计算。参数说明ttl 适合数据定期更新的场景比如每天更新一次就设成 3600 或 86400如果文件基本只增不改可以不传 ttl让缓存永久生效。数据文件被手动替换后旧缓存还会继续命中这时需要主动清理缓存这也是后面避坑章里要展开的内容。4.2 侧边栏筛选与图表联动widget 的典型闭环筛选是看板类页面最核心的交互。Streamlit 的写法是读取 widget 的值 → 过滤 DataFrame → 把过滤结果喂给图表regions st.sidebar.multiselect( 选择区域, df[region].unique(), defaultlist(df[region].unique()[:2]) ) filtered df[df[region].isin(regions)] daily filtered.groupby(order_date)[amount].sum() st.line_chart(daily) st.write(筛选后共 %d 条记录 % len(filtered))逻辑说明st.sidebar.multiselect 的第二个参数是候选选项集第三个参数是默认选中值。不传 default 时页面首次加载会返回空列表图表跟着空白新手常在这里翻车。filtered 这步是普通的 pandas 布尔索引Streamlit 本身不做任何数据过滤所有“动态效果”都来自脚本重跑后重新计算。参数说明multiselect 的 key 参数很重要如果多个页面都用了 region 这个名字切换页面时选中状态会被带到另一个页面。集合里的多页面 Demo 专门踩过这个坑解决办法是给 key 加上页面前缀比如 dashboard_region 和 analysis_region。4.3 指标卡与导出st.metric、下载按钮的配合看板不能只有图表还需要总结性数字和导出能力。典型写法total_amount filtered[amount].sum() col1, col2, col3 st.columns(3) col1.metric(总金额, f{total_amount:,.0f}) col2.metric(订单数, len(filtered)) col3.metric(平均单笔, f{total_amount / max(len(filtered), 1):,.2f}) csv_data filtered.to_csv(indexFalse).encode(utf-8-sig) st.download_button( 导出筛选结果, datacsv_data, file_namefiltered_orders.csv, mimetext/csv )逻辑说明st.columns 创建并排布局col1.metric 把带格式的字符串渲染成指标卡适合放在看板顶部让用户一眼读到核心数据。st.download_button 把 csv 字符串转成 bytes 直接下载不需要写后端接口文件只存在内存里比临时生成文件再清理干净得多。参数说明encode(utf-8-sig) 是给中文用的不加这个 BOMExcel 直接打开 csv 会乱码file_name 支持带日期比如 filtered_orders_20260415.csv方便按批次存档。f{total_amount:,.0f} 是千分位格式化一个小细节但直接影响页面的专业观感。拆完这个案例就能看到集合里的看板页面从结构上就是这一套东西加载缓存、侧边栏筛选、指标卡和导出。换数据源、改 groupby 维度就能覆盖绝大多数内部看板需求。真正决定页面能不能让同事愿意天天打开往往不是图表多炫而是筛选顺不顺、导出数据准不准。5. 避坑Streamlit 运行时的五个常见问题与排查这套集合本身代码不算复杂但运行环境的差异会制造出各种“在我电脑上是好的到你那边就翻车”的状况。下面这五条是我在拆这类项目时真实踩过的坑按现象、原因、解决的思路整理出来基本覆盖了 Streamlit 内部工具最常见的故障点。5.1 缓存不刷新文件改了页面数据还是旧数据现象csv 文件明明更新了页面上显示的却还是前天甚至上周的数据。反复刷新浏览器也没有变化看起来像“黑匣子”。原因st.cache_data 默认把函数参数和函数体代码当作缓存 key它不感知外部文件内容的修改。只要文件路径没变、参数没变缓存就一直命中旧数据就被反复拉出来展示。解决在调试入口加一个手动清缓存按钮代码是这样if st.sidebar.button(清缓存并刷新): st.cache_data.clear() st.rerun()st.cache_data.clear() 会清掉该页面所有缓存数据st.rerun() 强制脚本重跑。对内部工具来说加这样一个入口比教用户重启服务更省事。5.2 按钮状态一触就丢页面上的勾选和输入全部重置现象页面放了几个筛选框和一个“查询”按钮用户填好条件后点击按钮页面上所有输入框立刻恢复默认值填的内容全部消失。原因Streamlit 的脚本是单向渲染widget 的值默认随每次重跑重置只有通过 key 注册到 session_state 里的值才会保留。普通 Python 变量无法跨重跑存活。解决每个需要保留状态的 widget 都显式指定 key例如 st.text_input(项目名, keyproject_name)。值会自动写入 session_state 并在重跑后恢复。需要跨页面保存的数据提前初始化到 session_state再用 session_state[project_name] 读取。st.form 的提交机制能解决一部分问题但前提是控件必须包在 form 里面form 外散落的控件依然会每次参与重跑。5.3 中文乱码页面正常导出表格却乱码现象页面上显示的中文一切正常但用 st.download_button 导出的 csv 文件用 Excel 打开后乱码或者 plotly 图表的坐标轴中文变成方块。原因页面本身走 UTF-8 渲染所以浏览器里看不出问题。导出时如果直接 df.to_csv().encode(utf-8)Excel 默认按本地编码解析就读出了乱码。图表乱码则是因为绘图库默认字体集里没有中文字体渲染时找不到对应字形。解决导出统一 encode(utf-8-sig)加上 BOM 头Excel 就能正确识别。图表中文字体需要在绘图时显式指定包含中文的字体比如 SimHei 或 Microsoft YaHei并保证运行环境里装了对应字体。Linux 服务器上常见的坑是系统字体目录里没有中文字体即使代码写了字体内核也渲染不出来。5.4 端口被占第二个项目起不来现象跑完一个页面后再启动集合里的另一个页面终端直接报 8501 already in use页面一直显示请求超时。原因Streamlit 默认所有实例都绑定 8501 端口同一台机器上多个项目并发跑后启动的进程就抢不到端口。解决启动时显式指定端口streamlit run app_analysis.py --server.port8510。更稳妥的做法是写一个启动脚本把项目和端口映射关系固定下来避免每天靠记忆找端口。如果已有进程占住端口先查进程再决定要不要终止不建议 pkill 直接盲杀容易把别的服务一起带走。5.5 多页面相互污染切到另一个页面旧页面选的值被带过去现象集合里有两个页面都有“选择区域”这个下拉框在 A 页选了“华东”切到 B 页后 B 页也自动变成“华东”看起来像数据串了门。原因Streamlit 的多页面应用共享同一个 session_statewidget 的 key 在整个应用里是全局命名空间。两个页面用了相同的 key值就被后者覆盖或继承。解决每个页面的 widget key 加上页面前缀比如 dashboard_region 和 analysis_region。这个习惯要在一开始就建立等页面数量多了再改 key会连带丢失用户的选中状态排查成本更高。集合的多页面资源里已经按这个规范命名直接照搬就行。6. 把集合变成自己的部署前的三个收尾技巧模板拿回来能用只是第一步真正变成自己手里的工具还得处理路径、配置优先级和上线前验证。这三件事拼起来决定这份集合在别人电脑上能不能也顺利跑起来。6.1 把路径写成一个入口函数集合里每个页面开头那段路径字符串我见过太多硬编码写法。最稳的方式是用 pathlib 统一管理from pathlib import Path BASE_DIR Path(__file__).resolve().parent DATA_DIR BASE_DIR / data用 Path 拼接而不是字符串加号Windows 和 Linux 通用项目整体移动或换机器时不需要改任何一行代码。数据文件名也统一放到常量里别在代码里散落一堆魔法字符串。6.2 配置文件默认值与命令行优先级部署到服务器时配置来源会同时存在优先级需要心里有底配置来源优先级生效时机Streamlit 默认配置最低每次启动config.toml中等重启后生效命令行参数最高当前启动这个优先级意味着config.toml 里写了 port8502同时命令行带 --server.port8501以命令行为准。我习惯统一把端口写进 config.toml命令行只放身份相关的东西这样换机器时改一个文件就行。6.3 验证启动后先走一遍主要交互任何页面改完上线前我都强制自己走一遍完整交互链路打开页面填筛选、点提交、导出文件、下载后打开检查编码四个动作缺一不可。特别是导出文件一定要本地打开确认中文正常别等交付到同事手里才发现乱码。第一次拆这种集合资源时我拿到手第一件事不是读代码而是先把每个页面跑起来再对照代码看哪些套路是重复的。正是那次被动式的对比让我确认“先跑通再看代码最后改需求”才是处理模板类项目最靠谱的流程。从那以后每个模板项目的第一天我都强制走一遍建虚拟环境、装依赖、启动、打开浏览器点完主流程再决定从哪里下手改。希望帮到你。本文还有配套的精品资源点击获取