网易云音乐数据可视化大屏:Python爬虫+Django+ECharts用户画像实战 简介一份基于Python与Django开发的网易云音乐可视化项目压缩包面向计算机专业学生的毕业设计、课程设计及数据分析实践涵盖用户画像构建与播放行为分析两大核心模块。包内共54个文件以24个Python脚本为主体辅以11个编译后的pyc文件、7张可视化PNG图表、4份CSV数据文件以及环境配置说明、设计报告PDF和详细文档压缩包整体仅10.57MB结构清晰便于学习。该项目已在CSDN平台获得62人关注学习。代码经过严格测试可稳定运行配套的设计报告与爬虫说明文档能帮助快速理解架构读者既能直接复现大屏效果也可基于现有源码扩展新功能是完成毕设、课设或技术演示的高质量参考。压缩包内还包含依赖清单、爬虫脚本和字体文件等文件分类明确方便直接配置环境与按模块查阅。1. 网易云音乐可视化拿 Django 大屏项目实战用户画像与播放行为分析毕业设计或者课程设计想做一个能演示、能截图、能写进论文的完整项目这个网易云音乐可视化资源算是比较典型的一条路径爬虫抓数据 → MySQL 存数据 → Django 做接口 → ECharts 渲染大屏。技术栈不算新但胜在链路完整从数据采集到前端展示都有现成代码不用自己拼凑。项目核心围绕「用户画像 播放行为分析」展开爬取的是网易云音乐歌单与热歌榜数据最后落到可视化大屏上。适合正在选毕设方向、或者想快速搭一个数据可视化原型验证思路的同学。下文从架构选型、数据采集、后端接口到 ECharts 大屏逐步拆解最后把我在复现过程中踩过的坑一并列出来。2. 项目架构与选型为什么是 Scrapy MySQL Django ECharts整套系统的链路并不复杂但每一层选型都有其目的。先看清楚全局再动手改代码效率会高很多。2.1 分层结构与数据流向这个项目按照数据流向可以拆成四个模块数据采集层、存储层、服务层、展示层。数据采集层用 Scrapy 爬取网易云音乐热歌榜的歌单信息、歌曲信息和评论数据存储层统一进 MySQL服务层是 Django 应用对外提供 JSON 接口展示层是 HTML 页面加 ECharts 图表构成的大屏。数据流是单向的从爬虫到数据库再从数据库到接口最后渲染到页面。这种设计的好处是每一层都可以独立替换比如把 Scrapy 换成 requests 脚本或者把 MySQL 换成 SQLite都不会影响其他模块。2.2 为什么选这几样技术而不是其他方案Scrapy 的选择理由在于它自带请求调度、去重、管道Pipeline和 Item 定义写爬虫不需要自己造轮子。相比 requests BeautifulSoup 的手写方案Scrapy 在断点续爬、错误重试和并发控制上更省心。但代价是学习曲线稍陡新手容易在 settings.py 的配置上卡住。Django 在这里承担的是「数据服务」角色而不是传统意义上的业务系统。因为项目核心是可视化展示Django 只需要提供几个 JSON 接口配合 Django 自带的 ORM 做简单的聚合查询就能省去手写 SQL 拼接的麻烦。如果你对 Django 不熟也可以用 Flask 或 FastAPI 替换但那样需要自己处理跨域CORS、序列化等问题项目里的代码就无法直接复用了。存储层用 MySQL 是比较务实的选择。网易云音乐的歌曲和歌单数据量级在几万条上下MySQL 完全能承受。MySQL 配合 Navicat 或命令行工具做数据检查和调试都很方便。展示层 ECharts 是这类项目的标配。大屏场景下需要同时呈现多张图表ECharts 的图表类型覆盖了饼图、柱状图、折线图、地图等而且自带主题和动画效果写起来比 Highcharts 灵活比 D3 简单很多。2.3 目录结构与核心文件定位拿到解压后的项目你不会直接看到所有源码因为压缩包里有几份说明文档和设计报告。建议按下面的顺序去读文件/目录作用NEMCrawler/Scrapy 爬虫工程目录包含 spiders、pipelines、items 等模块NeteaseCloudMusicDataAnalysis/Django 工程目录包含 settings、urls、views 等song_reco/歌曲推荐或数据分析相关代码具体看内部 READMEdata/与data_apply/数据文件与数据应用脚本设计报告.pdf系统设计文档写论文时可以直接参考框架说明介绍.md项目运行说明包含环境依赖与启动步骤提示先看说明文档再跑代码。这个项目不是单文件脚本而是完整的工程结构跳过文档直接跑容易在环境依赖上翻车。2.4 环境准备requirements.txt 里的坑项目根目录提供了requirements.txt执行以下命令安装依赖pip install -r requirements.txt安装完成后用pip list检查一下关键包是否到位。常见的坑有三个一是 Django 和 Scrapy 的版本可能和 Python 版本不匹配Python 3.10 以上对 Scrapy 的旧版本兼容性不好建议把 Scrapy 升级到 2.11 以上二是 MySQL 驱动mysqlclient在 Windows 上经常编译失败需要提前安装 Visual C Build Tools 或者改用pymysql并在 Django 的__init__.py里加一段代码import pymysql pymysql.install_as_MySQLdb()三是requirements.txt里可能缺少django-cors-headers如果前端页面和后端接口分属不同端口跨域请求会报错需要手动补装。3. 数据采集层Scrapy 爬虫的页面解析与字段设计爬虫是整个项目的数据来源这部分出问题后面所有可视化都是空谈。很多同学会卡在「爬不下来」或者「字段对不上」所以我从实际代码层面把关键逻辑拆开讲。3.1 爬虫的入口与解析规则网易云音乐的 Web 端是动态渲染的直接请求 HTML 拿不到完整的歌单数据。这个项目的解决方案是请求网易云的 API 接口而不是解析页面 HTML。查看NEMCrawler/spiders/下的爬虫文件核心逻辑大致是这样的import scrapy import json class CloudMusicSpider(scrapy.Spider): name cloud_music def start_requests(self): # 热歌榜接口limit 控制返回条数 url https://music.163.com/api/playlist/detail?id3778678 yield scrapy.Request(url, callbackself.parse_playlist) def parse_playlist(self, response): data json.loads(response.text) tracks data.get(result, {}).get(tracks, []) for track in tracks: yield { song_name: track.get(name), artist: track.get(artists, [{}])[0].get(name), album: track.get(album, {}).get(name), duration: track.get(duration), play_count: track.get(playCount), comment_count: track.get(commentCount), }这段代码直接请求网易云的音乐列表接口然后从 JSON 里提取需要的字段。注意id3778678是某个热歌榜的歌单 ID如果你要换榜单替换这个 ID 即可。字段层面duration是毫秒单位入库时需要换算成秒或者分钟否则后续展示会有问题。3.2 Item 定义与 Pipeline 清洗光有yield字典还不够Scrapy 的规范做法是定义 Item 类把字段约束写清楚。项目里items.py大概长这样import scrapy class MusicItem(scrapy.Item): song_id scrapy.Field() song_name scrapy.Field() artist scrapy.Field() album scrapy.Field() duration scrapy.Field() play_count scrapy.Field() comment_count scrapy.Field()字段定义好之后数据会进入 Pipeline 做清洗和入库。Pipeline 是 Scrapy 里最容易忽略但最重要的环节默认情况下它不处理任何东西只有你在settings.py里显式启用才会生效ITEM_PIPELINES { NEMCrawler.pipelines.MusicPipeline: 300, } # MySQL 连接配置 MYSQL_HOST localhost MYSQL_PORT 3306 MYSQL_USER root MYSQL_PASSWORD your_password MYSQL_DATABASE cloud_musicPipeline 里最常见的操作是去重、类型转换和缺失值填充。比如播放量字段可能是字符串需要转成 int歌曲名可能为空需要填默认值。项目管线上对这些都有处理写论文时可以把这块作为「数据预处理」章节展开。3.3 爬虫运行与数据落库在NEMCrawler目录下执行scrapy crawl cloud_music如果一切正常终端会滚动输出抓取日志结束后用SELECT COUNT(*) FROM song;检查数据量。这里有个容易误操作的点执行爬虫前要先建好数据库和表结构数据库的建表 SQL 一般在项目的data目录下或者写在说明文档里。如果建表语句缺失可以直接根据 Item 字段手写 CREATE TABLE。注意网易云音乐的接口有过反爬策略升级表现为请求返回 403 或者[403] The request is blocked。常见解法是给start_requests加上 Cookie 和 Referer 头或者降低请求速率。项目里可能没有内置延迟建议在settings.py里设置DOWNLOAD_DELAY 1.0单位是秒避免高频请求被限流。4. 后端服务层Django 接口设计与数据聚合爬虫把数据存进 MySQL 之后接下来要解决的是「数据怎么变成接口」。Django 在这个项目里不算复杂但要理解它的工作方式模型Model对应数据表、视图View负责查询、URL 负责路由。4.1 模型定义与数据库映射Django 的 ORM 可以不用手写 SQL直接定义模型类。项目的models.py里会有一个和歌曲表对应的模型大致如下from django.db import models class Song(models.Model): song_id models.IntegerField(primary_keyTrue) song_name models.CharField(max_length200) artist models.CharField(max_length100) album models.CharField(max_length200) duration models.IntegerField() play_count models.IntegerField() comment_count models.IntegerField() class Meta: db_table songdb_table指定了表名要和爬虫写入的物理表一致。如果表名对不上Django 会报Table song doesnt exist或者反过来查询为空。这里踩坑的概率很高因为 Scrapy 建表时的命名风格和 Django 默认的应用名_小写类名不一样需要手动指定。4.2 视图函数与聚合查询接口的逻辑不复杂核心是几个聚合查询。比如统计歌曲评论数的分布区间、播放量 TOP10、歌手歌曲数量排行这些在 Django ORM 里都可以一行搞定。facets 统计的接口代码可以这样写from django.http import JsonResponse from django.db.models import Count, Sum, Avg from .models import Song def artist_rank(request): # 按歌手分组统计每位歌手的歌曲数量取前 20 result ( Song.objects.values(artist) .annotate(totalCount(song_id)) .order_by(-total)[:20] ) data list(result) return JsonResponse({code: 0, data: data})这段代码里values(artist)的意思是按歌手字段分组annotate(totalCount(song_id))为每一组计算歌曲数量order_by(-total)按总量倒序排[:20]只取前 20 条。最终返回的JsonResponse是标准 JSON前端直接能用。类似的统计还可以做歌手平均播放量、评论数最多的专辑、歌曲时长分布等。每个统计对应一个视图函数然后注册到urls.py里。4.3 URL 路由配置与跨域处理路由配置在urls.py里注意 Django 3.x 之后的写法有变化正则路径用re_path普通路径用pathfrom django.urls import path from . import views urlpatterns [ path(api/artist_rank/, views.artist_rank), path(api/play_distribution/, views.play_distribution), path(api/comment_top/, views.comment_top), path(api/user_profile/, views.user_profile), ]启动服务之后浏览器访问http://127.0.0.1:8000/api/artist_rank/应该能看到 JSON 数据。如果前端页面在另一个端口比如用 Live Server 打开就需要在 Django 里启用跨域推荐装django-cors-headers并在settings.py的MIDDLEWARE中加入corsheaders.middleware.CorsMiddleware同时设置CORS_ALLOW_ALL_ORIGINS True仅限开发环境。提示Django ALLOWED_HOSTS 的配置也会导致访问 400 错误开发调试时建议直接设为ALLOWED_HOSTS [*]。生产部署再收窄范围。5. 可视化大屏ECharts 配置与数据对接实战数据接口通了之后最后一步就是把数字变成图表。这一章是大屏效果的关键也是答辩时最出彩的部分。5.1 大屏布局与图表拆解项目里的可视化大屏是一个单页多图表布局常见的做法是把页面分成几个区域左侧放用户画像相关图表如年龄分布、性别占比、中间放核心 KPI 数字和播放趋势、右侧放歌手排行和热门歌曲。整体采用深色背景、亮色图表的设计这在 ECharts 里通过主题配置实现。div 布局可以参考下面的结构div classdashboard div classleft-panel div idgender_chart/div div idage_chart/div /div div classcenter-panel div idplay_trend/div div idkpi_numbers/div /div div classright-panel div idartist_rank_chart/div div idsong_rank_chart/div /div /div每个div对应一个 ECharts 实例CSS 控制尺寸和位置。大屏的视觉风格主要靠背景色、边框和图表间距实现不需要引入额外的 UI 框架。5.2 用 fetch 拉取 Django 接口并渲染图表ECharts 本身不关心数据从哪来它只负责渲染。项目里的常见写法是用 fetch 访问 Django 的 JSON 接口然后把数据组装成 ECharts 需要的格式。以歌手排行榜为例async function loadArtistRank() { const response await fetch(http://127.0.0.1:8000/api/artist_rank/); const result await response.json(); const names result.data.map(item item.artist); const counts result.data.map(item item.total); const chart echarts.init(document.getElementById(artist_rank_chart)); chart.setOption({ title: { text: 歌手歌曲数量 TOP20, textStyle: { color: #fff } }, tooltip: {}, xAxis: { type: category, data: names, axisLabel: { color: #fff } }, yAxis: { type: value }, series: [{ type: bar, data: counts, itemStyle: { color: #5b8ff9 } }] }); } loadArtistRank();注意这里map出来的数组必须和 ECharts 的数据格式一致。柱状图的xAxis.data是类目数组series.data是数值数组。如果接口返回的字段名和代码里对不上图表会是空的。5.3 数据联动与定时刷新大屏项目里有一个常见的需求是定时轮询接口让图表自动更新。实现方式是在页面加载后开启一个setInterval每隔一段时间重新 fetch 数据并setOptionsetInterval(() { loadArtistRank(); loadPlayTrend(); loadUserProfile(); }, 60000);这里的坑在于 ECharts 实例的复用。如果每次重新初始化实例旧的图表会报There is a chart instance already initialized on the dom解决办法是在setOption前调用chart.dispose()或者直接复用同一个实例仅更新option。项目代码里一般会采用后者因为更轻量。5.4 ECharts 配置的调试技巧如果图表渲染出来是空白优先打开浏览器控制台看报错。常见问题有三种JSON 接口返回了但数据格式不对、ECharts 和 jQuery 等库的引入顺序错了、容器 div 的高度为 0。最后一种很隐蔽因为 ECharts 默认要求容器有明确的宽高CSS 里给每个图表 div 设height: 400px或height: 50%才能正常渲染。注意跨域问题在本地开发中表现为Access-Control-Allow-Origin报错和图表配置无关优先检查 Django 是否启用了 CORS。6. 运行避坑记录环境配置到页面渲染的五个高频问题这一章把这套项目从解压到跑通全流程里最常遇到的五个问题写透每一条都是我实际踩过或者帮别人排过的。问题一Scrapy 启动报错ModuleNotFoundError: No module named win32api现象是scrapy crawl cloud_music执行后立即报错退出。原因是 Scrapy 在 Windows 上依赖pywin32这个库但requirements.txt里通常没有包含它。解决方式很简单pip install pywin32装完重启终端再执行爬虫命令即可。除了win32api在 Windows 上还可能会遇到Twisted安装失败的问题Python 3.8 以上的版本建议直接用pip install twisted拉最新版旧版本容易编译报错。问题二Django 启动时报django.core.exceptions.ImproperlyConfigured现象是python manage.py runserver之后提示数据库配置错误或者 mysqlclient 版本问题。大部分情况是 MySQL 驱动没装好。如果你在 Windows 上直接装mysqlclient多半会失败我建议改用pymysql然后在 Django 工程的__init__.py里写入import pymysql pymysql.install_as_MySQLdb()注意这段代码一定要放在django.setup()或者runserver之前生效所以写在__init__.py里最保险。问题三MySQL 中文乱码现象是爬虫抓到的歌曲名、歌手名在数据库里显示为???。原因是数据库连接字符集没有设置为 utf8mb4。解决方法是建库时指定CREATE DATABASE cloud_music DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;同时修改 Django 的DATABASES配置和 Scrapy 的 MYSQL 连接字符串加上charsetutf8mb4参数。MySQL 连接时如果漏了这一项中文写入后查出来就是乱码而且这个乱码是不可逆的只能删掉重爬。问题四接口能访问但前端图表不渲染现象是浏览器里直接访问接口有 JSON但页面是空白或者报Cannot read properties of undefined。这类问题九成出在数据字段不匹配比如 ECharts 里写的是item.artist接口返回的键名是artists。调试手段是在成功拿到响应的位置加一条console.log(result)把返回的 JSON 结构和代码里的字段逐一对照。快速定位方法如下fetch(http://127.0.0.1:8000/api/artist_rank/) .then(response response.json()) .then(data console.log(JSON.stringify(data, null, 2)));问题五大屏页面打开后只有背景没有图表现象是页面加载了但所有图表区域全是空白。先按 F12 打开开发者工具查看 Console 是否有 JavaScript 报错。如果没有报错几乎可以断定是容器高度问题——div 的height没设置或者为 0导致 ECharts 无法初始化。解决办法是在 CSS 里给对应的 div 设固定高度或者用window.onresize事件配合chart.resize()方法让图表随窗口自适应。window.addEventListener(resize, () { artistChart.resize(); playTrendChart.resize(); });以上五个问题覆盖了从爬虫到前端渲染的完整链路。遇见报错时不要一个一个试先看日志定位到层再对照上面的条目排掉。从那以后我每次复现这种多模块项目都强制走一遍「先通爬虫、再验字段、最后查页面」的顺序能省掉大半天的排查时间希望帮到你。本文还有配套的精品资源点击获取