
每年畢業設計選題季總有同學在“大數據分析”這個方向上猶豫不決。選純算法方向擔心推公式講不透選Web開發方向又覺得不夠有技術含量選爬蟲方向又容易做出一個沒有任何分析價值的腳本集合。如果你正好處在這樣的糾結里基于 Streamlit 構建一個國內汽車銷售分析系統是一個值得認真考慮的選項。這個選題最大的優勢在于它把 Python 爬蟲、Hadoop 存儲、Spark 數據處理、Streamlit 可視化完整串成了一條數據鏈路。你不僅能展示“我會用某個框架”還能向答辯老師講清楚“數據從哪里來、經過什么處理、最終如何呈現”。這篇文章會從選題價值、系統架構、核心代碼實現、驗證方式到答辯避坑把這個畢業設計題目的完整開發思路拆開講清楚。1. 這篇文章真正要解決的問題很多畢業生做大數據分析項目最常見的翻車現場是項目演示時只有幾張提前畫好的圖表老師問“數據怎么更新的”答不上來問“數據處理邏輯在哪里”只能指著一個 SQL 文件說“這就是清洗”。這種項目本質上只是一個“靜態可視化頁面”談不上大數據分析。而基于 Streamlit 的汽車銷售分析系統核心價值在于它不是一個“畫圖工具”而是一整套完整的數據管道。通過爬蟲獲取汽車銷量相關數據。把原始數據寫入 Hadoop HDFS 做分布式存儲。用 Spark 對海量銷售記錄做清洗和聚合統計。最后通過 Streamlit 提供交互式可視化面板讓用戶能按品牌、價格區間、地區、時間等維度自由篩選分析。這個選題適合以下人群有一定 Python 基礎希望在畢業設計中體現大數據技術棧但不想在研究分布式原理上耗費過多精力的同學。它不需要你精通 Hadoop 源碼也不需要你開發復雜的機器學習模型但要求你能把這些開源組件搭建起來、串聯起來、把業務問題跑通。這種“全鏈路”能力恰恰是很多企業招聘時看重的。2. 核心技術棧拆解每個組件真正負責什么項目名字里出現的每個技術名詞在實際系統中都有明確的分工不能只是羅列在簡歷上。2.1 Python 與爬蟲負責數據采集。汽車銷量數據通常分布在垂直資訊網站、行業數據平臺或公開榜單中。使用 Python 的requests、BeautifulSoup、json等庫可以定時從這些渠道抓取品牌、車型、銷量、價格區間等字段。爬蟲是系統的數據入口也是整個鏈路里最容易出問題的環節因為目標網頁結構變化、反爬機制、數據格式不一致都會導致采集失敗。2.2 Hadoop HDFS負責原始數據存儲。爬蟲抓下來的數據是散亂的 JSON 或 CSV 文本如果直接交給 Spark 分析會有大量臟數據。HDFS 在這里扮演的是“數據湖泊”的角色先把原始文件統一上傳到 HDFS 指定目錄再做后續清洗。在畢業設計環境中通常使用 Hadoop 偽分布式模式單機就能模擬真實 HDFS 的文件讀寫和副本機制。2.3 Spark負責數據清洗、統計分析和離線計算。它從 HDFS 讀取數據完成去重、缺失值處理、格式統一然后按品牌、地區、時間等維度做聚合統計。相比直接用 Pandas 處理Spark 的優勢在于當數據量達到百萬級以上時它能利用分布式計算能力同一個聚合邏輯可以平滑地從單機擴展到集群。這在畢業設計答辯中是一個非常加分的“工程化設計點”。2.4 Streamlit負責交互式可視化。Streamlit 是一個 Python 開源框架能用純 Python 腳本快速構建數據應用。它的核心特點是你寫一個st.bar_chart刷新頁面就是一個圖表控件寫一個st.selectbox就能生成下拉篩選框。不需要掌握 HTML、CSS、JavaScript幾十行代碼就能做一個可交互的數據面板非常適合畢業設計這種需要快速交付演示系統的場景。2.5 各技術棧的分工對比組件核心職責輸入輸出Python 爬蟲數據采集公開網頁或 API原始 CSV/JSON 文件Hadoop HDFS分布式存儲原始文件HDFS 上的數據文件Spark數據清洗與聚合HDFS 上的文件統計結果表MySQL / SQLite結果存儲Spark 輸出結果結構化結果數據Streamlit可視化交互結果數據瀏覽器訪問的分析面板3. 系統架構與模塊劃分整個系統的架構可以分成五個層次每一層都有一個清晰的數據入口和出口。數據采集層Python 爬蟲定時抓取生成原始數據文件 ↓ 數據存儲層原始文件上傳 Hadoop HDFS ↓ 數據處理層Spark 讀取 HDFS完成清洗和聚合統計 ↓ 結果存儲層統計結果寫入 MySQL 或 SQLite ↓ 可視化層Streamlit 讀取結果庫生成交互式 Dashboard在畢業設計論文中建議第一張架構圖就畫這個五層模型。相比只畫一個流程圖這個分層模式能清楚展示你對系統整體性的把握同時也是后期寫各章分工的骨架。系統內部模塊建議按功能拆分幾個獨立的 Python 包crawler/爬蟲模塊負責數據采集和本地落盤。storage/負責 HDFS 文件上傳和目錄管理。spark_jobs/Spark 統計任務一個任務對應一個分析維度。dashboard/Streamlit 頁面腳本負責可視化查詢。config/存放數據庫連接、HDFS 地址、爬蟲目標等配置文件。這樣拆分的好處是答辯時老師問“你這個系統哪些模塊是獨立可復用的”你可以直接回答每一個包都可以單獨運行、單獨測試不是一個所有代碼堆在同一個 py 文件里的低質量項目。4. 環境準備與開發環境搭建在開始編碼之前先把環境準備好。下面是一套適合畢業設計演示的推薦環境版本號請以官方文檔和實際安裝為準不要機械照搬。4.1 Python 環境建議使用 Python 3.9 到 3.12 之間的穩定版本。Streamlit 對 Python 版本有一定要求過老的 Python 版本可能無法安裝最新版 Streamlit。使用虛擬環境管理依賴避免多個項目依賴互相污染。# 創建并激活虛擬環境 python -m venv venv source venv/bin/activate # Windows 請使用 venv\Scripts\activate # 安裝核心依賴 pip install streamlit pip install pandas pip install plotly pip install pyspark pip install requests pip install beautifulsoup4 pip install pymysql pip install apscheduler如果你需要同時連接 Hadoop HDFS在純 Python 項目中可以使用hdfs庫來調用 WebHDFS 接口這比自己實現 Hadoop RPC 協議要簡單得多。pip install hdfs4.2 Hadoop 環境畢業設計推薦使用 Hadoop 偽分布式模式。偽分布式是指在單臺服務器上以獨立進程模擬 NameNode、DataNode、SecondaryNameNode 等角色既能展示 HDFS 的核心機制又不需要多臺物理機。啟動流程# 格式化 NameNode僅第一次啟動時執行 hdfs namenode -format # 啟動 HDFS 服務 start-dfs.sh # 驗證是否啟動成功 jpsjps命令輸出中如果看到NameNode、DataNode、SecondaryNameNode三個進程說明 HDFS 核心節點已經正常啟動。創建項目數據目錄hdfs dfs -mkdir -p /user/student/car_sales/raw hdfs dfs -mkdir -p /user/student/car_sales/clean4.3 Spark 環境Spark 建議使用 Local 模式完成開發調試減少集群資源調度帶來的額外復雜度。在提交任務時--master local[*]表示使用本機所有可用 CPU 核心執行任務這個參數對單機演示完全夠用。spark-submit \ --master local[*] \ --name CarSalesStatistics \ spark_jobs/sales_statistics.py4.4 數據庫環境統計結果存放于 MySQL 或 SQLite。MySQL 更適合展示工程化能力SQLite 更適合快速演示和打包提交。二選一即可重點在于表結構設計清晰。下表是一個簡易的汽車銷量統計結果表設計字段名類型說明idINT主鍵自增brandVARCHAR(50)品牌名稱modelVARCHAR(100)車型名稱sale_dateVARCHAR(20)銷售日期sales_volumeINT銷量price_rangeVARCHAR(20)價格區間regionVARCHAR(20)銷售地區5. 數據采集層用 Python 爬蟲獲取汽車銷量數據爬蟲是數據入口也是最容易被忽略工程質量的部分。不少同學把目標網頁復制成 HTML 文件然后寫一個字符串解析腳本這種方式在答辯中很難自圓其說。更穩妥的做法是先確認目標數據源是否允許爬蟲訪問遵守robots.txt和網站服務條款在代碼中做好頻率控制和異常處理僅將數據用于學習和畢業設計研究。下面是一個簡化版的采集流程結構上先請求數據再解析字段最后保存到本地 CSV 文件。# 文件路徑crawler/car_sales_crawler.py import csv import json import random import time import requests # 演示用模擬接口地址實際項目需替換為確認可合法訪問的數據源 API_URL https://example-car-data-api.com/api/v1/sales def fetch_sales_page(page: int, page_size: int 100) - list: 拉取一頁銷售記錄。 實際采集前必須確認目標數據源的服務條款與 robots 規則。 params { page: page, page_size: page_size } headers { User-Agent: ( Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 ) } # 注這里會進行真實網絡請求本地不能訪問外網時 # 可以用下面的 mock_data() 返回演示數據。 resp requests.get(API_URL, paramsparams, headersheaders, timeout10) resp.raise_for_status() data resp.json() # 根據返回結構解析記錄列表 records data.get(data, {}).get(records, []) return records def mock_data(): 僅用于本地功能演示構造符合字段結構的樣本數據。 brands [大眾, 豐田, 比亞迪, 本田, 長安, 吉利] models { 大眾: [朗逸, 速騰, 帕薩特], 豐田: [卡羅拉, 凱美瑞, RAV4榮放], 比亞迪: [秦PLUS, 宋PLUS, 漢], 本田: [思域, 雅閣, CR-V], 長安: [CS75 PLUS, 逸動, UNI-V], 吉利: [星越L, 帝豪, 博越L], } price_ranges [8-10萬, 10-15萬, 15-20萬, 20-30萬] regions [華東, 華南, 華北, 西南, 東北] records [] for _ in range(20): brand random.choice(brands) model random.choice(models[brand]) records.append({ brand: brand, model: model, sale_date: f2024-{random.randint(1, 12):02d}-01, sales_volume: random.randint(1000, 40000), price_range: random.choice(price_ranges), region: random.choice(regions), }) return records def save_to_csv(records: list, file_path: str) - None: 將記錄列表寫入 CSV 文件。 if not records: return fieldnames [brand, model, sale_date, sales_volume, price_range, region] with open(file_path, w, newline, encodingutf-8) as f: writer csv.DictWriter(f, fieldnamesfieldnames) writer.writeheader() writer.writerows(records) def main(): # 在線數據源不可用時切換為 mock_data() 構造本地演示數據 all_records [] for page in range(1, 6): try: records fetch_sales_page(page, page_size100) except Exception as e: print(f請求失敗使用模擬數據。錯誤信息{e}) records mock_data() all_records.extend(records) # 控制采集頻率避免對目標站點造成壓力 time.sleep(random.uniform(0.5, 1.5)) save_to_csv(all_records, data/raw_sales.csv) print(f采集完成共保存 {len(all_records)} 條記錄) if __name__ __main__: main()這段代碼中有幾個針對答辯的設計點要提前準備第一采集必須帶User-Agent并在兩次請求之間隨機休眠這體現的是對目標站點的禮貌訪問也是爬蟲的基本素養。第二try...except中切換為模擬數據既能保證代碼在離線環境下可運行也能應對真實接口訪問失敗時系統不崩潰。第三字段名稱統一采用英文蛇形命名方便后續 Spark 和 Streamlit 直接讀取避免中文字段名在數據管道中引發編碼問題。運行方式python crawler/car_sales_crawler.py運行完成后在data/目錄下會生成raw_sales.csv文件包含品牌、車型、銷量、日期、價格區間和地區字段。6. 數據存儲層Hadoop HDFS 上傳與目錄管理爬蟲生成的 CSV 文件還在本地下一步需要上傳到 HDFS。這一步在系統里的意義是把“原始數據”與“分析數據”隔離存放避免后面反復讀取本地文件產生路徑混亂。HDFS 常用命令# 上傳本地文件到 HDFS hdfs dfs -put data/raw_sales.csv /user/student/car_sales/raw/ # 查看文件是否上傳成功 hdfs dfs -ls /user/student/car_sales/raw/ # 查看文件大小和分塊信息 hdfs dfs -du -h /user/student/car_sales/raw/如果你希望爬蟲完成之后自動上傳文件可以在 Python 中調用 WebHDFS 接口。這里給出一個最小實現把本地上傳邏輯封裝起來避免每次手動執行 HDFS 命令。# 文件路徑storage/hdfs_client.py from hdfs import InsecureClient # HDFS NameNode 地址根據實際部署環境修改 HDFS_HOST http://localhost:9870 HDFS_USER student client InsecureClient(HDFS_HOST, userHDFS_USER) def upload_to_hdfs(local_path: str, hdfs_path: str) - None: 將本地文件上傳到 HDFS 指定路徑。 local_path: data/raw_sales.csv hdfs_path: /user/student/car_sales/raw/raw_sales.csv client.upload(hdfs_path, local_path, overwriteTrue) print(f文件已上傳{local_path} - {hdfs_path}) def list_hdfs_dir(hdfs_dir: str) - list: 列出 HDFS 目錄下的文件信息。 return client.list(hdfs_dir, statusTrue) if __name__ __main__: upload_to_hdfs( data/raw_sales.csv, /user/student/car_sales/raw/raw_sales.csv ) print(list_hdfs_dir(/user/student/car_sales/raw))從教學角度看HDFS 部分不需要在論文里展開講太多底層原理但要能回答三個問題為什么用 HDFS 而不是直接放本地磁盤實際數據存儲在哪個節點文件的副本機制是什么能回答這三問就足以證明你不是只知道命令的工具人。7. 數據分析層Spark 清洗與銷量統計實現Spark 是整個系統里最能體現“大數據分析”的部分。它承擔的任務有兩塊第一把 HDFS 上的原始數據讀進來第二按品牌、時間、價格區間、地區等維度做聚合統計。下面是一個典型的統計任務腳本示例# 文件路徑spark_jobs/sales_statistics.py from pyspark.sql import SparkSession from pyspark.sql.functions import sum, col, to_date, year, month from pyspark.sql.window import Window from pyspark.sql.functions import row_number # 初始化 SparkSession本地模式運行 spark SparkSession.builder \ .appName(CarSalesAnalysis) \ .master(local[*]) \ .config(spark.sql.shuffle.partitions, 4) \ .getOrCreate() # 從 HDFS 讀取原始銷售數據 sales_df spark.read.csv( hdfs://localhost:9000/user/student/car_sales/raw/, headerTrue, inferSchemaTrue ) # 數據清洗去除銷量為空或小于 0 的記錄 clean_df sales_df.filter(col(sales_volume).isNotNull()) \ .filter(col(sales_volume) 0) \ .dropDuplicates([brand, model, sale_date]) # 增加年份和月份兩列便于時間維度分析 clean_df clean_df.withColumn(sale_date, to_date(col(sale_date), yyyy-MM-dd)) \ .withColumn(year, year(col(sale_date))) \ .withColumn(month, month(col(sale_date))) # 統計品牌總銷量 brand_sales clean_df.groupBy(brand) \ .agg(sum(sales_volume).alias(total_sales)) \ .orderBy(col(total_sales).desc()) # 統計價格區間銷量分布 price_sales clean_df.groupBy(price_range) \ .agg(sum(sales_volume).alias(total_sales)) \ .orderBy(col(total_sales).desc()) # 統計大區銷量排名 region_sales clean_df.groupBy(region) \ .agg(sum(sales_volume).alias(total_sales)) \ .orderBy(col(total_sales).desc()) # 查看結果方便調試時確認數據是否正確 brand_sales.show(10) price_sales.show(10) region_sales.show(10) # 寫入結果庫以 CSV 形式落盤 brand_sales.write.mode(overwrite).csv(data/output/brand_sales) price_sales.write.mode(overwrite).csv(data/output/price_sales) region_sales.write.mode(overwrite).csv(data/output/region_sales) spark.stop()這段代碼的關鍵邏輯在于用dropDuplicates去除同一品牌、車型、日期下的重復記錄這是爬蟲采集中最常見的臟數據問題。用to_date把字符串日期轉成真正的日期類型后續按年、月聚合才不容易出錯。所有聚合結果都單獨導出到data/output/目錄方便 Streamlit 層讀取。Spark 是否真的有必要在這個畢業設計里答案是“有必要”因為它定義了系統的擴展邊界。答辯時你可以這樣說如果數據量從今天的幾千條增長到千萬條量級只需要把master從local[*]改成 YARN 集群的提交方式同一套聚合邏輯可以直接運行在分布式環境。這種回答比任何背誦的八股文都有說服力。注意如果從 HDFS 讀取文件時遇到網絡不通、權限不足可以先在本地用 CSV 路徑做開發調試確認邏輯正確后再切換回 HDFS 路徑。項目開發要有“先跑通、再換環境”的階段拆分意識。8. 可視化層Streamlit 交互式儀表盤實現Streamlit 是這個項目里開發效率最高的部分。你寫一個 Python 腳本保存后刷新頁面就能看到圖表和篩選器不需要配置任何前端工程。下面是一個完整的 Streamlit 應用框架包含數據加載、側邊欄篩選、指標卡片和三個分析頁簽。# 文件路徑dashboard/app.py import streamlit as st import pandas as pd import plotly.express as px # 頁面基礎配置 st.set_page_config( page_title國內汽車銷售分析系統, page_icon:car:, layoutwide ) st.title(國內汽車銷售分析系統) st.markdown(本系統基于 Python 爬蟲、Hadoop HDFS、Spark 與 Streamlit 構建數據均為教學演示樣本。) st.cache_data def load_data(): 從 Spark 輸出的結果目錄加載數據。 如果是開發階段也可以直接讀取 data/raw_sales.csv。 brand_df pd.read_csv(data/output/brand_sales/*.csv, headerNone, names[brand, total_sales]) price_df pd.read_csv(data/output/price_sales/*.csv, headerNone, names[price_range, total_sales]) region_df pd.read_csv(data/output/region_sales/*.csv, headerNone, names[region, total_sales]) return brand_df, price_df, region_df brand_df, price_df, region_df load_data() # 側邊欄篩選 st.sidebar.header(篩選條件) all_brands brand_df[brand].tolist() selected_brand st.sidebar.selectbox(選擇品牌, [全部] all_brands) all_regions region_df[region].tolist() selected_region st.sidebar.multiselect(選擇地區, all_regions, defaultall_regions) # 核心指標卡片 total_sales brand_df[total_sales].sum() brand_count brand_df.shape[0] avg_sales brand_df[total_sales].mean() col1, col2, col3 st.columns(3) col1.metric(總銷量, f{total_sales:,}) col2.metric(品牌數量, brand_count) col3.metric(品牌平均銷量, f{avg_sales:,.0f}) # 圖表區 tab1, tab2, tab3 st.tabs([品牌銷量排行, 價格區間分布, 地區銷量對比]) with tab1: fig_brand px.bar( brand_df.head(10), xbrand, ytotal_sales, title品牌銷量 Top10, texttotal_sales ) st.plotly_chart(fig_brand, use_container_widthTrue) with tab2: fig_price px.pie( price_df, namesprice_range, valuestotal_sales, title價格區間銷量占比 ) st.plotly_chart(fig_price, use_container_widthTrue) with tab3: fig_region px.bar( region_df.loc[region_df[region].isin(selected_region)], xregion, ytotal_sales, title地區銷量對比, colorregion ) st.plotly_chart(fig_region, use_container_widthTrue) st.markdown(---) st.caption(數據說明本頁面展示的統計結果由 Spark 離線計算生成數據文件來自教學演示樣本。)8.1 Streamlit 緩存機制st.cache_data是 Streamlit 中一個非常實用的裝飾器。默認情況下Streamlit 腳本在每次交互時都會重新執行如果每次都重新讀 CSV 或數據庫頁面會明顯卡頓。加上這個裝飾器后同樣的參數只會加載一次數據后續交互直接走緩存頁面響應更快。答辯演示時這個細節體現的是你對數據加載性能的敏感度。8.2 多頁簽設計使用st.tabs可以把品牌、價格、地區三個分析視角放在同一個頁面里而不是像傳統 Flask 項目那樣跳轉多個頁面。這種設計更符合數據分析師的日常使用習慣進入系統后在一個頁面內完成所有維度的探索。8.3 跑通一個最小可運行版本如果 Spark 輸出文件還沒有生成可以先在load_data()里臨時改為讀取data/raw_sales.csv用原始數據做圖表保證 Streamlit 頁面先能跑起來。然后再切換回 Spark 結果文件形成完整的“數據生成到展示”閉環。9. 系統運行效果與答辯演示要點整個系統開發完成后的運行命令分兩步先跑 Spark 統計任務再啟動 Streamlit 應用。# 第一步執行 Spark 統計任務 python spark_jobs/sales_statistics.py # 第二步啟動 Streamlit 可視化服務 streamlit run dashboard/app.py啟動成功后終端會輸出本地訪問地址默認是http://localhost:8501。用瀏覽器打開后預期看到以下內容頂部標題與系統簡介。三個指標卡片總銷量、品牌數量、品牌平均銷量。品牌銷量排行柱狀圖顯示銷量最高的前 10 個品牌。價格區間銷量占比餅圖。地區銷量對比條形圖并且可以通過側邊欄篩選地區。答辯演示時建議按以下節奏操作每一步都能對應到系統功能打開 Streamlit 頁面先展示整體布局說明每一塊區域的功能與對應數據來源。在側邊欄切換品牌和地區展示圖表的實時聯動效果證明系統具有交互分析能力。切換到終端窗口展示 Spark 任務執行日志指出聚合計算的分區數量和完成耗時。打開 HDFS 目錄命令展示原始數據文件在分布式文件系統中的存儲位置。最后回到項目代碼用一兩頁 PPT 重點展示數據管道五層模型。如果頁面出現空白或圖表不顯示優先檢查data/output/目錄下 Spark 是否生成了 CSV 文件以及文件路徑是否與pd.read_csv中的模式匹配。10. 常見問題與排查思路開發過程中最容易踩的坑按出現頻率從高到低排列如下。問題現象可能原因排查方式解決方案Streamlit 無法啟動或端口被占用8501 端口已被其他進程占用查看終端報錯信息運行netstat -ano | findstr 8501使用streamlit run app.py --server.port 8502更換端口pd.read_csv(data/output/brand_sales/*.csv)找不到文件Spark 輸出的文件不是單個 CSV而是目錄下的多個 part 文件用hdfs dfs -ls data/output查看目錄結構用通配符*.csv匹配或調整 Spark 輸出為單文件模式Spark 任務運行內存不足本地 JVM 堆內存設置過小查看 Spark 日志中的 OutOfMemory 信息在提交命令中添加--driver-memory 2gHDFS 上傳文件失敗NameNode 未啟動或權限不足運行hdfs dfs -ls /測試連接重新執行start-dfs.sh檢查用戶權限CSV 中文讀取亂碼文件編碼與讀取編碼不一致用文本編輯器查看文件編碼格式pd.read_csv中指定encodingutf-8Streamlit 頁面圖表不聯動篩選變量沒有傳給圖表數據源檢查側邊欄變量是否在px.bar中作為過濾條件在圖表繪制前增加篩選邏輯例如brand_df[brand_df[brand] selected_brand]這里單獨說一下 Spark 輸出文件的問題Spark 在分布式模式下寫入數據時默認會在輸出目錄下生成多個part-00000文件而不是一個單獨的result.csv。如果你希望在 Streamlit 中更方便地讀取可以在寫入前調用coalesce(1)強制合并為一個分區輸出brand_sales.coalesce(1).write.mode(overwrite) \ .option(header, true) \ .csv(data/output/brand_sales)但要注意coalesce(1)會降低數據寫入的并行度。真實項目中數據量大時不建議使用這個點也可以在答辯時主動說明展示你對性能與易用性之間權衡的理解。11. 畢業設計最佳實踐與避坑指南這個項目雖然技術棧清晰但如果不注意工程規范很容易在開發過程中變得混亂。下面幾條建議來自真實開發經驗能幫你少走很多彎路。11.1 數據字段統一命名爬蟲、Spark、Streamlit 三個環節共享同一套字段結構。建議在項目根目錄維護一份README.md記錄每個字段的含義、類型和取值范圍。比如sales_volume的單位是“輛”price_range只能是預定枚舉值。這份文檔既是開發備忘也是撰寫論文時“數據字典”章節的素材。11.2 分階段推進不要一次做完建議按以下順序推進項目第一階段用模擬數據跑通 Streamlit 頁面和圖表交互。 第二階段編寫 Spark 統計任務產出統計結果替換 Streamlit 的數據源。 第三階段實現爬蟲采集真實或模擬接口數據。 第四階段接入 HDFS形成完整存儲鏈路。 第五階段加入定時調度讓系統能自動更新數據。每個階段都有可交付、可驗證的成果避免最后階段才發現鏈路不通、無從排查。11.3 結果數據落庫而不是反復計算Spark 計算完成后把聚合結果寫入結果表或輸出文件。Streamlit 頁面只讀取結果不參與大數據計算。這樣設計的好處是頁面響應速度與數據量解耦不會因為原始數據增大而讓 Dashboard 變慢。11.4 善用定時任務讓數據自動更新如果希望在答辯前展示系統的“數據更新能力”可以用APScheduler實現定時采集和定時分析# 文件路徑scheduler/update_task.py from apscheduler.schedulers.blocking import BlockingScheduler from crawler.car_sales_crawler import main as crawler_main from spark_jobs.sales_statistics import main as spark_main def daily_update(): # 先采集數據 crawler_main() # 再將數據上傳 HDFS # 最后執行 Spark 統計任務 spark_main() if __name__ __main__: scheduler BlockingScheduler() # 每天凌晨 2 點執行更新任務 scheduler.add_job(daily_update, cron, hour2, minute0) scheduler.start()這個模塊放在系統中等于給項目增加了一個“定時數倉更新”的場景答辯時是一個明顯的加分項。11.5 代碼注釋和日志規范化項目源碼中核心函數必須寫 docstring關鍵步驟要有日志輸出。建議使用 Python 的logging模塊把爬蟲采集量、Spark 處理耗時、Streamlit 啟動日志都記錄下來。這不僅是良好代碼習慣也方便你在論文里展示系統可觀測性。12. 總結與后續提升方向基于 Streamlit 的國內汽車銷售分析系統本質上是一個“大數據分析技術的完整落地案例”。它把 Python 爬蟲、Hadoop HDFS、Spark、Streamlit 這些技術名詞串成了一條真實可運行的數據管道既能作為畢業設計選題也是一份很好的大數據應用開發入門項目。后續如果還有時間可以從以下方向繼續擴展把 Streamlit 部署到服務器通過 Nginx 反向代理讓其他人可以通過公網地址訪問系統接入更多維度的外部數據分析讓圖表更有業務意義將 Spark 計算從本地模式遷移到 YARN 集群驗證分布式環境下的計算性能引入定時調度框架讓整個數據管道每天自動運行。技術路線沒有唯一答案。有人用 Flask 做可視化有人用 Hive 做數據倉庫也有人用 ClickHouse 做實時查詢但核心思想是一致的數據采集、存儲、計算、展示必須是一套完整鏈路。你能把這條鏈路講透、跑通這就是一個高質量的畢業設計。