这次我们来看一个很适合做计算机毕业设计的完整项目:基于 Python 爬虫 + Hadoop + Spark 的电影票房数据分析与可视化系统。
这个选题的价值在于,它不是单一技术点的堆砌,而是把数据采集、分布式存储、离线计算、Web 可视化的全链路串在了一起。很多同学的毕设卡在“有模型没数据”或“有数据没计算”,而电影票房这个领域的数据公开度较高、字段结构化程度高、分析维度丰富,非常适合用来展示大数据处理流程。更重要的是,这套系统对硬件要求不高,不需要 GPU,一台普通电脑就能跑伪分布式 Hadoop,重点考察的是你能否把组件装起来、把流程跑通、把结果讲清楚。
这篇文章会从系统架构、环境准备、爬虫实现、HDFS 存储、Spark 分析、可视化展示、接口设计、批量调度、性能观察、问题排查到最佳实践,完整拆解这个毕设选题怎么做。想直接拿来当课题框架,或者思考怎么扩展成生产级数据管道的读者,都可以参考。
1. 核心能力速览
| 能力项 | 说明 |
|---|---|
| 项目类型 | 大数据分析与可视化系统,毕业设计级项目 |
| 核心技术栈 | Python、爬虫、Hadoop(HDFS)、Spark、可视化 Web |
| 数据接入 | Python 爬虫采集公开电影票房数据,支持定时批量抓取 |
| 数据存储 | HDFS 分布式文件系统,按日期/来源目录组织 |
| 数据分析 | Spark SQL / DataFrame 离线计算,统计票房排行、趋势、类型分布等 |
| 可视化展示 | Web 页面展示折线图、柱状图、饼图、数据表格 |
| 接口服务 | Flask / FastAPI 提供 JSON 查询接口,供前端图表调用 |
| 批量任务 | 爬虫批量采集、Spark 批量分析、可视化结果定时刷新 |
| 推荐环境 | JDK + Hadoop 3.x + Spark 3.x + Python 3.8+,单机伪分布式即可 |
| 显存要求 | 无 GPU 依赖 |
| 启动方式 | 命令启动:start-dfs.sh、start-yarn.sh、spark-submit、python app.py |
| 适合场景 | 毕业设计、大数据课程项目、数据仓库入门实践 |
需要注意,不同版本的 Hadoop、Spark、JDK 组合差异较大,部署前一定要确认各自的版本兼容性。下面提到的所有命令和配置都以通用模板形式给出,实际使用时要替换为自己的安装路径、端口和文件目录。
2. 适用场景与使用边界
这个项目适合三类人。
第一类是计算机、大数据、数据科学相关专业的毕业生,需要一个“技术栈完整、能演示、能答辩”的选题。它既有 Python 爬虫的编码量,又有 Hadoop 和 Spark 的架构体现,还有前端可视化的展示效果,评审老师看到的是一个闭环系统,而不是零散的作业。
第二类是正在学习大数据技术、想通过实战项目把 HDFS 和 Spark 用起来的开发者。很多人看完 Hadoop 教程后没有头绪,因为不知道拿什么数据练手。电影票房数据集非常经典,字段清晰、维度固定、计算逻辑容易验证。
第三类是准备往后端数据工程方向走的同学,可以用这个项目入门离线路线的完整流程,后续再替换成 Flume、Kafka、Hive 等生产组件。
使用边界也要说清楚:
爬虫部分只应采集公开、合法、允许访问的数据,并且要遵守目标网站的 robots 协议和服务条款,不得绕过登录、验证码、反爬机制去获取非公开数据,更不能采集个人信息。电影票房这类统计数据本身属于可公开查询的范畴,但整理后的结构化数据仍可能涉及版权问题,用于课程学习和毕业设计通常没问题,如果要公开发布或商用,必须确认数据来源的授权许可。
系统定位是离线批处理,不追求实时性。如果你的毕设想写“实时票房分析”,那需要换一套实时技术栈,这不是当前这个架构能覆盖的内容。
3. 总体技术架构设计
整个系统的数据流可以分成四层,每一层职责单一,便于后期替换组件。
3.1 数据采集层
数据采集层负责从公开数据源抓取电影票房相关数据,包括影片名称、上映日期、类型、导演、主演、票房(累计与单日)、排片场次、上座率、评分等字段。实现上推荐 Python 爬虫,原因有三:
- Python 的 requests、BeautifulSoup、Scrapy 生态成熟,开发效率高。
- 采集后的数据可以直接生成 JSON、CSV 格式,方便后续上传 HDFS。
- Python 写爬虫逻辑门槛低,答辩时比较容易解释。
设计时要注意请求频率,加随机延时,减少对目标站点的压力。同时保存原始响应或原始解析结果,方便数据清洗阶段回溯。
3.2 数据存储层
存储层使用 HDFS。采集到的结构化数据先落到本地临时目录,再通过hdfs dfs -put上传到 HDFS。目录设计建议按照“业务/日期”两层组织,例如:
/user/hadoop/movie/input/2025-06-01/ /user/hadoop/movie/input/2025-06-02/ /user/hadoop/movie/analysis/按日期分目录的好处是,Spark 分析时可以直接读取指定日期范围的数据,也能方便地做增量分析。如果后续引入 Hive,还可以把 HDFS 目录映射成外部表,实现 SQL 查询。
3.3 数据计算层
计算层使用 Spark 读取 HDFS 中的数据,完成票房排行、年度趋势、类型分布等分析任务。Spark 的优势是比纯 Hadoop MapReduce 写起来简洁,而且支持 DataFrame 和 SQL,适合快速实现统计逻辑。
计算完的结果可以写回 HDFS,也可以写到本地 MySQL,或者直接导出为 JSON 结果文件,供 Web 层读取。
3.4 可视化层
可视化层是一个轻量级 Web 应用,推荐 Flask + ECharts。Flask 负责提供查询接口,ECharts 负责渲染图表。浏览器先请求 Flask 接口,拿到 JSON 数据后动态渲染图表。这样前后端分离,逻辑清晰,也方便后期扩展。
整体流程图可以概括为:
Python 爬虫 -> 本地 CSV/JSON -> HDFS -> Spark 分析 -> 结果文件/数据库 -> Flask API -> ECharts 图表4. 环境准备与安装部署
这是整套系统里最容易出问题的环节。Hadoop 和 Spark 的安装不像普通 Python 包那样一条命令搞定,配置文件和版本兼容问题会消耗大量时间。建议按下面的流程核对环境。
4.1 环境检查清单
| 组件 | 建议要求 | 说明 |
|---|---|---|
| 操作系统 | Linux(CentOS 7/8、Ubuntu 20.04+) | 也可以用 Windows + WSL,但纯 Windows 跑 Hadoop 比较容易踩坑 |
| JDK | JDK 1.8 或 JDK 11 | Hadoop 3.x 对 JDK 版本有要求,安装前查官方文档 |
| Hadoop | Hadoop 3.3.x 或更高 | 伪分布式模式即可满足毕设需求 |
| Spark | Spark 3.x | 需要与 Hadoop 版本兼容,建议用 pre-built 版本 |
| Python | Python 3.8+ | 用于编写爬虫和可视化服务 |
| 内存 | 8G 以上 | 伪分布式 Hadoop 加 Spark 本地模式,4G 会比较吃力 |
| 磁盘 | 20G 以上 | 系统、组件、数据文件都需要空间 |
这些版本号是通用建议,实际使用要以对应组件的官方文档为准。如果机器配置允许,也可以直接用 Docker 镜像启动 Hadoop,能省去不少安装时间,代价是你需要多理解一层 Docker 网络和文件挂载。
4.2 安装顺序建议
推荐顺序是:JDK -> Hadoop -> Spark -> Python 依赖。
# 检查 JDK 版本 java -version # 检查 Python 版本 python3 --version # 检查 Hadoop 版本 hadoop version # 检查 Spark 版本 spark-shell --versionHadoop 安装完成后,首次启动前要配置core-site.xml、hdfs-site.xml、yarn-site.xml三个文件,并且执行格式化命令:
# 格式化 NameNode,只在第一次安装时执行 hdfs namenode -format格式化操作很关键,如果重复执行,会导致 NameNode 元数据冲突,DataNode 无法正常连接。
4.3 常用启动命令
# 启动 HDFS 和 YARN start-dfs.sh start-yarn.sh # 查看进程是否就绪 jpsjps应该能看到 NameNode、DataNode、ResourceManager、NodeManager 等进程。任何一个进程缺失,都要去对应日志目录排查。
之后可以在浏览器访问 HDFS Web 界面和 YARN 界面,默认端口在不同版本有差异,Hadoop 3.x 一般是 9870 和 8088。
4.4 Python 可视化服务环境
pip install flask requests pandas写完 Flask 接口后,启动 Python 服务即可。如果本地多个项目共用 Python 环境,建议用 venv 或 conda 隔离,避免依赖互相覆盖。
5. 电影票房数据爬虫模块实现
爬虫模块是整个项目的数据源头。这一层设计得好不好,直接决定后续分析有没有料。
5.1 技术选型
requests:请求网页。BeautifulSoup:解析 HTML。re:清洗字符串。json/csv:保存结果。
如果目标站点是 API 接口返回 JSON,直接请求接口更稳定,不需要解析 HTML;如果目标站点是静态页面,就用 BeautifulSoup 解析。不管是哪种,务必先阅读目标网站的 robots 协议和页面声明,确认允许访问。
5.2 爬虫设计要点
爬虫不是简单抓一次就结束,毕设里要体现设计和稳定性。
- 请求头模拟:设置 User-Agent、Referer,让请求更像真实浏览器。
- 频率控制:
time.sleep(random.uniform(1, 3)),降低请求频率。 - 异常处理:捕获请求超时、解析失败等异常,记录日志,跳过单条失败数据。
- 增量采集:记录上次抓取日期,只抓新增数据。
- 断点续爬:每抓一定数量就保存一次临时结果,避免程序中断后全部丢失。
- 数据落盘:输出字段统一、编码统一的 JSON 或 CSV 文件。
5.3 数据字段说明
建议保留以下字段作为基础数据结构:
| 字段 | 类型 | 说明 |
|---|---|---|
| movie_name | string | 影片名称 |
| release_date | string | 上映日期 |
| genre | string | 电影类型,多个类型用分隔符连接 |
| director | string | 导演 |
| box_office_total | double | 累计票房 |
| box_office_daily | double | 单日票房 |
| schedule_count | int | 排片场次 |
| attendance_rate | double | 上座率 |
| rating | double | 评分 |
| crawl_date | string | 采集日期 |
字段设计要提前定好,因为后面 HDFS 目录、Spark Schema、可视化接口都依赖这一份数据结构。后期想加字段会导致上游到下游全部改动,成本很高。
5.4 爬虫代码示例
import requests import time import random import json from bs4 import BeautifulSoup def fetch_movie_list(url, headers=None): """请求公开的电影票房页面,返回结构化电影列表。""" if headers is None: headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)" } resp = requests.get(url, headers=headers, timeout=10) resp.raise_for_status() soup = BeautifulSoup(resp.text, "html.parser") items = [] for block in soup.select(".movie-item"): # 选择器需要按实际页面结构调整 name_node = block.select_one(".movie-name") office_node = block.select_one(".box-office") if name_node is None or office_node is None: continue item = { "movie_name": name_node.get_text(strip=True), "box_office_total": office_node.get_text(strip=True), "crawl_date": time.strftime("%Y-%m-%d"), } items.append(item) return items def save_to_json(data, filepath): with open(filepath, "w", encoding="utf-8") as f: json.dump(data, f, ensure_ascii=False, indent=2) if __name__ == "__main__": # 替换为实际可访问的公开数据源地址 data = fetch_movie_list("https://example.com/movie/boxoffice") save_to_json(data, "./data/movie_bo.json") print(f"采集完成,共 {len(data)} 条记录") # 批量采集时,每次请求间隔随机延时 for i in range(3): time.sleep(random.uniform(1, 3))这段代码是通用模板,选择器、URL 都需要按实际目标站点调整。爬虫首先保证能跑通单条链路,再考虑批量采集。
6. 数据入湖与 HDFS 存储设计
爬虫落盘的是本地 JSON 文件,接下来要把这些文件上传到 HDFS,让 Spark 能够读取。
6.1 数据格式化与上传
先检查本地生成的文件格式是否统一,编码是否为 UTF-8,字段名是否一致。
比如 JSON 文件可能是每行一个 JSON 对象的格式,也可能是整个数组的格式。Spark 读取多行 JSON 数组和单行 JSON 对象的写法不同,所以上传前最好统一为“每行一个 JSON 对象”的格式,这种格式也叫 JSON Lines。
# 创建 HDFS 输入目录 hdfs dfs -mkdir -p /user/hadoop/movie/input # 上传本地数据文件 hdfs dfs -put ./data/movie_bo.json /user/hadoop/movie/input/ # 查看上传结果 hdfs dfs -ls /user/hadoop/movie/input/上传之后可以检查一下文件内容:
hdfs dfs -text /user/hadoop/movie/input/movie_bo.json | head6.2 HDFS 目录设计
建议按日期组织目录:
hdfs dfs -mkdir -p /user/hadoop/movie/input/$(date +%Y-%m-%d) hdfs dfs -put ./data/movie_bo.json /user/hadoop/movie/input/$(date +%Y-%m-%d)/这样后面做增量分析时,Spark 可以根据目录名过滤数据。
6.3 数据校验
上传到 HDFS 后别急着跑分析,先做一个粗略校验:比较本地文件行数和 HDFS 上的文件行数,确认没有丢数据。
wc -l ./data/movie_bo.json hdfs dfs -cat /user/hadoop/movie/input/movie_bo.json | wc -l如果两个数字不一致,检查爬虫有没有截断文件,或者本地文件是否被重复覆盖。
7. Spark 票房分析模块实现
Spark 模块是整个系统的核心计算部分。推荐使用 PySpark,原因很简单:毕设的爬虫和可视化都已经用 Python 了,再用 Python 写分析,整个项目语言栈统一,答辩时也更连贯。
7.1 分析维度
结合电影票房数据的特点,建议至少实现以下五个分析任务:
- 年度总票房趋势:按年份聚合,观察整体市场走势。
- 月度票房分布:按月份聚合,找出档期效应。
- 票房 Top N 排行:按累计票房取前 10。
- 电影类型票房构成:统计不同类型电影的票房总和,观察观众偏好。
- 评分与票房关系:按评分区间聚合平均票房,分析口碑与商业表现的关系。
这些任务用 Spark SQL 或 DataFrame API 都能实现,逻辑不复杂,但足以覆盖“离线分析”的核心能力。
7.2 Spark SQL 示例代码
from pyspark.sql import SparkSession from pyspark.sql.functions import col spark = SparkSession.builder \ .appName("MovieBoxOfficeAnalysis") \ .getOrCreate() # 读取 HDFS 上的 JSON 数据 df = spark.read.json("hdfs:///user/hadoop/movie/input/*.json") # 数据基本概览 df.printSchema() df.show(5, truncate=False) print(f"总记录数: {df.count()}") # 年度票房趋势 df.groupBy("year") \ .sum("box_office_total") \ .orderBy("year") \ .show() # 票房 Top 10 排行榜 df.orderBy(col("box_office_total").desc()) \ .select("movie_name", "box_office_total", "rating") \ .show(10, truncate=False) # 统计结果写出为 JSON,供可视化层读取 result = df.groupBy("year").sum("box_office_total") result.write.mode("overwrite").json("hdfs:///user/hadoop/movie/analysis/yearly_trend") spark.stop()这段代码把分析结果写回 HDFS,Flask 接口可以读取这些结果文件,也可以把结果导入 MySQL 再查询。如果只是课程设计,直接读 JSON 文件更省事。
7.3 分析结果输出策略
分析结果输出有三种常见方案:
- 写回 HDFS 的 JSON 目录,Web 层读取后直接返回。
- 写回 MySQL 表,Web 层查询数据库返回。
- 打印到控制台,人工肉眼观察,适合调试验证。
推荐第一种,少引入一个数据库组件,链路更短。如果导师要求体现“数据入库”,再上 MySQL。
8. 可视化展示与 API 接口设计
可视化层是答辩时最容易加分的部分,因为效果直观。
8.1 图表设计
| 图表类型 | 展示内容 | 对应分析结果 |
|---|---|---|
| 折线图 | 年度票房趋势 | 按年份聚合的票房总和 |
| 柱状图 | 票房 Top 10 排行 | 按累计票房排序的前10部电影 |
| 饼图 | 电影类型票房构成 | 按类型聚合的票房占比 |
| 表格 | 明细数据 | 原始数据列表,支持分页 |
ECharts 是浏览器端渲染,数据通过 Ajax 请求获取,交互体验比后端模板渲染好很多。
8.2 Flask 接口示例
import json from flask import Flask, jsonify, request app = Flask(__name__) # 读取 Spark 分析结果 JSON 的函数,按实际路径调整 def load_analysis_result(path): with open(path, "r", encoding="utf-8") as f: return json.load(f) @app.route("/api/yearly_trend", methods=["GET"]) def yearly_trend(): data = load_analysis_result("./analysis_result/yearly_trend.json") return jsonify({"code": 0, "data": data}) @app.route("/api/top10", methods=["GET"]) def top10(): data = load_analysis_result("./analysis_result/top10.json") return jsonify({"code": 0, "data": data}) @app.route("/api/genre_distribution", methods=["GET"]) def genre_distribution(): data = load_analysis_result("./analysis_result/genre_distribution.json") return jsonify({"code": 0, "data": data}) if __name__ == "__main__": app.run(host="127.0.0.1", port=5000, debug=False)启动服务后,浏览器可以直接访问接口验证:
http://127.0.0.1:5000/api/top10看到 JSON 返回说明接口正常。随后在前端页面上用 ECharts 请求这些接口渲染图表即可。
8.3 前端页面流程
页面加载顺序建议是:
浏览器 -> 点击页面 -> 请求 Flask API -> 读取分析结果 JSON -> ECharts 渲染图表如果图表空白,先看浏览器开发者工具里的 Network 面板,确认 API 是否正常返回。
9. 功能测试与批量任务验证
功能测试要覆盖两条链路:单次全流程和批量任务。
9.1 单次全流程测试
按下面的顺序走一遍:
# 1. 清理历史结果 hdfs dfs -rm -r /user/hadoop/movie/input/* # 2. 上传新数据 hdfs dfs -put ./data/movie_bo.json /user/hadoop/movie/input/ # 3. 运行 Spark 分析 spark-submit --master local[2] movie_analysis.py # 4. 启动可视化服务 python app.py预期结果是:Spark 日志正常结束,控制台能打印出统计结果表,HDFS 的 analysis 目录出现结果文件,Flask 接口返回非空 JSON,前端图表正常展示。
9.2 批量任务设计
批量任务的典型场景是“每天定时抓取并分析一次”。最简单的方式是写一个 Shell 脚本,按顺序执行爬虫、上传、分析三个步骤:
#!/bin/bash # 定义日期变量 TODAY=$(date +%Y-%m-%d) # 1. 执行爬虫 python3 crawler/crawler.py # 2. 上传数据到 HDFS hdfs dfs -mkdir -p /user/hadoop/movie/input/$TODAY hdfs dfs -put ./data/movie_bo.json /user/hadoop/movie/input/$TODAY/ # 3. 执行 Spark 分析 spark-submit --master local[2] analysis/movie_analysis.py # 4. 输出完成日志 echo "$TODAY batch task finished"配合 crontab 就可以实现定时任务:
crontab -e # 每天凌晨 2 点执行 0 2 * * * /home/hadoop/movie_project/run_batch.sh >> /home/hadoop/movie_project/logs/batch_$(date +\%Y\%m\%d).log 2>&1批量任务的核心不是跑起来,而是能查看到失败日志、能重跑失败批次。所以一定要在脚本里加set -e或在每个步骤后检查退出码,避免某个步骤失败后后面所有步骤继续空跑。
9.3 批量调用接口测试
如果批量分析结果写成 JSON 文件,可以用 Python 脚本批量校验接口返回:
import requests api_list = [ "http://127.0.0.1:5000/api/yearly_trend", "http://127.0.0.1:5000/api/top10", "http://127.0.0.1:5000/api/genre_distribution", ] for api in api_list: resp = requests.get(api, timeout=10) data = resp.json() print(api, resp.status_code, len(data.get("data", [])))10. 资源占用与性能观察
这套系统不涉及 GPU 和显存,资源观察重点在 CPU、内存、HDFS 存储和 YARN 调度。
10.1 Hadoop 资源观察
Hadoop 自带的 YARN 管理界面可以看到每个任务的资源占用情况。在浏览器打开 YARN 界面后,能看到当前运行的任务、队列资源、内存使用等。如果提交 Spark 任务后长时间卡在 WAITING 状态,通常是 YARN 可用内存不足,需要调整:
<property> <name>yarn.nodemanager.resource.memory-mb</name> <value>8192</value> </property>这个配置表示每台 NodeManager 可以使用的内存上限,实际数值按机器配置调整。
10.2 Spark 资源参数
Spark 提交任务时可以指定 executor 内存和核心数:
spark-submit \ --master yarn \ --executor-memory 2g \ --num-executors 2 \ --executor-cores 2 \ movie_analysis.py如果数据量小,比如只有几百条,没必要开太多 executor,反而会增加调度开销。先用--master local[2]本地模式跑通,再切到 YARN 模式,是更稳妥的开发顺序。
10.3 数据量增长的影响
当数据量从几百条增长到几万条时,需要注意三点:
- 爬虫采集时间变长,单机串行抓取会越来越慢,需要控制频率,也要做好日志记录。
- HDFS 小文件变多,每个文件都有元数据开销,建议按日期合并输出。
- Spark Shuffle 阶段可能出现数据倾斜,比如某个热门类型占比过大,导致单个分区数据量集中。遇到这种情况,可以在聚合前先按维度加盐重分区,或者对热点维度单独处理。
观察资源占用最直接的方法是看 YARN 和 Spark UI 的实时指标,而不是等任务结束后再看日志。任务运行时打开 Spark UI,能看到每个 Stage 的处理时间、Shuffle 读写量、执行器内存使用率,这些数据能帮你快速定位瓶颈。
11. 常见问题与排查方法
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
Hadoop 启动后jps缺少 NameNode | 元数据目录不存在或格式化未完成 | 查看 Hadoop 日志目录下的.log文件 | 重新执行hdfs namenode -format,并检查目录权限 |
| DataNode 无法连接 NameNode | clusterID 不一致 | 查看 datanode 日志 | 删掉临时数据目录,重新格式化,或统一各节点 clusterID |
| HDFS 页面无法访问 | 端口配置不符或服务未启动 | netstat -tlnp检查端口 | 启动对应服务,或修改配置中的端口 |
| Spark 提交任务报错 | YARN 资源不足或版本冲突 | 查看 Spark UI 和 YARN 日志 | 减少 executor 数量,提高内存,检查 jar 包版本 |
| 爬虫请求返回 403 | 被目标网站反爬限制 | 检查响应状态码和页面内容 | 降低请求频率,更换 User-Agent,使用合规代理,或寻找其他公开数据源 |
| 上传 HDFS 失败 | 磁盘空间不足或权限不足 | df -h检查磁盘,hdfs dfs -ls /检查权限 | 清理无用文件,修改目录权限 |
| Spark 分析结果为空 | JSON 路径不正确或字段名不匹配 | df.printSchema()检查字段名 | 调整read.json路径,统一字段名 |
| 可视化页面图表空白 | Flask 接口返回异常或数据格式不对 | 浏览器 Network 面板查看接口状态 | 先直接访问接口确认 JSON 格式,再检查 ECharts 数据结构 |
| 批量任务跑了一部分就中断 | 网络波动或进程被杀 | 查看日志文件,检查退出码 | 在脚本中增加重试机制,每个步骤单独输出日志 |
| 内存不足导致 OOM | 数据分区过多或 executor 内存过小 | Spark UI 查看 Memory 指标 | 增加 executor 内存,减少并行度,或过滤无用字段 |
12. 最佳实践与使用建议
12.1 开发顺序
千万不要一上来就搭建 Hadoop 集群。更稳的顺序是:
- 先用 Python 爬虫保证拿到数据,字段定义清楚。
- 用本地目录 + pandas 或本地 Spark 验证分析逻辑。
- 再切到 HDFS 和 YARN 分布式环境跑通全流程。
- 最后做可视化页面。
这样每一步的错误范围都很小,排查起来快。
12.2 模块化与配置管理
项目目录建议这样组织:
movie_project/ ├── crawler/ │ ├── crawler.py │ └── config.yaml ├── analysis/ │ ├── movie_analysis.py │ └── requirements.txt ├── web/ │ ├── app.py │ ├── templates/ │ └── static/ ├── data/ │ ├── raw/ │ └── processed/ ├── scripts/ │ └── run_batch.sh └── logs/爬虫、分析、Web 三层完全解耦,互相之间只通过文件或接口通信。这样哪怕以后换爬虫框架、换分析引擎,都不会牵一发动全身。
config.yaml统一管理数据源地址、目录路径、请求频率、字段映射等参数:
crawler: sleep_min: 1 sleep_max: 3 output_dir: "./data/raw" hdfs: input_dir: "/user/hadoop/movie/input" analysis_dir: "/user/hadoop/movie/analysis" spark: app_name: "MovieBoxOfficeAnalysis" master: "local[2]"12.3 纪律与合规
爬虫任务要在代码里固定请求间隔,不要为了数据量而暴力抓取。目标页面明确声明不允许爬取的,换数据源,不要硬碰。涉及点评、影评这类用户生成内容时,避免采集用户个人信息,只保留脱敏后的统计数据。
12.4 答辩演示建议
演示时不要只展示“项目跑起来了”,要按链路讲:
- 展示爬虫日志,说明采集了哪些字段。
- 打开 HDFS 目录,展示原始数据文件。
- 展示 Spark 分析结果表。
- 最后打开可视化页面,让图表和前面的分析结果互相印证。
- 现场手动执行一次批量脚本,展示从采集到展示的完整链路。
13. 总结与下一步
这个选题最值得尝试的点在于:你不需要很高的硬件成本,就能亲手跑通一条从数据采集到可视化展示的大数据完整链路。如果你正在准备毕业设计,第一步先不要碰 Hadoop 集群,先从爬虫开始,把字段定好、数据抓下来、用本地 Spark 跑出 Top 10 和趋势图,看到真实数据后再接入 HDFS。这个顺序能省掉大量“环境没配好导致分析没数据”的无效时间。
最容易踩的坑非常集中:Hadoop 版本和 JDK 版本不兼容、第一次格式化 NameNode 后重复格式化导致集群起不来、Spark 读取 JSON 时字段名不匹配导致结果为空。这三个坑解决掉,整个项目就稳了一半。
如果后面还想继续深入工程方向,可以试试把爬虫接入 Kafka 做实时数据管道,或者引入 Hive 做数仓分层,把“离线批处理”升级成更完整的生产级架构。不要急于加实时计算,先把离线链路做扎实,这个项目的底子就够用了。