大数据毕业设计实战:基于网易云音乐爬虫的音乐数据采集、分析与可视化系统架构
毕业设计最怕“数据断粮”。去年做音乐分析项目时,我把网易云当数据源,结果一周就被封 IP,动态页面还拿不到评论。踩坑无数后,把整套方案重新梳理成“可复现、可演示、可扩展”的模板,最终答辩拿了 A。下文把踩坑笔记和代码全部拆开,照着搭,两周就能跑出一条稳定的数据链路。
1. 背景与典型痛点
音乐平台数据价值高,却也是反爬“重灾区”。我遇到的三大坑:
- 动态渲染:热门榜单、评论翻页全靠 JS 渲染,单纯 Requests 抓到的 HTML 是空骨架。
- 登录态维持:每日推荐、私人雷达需要 Cookie + CSRF Token,一旦失效就 302 跳转登录页。
- IP 封禁:相同出口 IP 请求超过 60 次/分钟,接口直接返回
-460 "Cheating",且封 24 h。
再加上毕设时间紧、机器性能有限,方案必须“轻量可落地”,否则数据量撑不到“大”字。
2. 技术选型对比
2.1 爬虫框架
| 维度 | Scrapy | Playwright |
|---|---|---|
| 学习曲线 | 低,文档全 | 中,需懂浏览器上下文 |
| 动态页面 | 需配合 Splash/Selenium | 原生支持 |
| 并发模型 | Twisted 异步,百并发 | 浏览器实例重,10 并发以内 |
| 内存占用 | <200 MB | 每实例 ~150 MB |
| 可扩展 | 中间件/管道丰富 | 需自己封装 |
结论:
- 列表页、评论接口用 Scrapy 直接抓 API,速度优先;
- 登录、验证码、JS 加密参数用 Playwright 一次拿 Cookie,后续把 Cookie 池化给 Scrapy 复用。
两者混部,既省资源又避开浏览器长驻实例。
2.2 流式计算
| 维度 | Spark Structured Streaming | Flink |
|---|---|---|
| 批流一体 | 与毕设批代码共用一套 SQL | 需额外 Table API |
| 资源消耗 | 单节点也能跑 micro-batch | 最低 2 GB JM+TM |
| 社区资料 | 中文博客多 | 相对少 |
| 代码量 | 30 行搞定 Kafka→MySQL | 需理解 Checkpoint |
结论:
毕设阶段“能跑就行”,选 Spark;后期若需要毫秒级延迟再迁 Flink。
3. 核心实现细节
3.1 整体链路
浏览器取 Cookie → Scrapy 抓取 → Kafka → Spark Streaming → MySQL → Vue + ECharts
3.2 请求头轮换中间件
网易云只检查User-Agent与Referer,不验签名即可拿到 90% 公开接口。下面中间件每 3–7 次请求换一套 UA,并随机睡眠,降低被封概率。
# middlewares.py import random, time, logging from scrapy.downloadermiddlewares.useragent import UserAgentMiddleware UA_LIST = [ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) ...", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)...", # 更多略 ] class RotateUAAndDelayMiddleware(UserAgentMiddleware): def __init__(self, crawler): super().__init__() self.crawler = crawler @classmethod def from_crawler(cls, crawler): return cls(crawler) def process_request(self, request, spider): request.headers["User-Agent"] = random.choice(UA_LIST) request.headers["Referer"] = "https://music.163.com/" # 随机 0.3–1.2 s 睡眠,降低 QPS time.sleep(random.uniform(0.3, 1.2)) return None3.3 Cookie 池化
Playwright 登录后把 Cookie 写 Redis,Scrapy 启动时随机取一条注入Cookie头,实现“登录态”复用。
# cookies.py import json, redis, random, os rdb = redis.Redix(host="localhost", port=6379, decode_responses=True) def random_cookie(): key = random.choice(rdb.keys("netease:cookies:*")) return json.loads(rdb.get(key))3.4 验证码绕过(仅限公开接口)
网易云网页端登录会弹极验滑块验证码,但手机登录接口(/weapi/login/cellphone)在相同 IP 低频率下很少出现。毕设场景用一次性手动登录 + Cookie 池即可,不碰打码平台、不破解滑块,保持合法合规。
3.5 数据清洗逻辑
原始评论 JSON 示例:
{ "user": {"userId": 123, "nickname": "xxx", "avatarUrl": "http://..."}, "content": "好听!", "time": 1710000001234, "likedCount": 42 }清洗目标:
- 时间转 yyyy-MM-dd HH:mm:ss
- 用户 ID 仅保留前 8 位哈希,脱敏
- 过滤 emoji、只保留中英文数字
Spark 代码片段:
// CommentETL.scala val df = spark.read.json("kafka://...") val cleaned = df.select( hash($"user.userId").alias("uid_hash"), regexp_replace($"content", "[^\\u4e00-\\u9fa5a-zA-Z0-9]", "").alias("content"), from_unixtime($"time"/1000).alias("comment_time"), $"likedCount".alias("like") ) cleaned.write.mode("append").jdbc(url, "comment_clean", prop)4. 性能与安全性
频率控制
单出口 IP 限制 40 次/分钟,通过scrapy.extensions.throttle.AutoThrottle自动调整并发。隐私字段脱敏
用户 ID 哈希、手机号/邮箱字段直接丢弃,只保留地区、性别、等级等可公开聚合维度。数据幂等写入
Kafka 以 “songId + commentId” 为 key,Spark 使用foreachBatch + INSERT ... ON DUPLICATE KEY UPDATE,保证重复跑作业不脏数据。日志脱髓
关闭scrapy.log的DOWNLOAD_DELAY明细,生产日志只保留 WARN,防止 Cookie 泄露。
5. 生产环境避坑指南
冷启动延迟
Spark Streaming 默认processingTime最小 1 s,首次拉 Kafka 空分区会报OffsetOutOfRange。解决:启动前脚本kafka-consumer-groups --reset-offsets --to-earliest。Docker 时钟漂移
容器化部署时,宿主机与容器 UTC 不一致会导致 Cookie 的__csrf提前过期。统一挂ntp服务。反爬升级
2024 上半年起,部分接口新增eparams加密参数。监控返回体出现"xxx cheating"时自动暂停爬虫,并推送钉钉告警,人工确认后再切代理池。代理池成本
免费代理 90% 不可用,建议 2 元/天的隧道代理即可满足毕设 5 万条/日需求,不必自建池。
6. 可运行最小闭环 Demo
目录结构:
music_bigdata/ ├─ scrapy/ # 爬虫 ├─ streaming/ # Spark 作业 ├─ dashboard/ # Vue + ECharts └─ docker-compose.yml一键启动:
$ git clone https://github.com/yourname/music_bigdata.git $ cd music_bigdata $ docker-compose up -d # 拉起 zookeeper/kafka/mysql/redis $ cd scrapy $ scrapy crawl comment -a song_id=186016 -L WARN $ cd ../streaming $ spark-submit --master local[*] CommentETL.scala $ cd ../dashboard && npm i && npm run dev浏览器打开http://localhost:8080即可看到实时评论词云、情感占比、榜单趋势三张图,答辩演示够用。
7. 后续可扩展方向
- 多平台融合:QQ 音乐、酷狗、Spotify 均有公开榜单 API,统一 songId 用 ISRC 做映射,可对比跨平台热度。
- 推荐算法:在现有“用户-歌曲-评分”矩阵上,直接调用 Spark MLlib 的 ALS,10 行代码就能跑出个性化推荐,把模型服务用 Flask 封装成 REST API,即升级为“音乐推荐系统”。
- 实时情感分析:评论流进 Kafka 后调用 HuggingFace 情感模型,把结果写回 Druid,实现秒级情感监控大屏。
整套代码已上传 GitHub,欢迎提 PR 一起完善。毕业设计不是终点,把数据链路开源出来,下一届学弟学妹就不用再被-460折磨了。