B站用户行为分析系统源码解析:Python爬虫与数据可视化实战
简介这是一套面向课程设计与Python后端学习者的B站用户行为分析系统完整项目源码适合数据科学、机器学习方向的学生和开发者作为实战参考。项目通过爬虫采集观看历史、弹幕、评论等行为数据结合Pandas、Matplotlib完成清洗与可视化并尝试用聚类、关联规则等方法挖掘用户偏好与内容流行趋势最终输出用户画像和内容推荐列表配套界面可查看分析结果与报告。资源包共427个文件约72.41MB以png图表、js脚本、html页面、py源码及pyc缓存为主另含css样式、svg图标、sql建表脚本、pkl模型文件与doc说明文档覆盖数据爬取、处理、分析、可视化及前端展示的完整链路。目前已有252人学习下载读者可据此理解从数据采集到推荐输出的工程结构并借鉴其模块划分与排错思路。1. 从一份 B 站用户行为分析系统源码说起它到底能跑出什么如果你手头正好有一份python项目基于B站用户行为分析系统.zip第一反应大概率是这玩意儿能直接跑吗跑完能出什么图我拆过不少课程设计类的 Python 项目这份属于典型的「爬虫 数据分析 可视化 Web 界面」四件套。它的核心链路很清晰用爬虫抓取 B 站用户的观看历史、弹幕、评论等行为数据落到本地做清洗再用 Pandas 做聚合、Matplotlib 出图最后套一个前端页面把用户画像和内容推荐列表展示出来。适合两类人一是正在做课程设计、需要一份能讲清楚链路的参考实现二是想拿真实场景练 Python 数据分析与可视化的人。但要注意它不是一个开箱即用的成品前端那堆 css 文件和爬虫脚本之间的耦合关系才是你真正要花时间的地方。2. 拆开压缩包先看结构前端资源与后端脚本怎么分工2.1 从 css 文件清单反推前端页面构成项目正文里列了一串样式文件font-awesome.min.css、home.css、icon.css、responsive.css、select2.css、base.css、select2.min.css、style.css、widgets.css、autocomplete.css。这不是随便堆的从命名能反推出前端至少有这么几块文件作用推断对应页面区域base.css全局重置与基础排版所有页面home.css首页专属布局数据概览首页style.css主样式表通用组件responsive.css响应式断点移动端适配widgets.css卡片/面板类组件图表容器select2.cssselect2.min.css下拉选择框增强筛选条件区autocomplete.css输入联想搜索框icon.cssfont-awesome.min.css图标字体导航与按钮这套组合说明前端不是纯静态页面而是带交互筛选的——有下拉、有联想搜索、有响应式。常见做法是后端用 Flask 或 Django 渲染模板前端用 jQuery Select2 做异步筛选。你拿到项目后先确认templates或static目录下有没有对应的 HTML如果没有那前端就是半成品得自己补。2.2 后端脚本的典型分层一个合格的 B 站行为分析项目后端一般分四层你对照着看压缩包里缺哪层# 典型目录结构对照你的压缩包 bilibili_analysis/ ├── spider/ # 爬虫层 │ ├── user_spider.py # 抓用户信息 │ ├── video_spider.py # 抓视频/弹幕/评论 │ └── middleware.py # 请求头、延时、重试 ├── data/ # 数据层 │ ├── raw/ # 原始 json/csv │ └── clean/ # 清洗后数据 ├── analysis/ # 分析层 │ ├── user_profile.py # 用户画像 │ ├── trend.py # 内容趋势 │ └── recommend.py # 推荐列表 ├── web/ # 展示层 │ ├── app.py # Flask 入口 │ ├── static/ # 上面那堆 css │ └── templates/ # html └── requirements.txt如果压缩包里spider和analysis混在一起说明作者图省事你后续改代码会很难受。我一般会先花十分钟把目录理成上面这样再动代码。这一步不做后面调 bug 就是黑匣子。2.3 依赖安装与首次运行的最小闭环先别急着跑全流程用最小闭环验证环境。新建虚拟环境装核心依赖python -m venv venv source venv/bin/activate # Windows 用 venv\Scripts\activate pip install requests pandas matplotlib flask beautifulsoup4 lxml pip freeze requirements.txt参数说明requests负责 HTTP 请求beautifulsoup4lxml做 HTML 解析pandas做数据清洗matplotlib出图flask起 Web 服务。如果项目里用了 Scrapy把requests换成scrapy但课程设计级别用 requests 足够。装完先跑一个单文件测试# test_env.py import requests, pandas as pd, matplotlib print(requests:, requests.__version__) print(pandas:, pd.__version__) print(matplotlib:, matplotlib.__version__) # 测试能否拿到 B 站公开接口的响应结构 resp requests.get( https://api.bilibili.com/x/web-interface/view, params{bvid: BV1xx411c7mD}, headers{User-Agent: Mozilla/5.0} ) print(status:, resp.status_code) print(keys:, list(resp.json().keys())[:5])逻辑说明这段不抓真实用户数据只验证两件事——依赖装对了没以及你的网络环境能不能正常访问公开接口。params里的bvid随便填一个公开视频号即可重点看status是不是 200。如果返回 412 或 -403说明请求头或频率有问题先解决这个再往下走。3. 爬虫层实操请求构造、字段提取与频率控制3.1 请求头与参数怎么设才不容易翻车B 站公开接口对请求头有基本校验缺User-Agent和Referer大概率吃 412。我一般固定这么写import requests, time, random 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 ), Referer: https://www.bilibili.com/, Accept: application/json, text/plain, */*, } def fetch_json(url, paramsNone, retry3): for i in range(retry): try: r requests.get(url, headersHEADERS, paramsparams, timeout10) if r.status_code 200: return r.json() # 412 通常是风控退避后重试 if r.status_code 412: time.sleep(2 ** i random.random()) except requests.RequestException as e: print(f第{i1}次失败: {e}) time.sleep(1) return None参数说明timeout10防止单请求卡死retry3配合指数退避2**i第一次等 1 秒、第二次 2 秒、第三次 4 秒加随机小数避免规律性请求。Referer必须带否则部分接口直接拒绝。这套写法比裸requests.get稳得多血泪经验。3.2 用户行为字段的提取与落盘拿到 JSON 后别整包存只留分析要用的字段。以视频评论为例import pandas as pd def parse_comments(raw_json): rows [] for item in raw_json.get(data, {}).get(replies, []) or []: rows.append({ user_id: item[member][mid], username: item[member][uname], content: item[content][message], like_count: item[like], ctime: item[ctime], video_id: item.get(oid), }) df pd.DataFrame(rows) if not df.empty: df[ctime] pd.to_datetime(df[ctime], units) return df # 落盘 df parse_comments(fetch_json( https://api.bilibili.com/x/v2/reply, params{type: 1, oid: 123456, pn: 1, ps: 20} )) df.to_csv(data/raw/comments_p1.csv, indexFalse, encodingutf-8-sig)逻辑说明oid是视频的 aidpn是页码ps是每页条数。encodingutf-8-sig是为了 Excel 打开不乱码这个细节很多人栽过。字段只留六个后续做用户画像和内容趋势都够用。注意replies可能为None所以用or []兜底。3.3 频率控制与断点续爬课程设计最容易忽略的就是频率。我一般设成每请求间隔 1.5 到 3 秒随机并且把已抓的页码记到本地断了能续import os, json def crawl_pages(oid, start1, end10, cachedata/raw/_progress.json): done set() if os.path.exists(cache): done set(json.load(open(cache))) for pn in range(start, end 1): if pn in done: continue data fetch_json( https://api.bilibili.com/x/v2/reply, params{type: 1, oid: oid, pn: pn, ps: 20} ) if data: parse_comments(data).to_csv( fdata/raw/comments_{oid}_{pn}.csv, indexFalse, encodingutf-8-sig ) done.add(pn) json.dump(list(done), open(cache, w)) time.sleep(random.uniform(1.5, 3.0))参数说明cache文件记录已完成页码重跑时自动跳过。random.uniform(1.5, 3.0)是随机间隔比固定 sleep 更自然。这套断点续爬在抓多页数据时能省大量时间尤其是中途被限流的时候。4. 分析层实操用户画像、趋势与推荐列表怎么算4.1 用 Pandas 做用户活跃度与偏好聚合爬完数据后核心分析就三块用户活跃度、内容偏好、时间趋势。先做用户维度的聚合import pandas as pd df pd.read_csv(data/raw/comments_all.csv, parse_dates[ctime]) # 用户活跃度评论数 获赞数 user_stats df.groupby([user_id, username]).agg( comment_count(content, count), total_likes(like_count, sum), first_active(ctime, min), last_active(ctime, max), ).reset_index() # 活跃天数跨度 user_stats[active_days] ( user_stats[last_active] - user_stats[first_active] ).dt.days 1 # 简单分层高频/中频/低频 def level(n): if n 10: return 高频 if n 3: return 中频 return 低频 user_stats[level] user_stats[comment_count].apply(level) user_stats.to_csv(data/clean/user_profile.csv, indexFalse, encodingutf-8-sig)逻辑说明groupby按用户聚合agg同时算评论数、总赞数、首末活跃时间。active_days用时间差加 1避免同天活跃算成 0 天。分层阈值 10 和 3 是经验值你可以根据数据量调。这份user_profile.csv就是用户画像的基础表。4.2 内容趋势与可视化出图趋势分析按天聚合再用 Matplotlib 出图import matplotlib matplotlib.use(Agg) # 无界面环境必须加 import matplotlib.pyplot as plt df[date] df[ctime].dt.date daily df.groupby(date).size().reset_index(namecount) plt.figure(figsize(10, 4)) plt.plot(daily[date], daily[count], markero, linewidth1.5) plt.title(Daily Comment Trend) plt.xlabel(Date) plt.ylabel(Comments) plt.xticks(rotation45) plt.tight_layout() plt.savefig(web/static/trend.png, dpi120)参数说明matplotlib.use(Agg)是关键服务器或无显示器环境不加这句直接报错。dpi120平衡清晰度和文件大小。tight_layout()防止日期标签被裁掉。图存到static目录前端直接引用。4.3 关联规则做内容推荐的简化实现推荐列表不用上复杂模型课程设计级别用共现统计就够from itertools import combinations from collections import Counter # 假设同一用户评论过的视频集合 user_videos df.groupby(user_id)[video_id].apply(set) pair_counter Counter() for vids in user_videos: if len(vids) 2: for pair in combinations(sorted(vids), 2): pair_counter[pair] 1 # 取共现最高的前 10 对 top_pairs pair_counter.most_common(10) print(top_pairs)逻辑说明combinations生成同一用户看过的视频两两组合Counter统计共现次数。共现越高说明两个视频的受众重叠越大可以作为「看了 A 的人也看 B」的推荐依据。这是关联规则里最朴素的实现不用装mlxtend也能跑。如果项目里用了 Apriori把这段替换掉即可但思路一致。5. 避坑与排查这份源码最容易翻车的五个地方5.1 接口返回 412 或 -403现象请求 B 站接口时状态码 412或 JSON 里code为 -403。原因请求头缺失、频率过高、或 IP 被临时限制。解决补全User-Agent和Referer把间隔调到 2 秒以上加重试退避。如果持续 412换时间段再跑别硬刚。5.2 前端页面样式全丢现象Flask 起来后页面能打开但没有任何样式图标也不显示。原因static目录路径没配对或url_for(static, filename...)写错。解决确认app.py里static_folder指向正确HTML 里所有 css 引用走url_for。font-awesome.min.css还要确认字体文件路径缺字体图标就是方块。5.3 中文乱码现象CSV 用 Excel 打开全是乱码或图表标题中文变方块。原因编码不一致或 Matplotlib 没设中文字体。解决落盘统一utf-8-sigMatplotlib 加plt.rcParams[font.sans-serif] [SimHei]和plt.rcParams[axes.unicode_minus] False。Linux 没 SimHei 就装fonts-noto-cjk。5.4 爬虫中途断掉要重头跑现象抓了几百页网络一抖全白干。原因没有断点记录。解决用第 3.3 节的_progress.json方案每完成一页写一次。重跑时自动跳过已完成页码。这个后悔药一定要提前吃。5.5 依赖版本冲突现象pip install报错或跑起来ImportError。原因requirements.txt里版本锁太死或 Python 版本不匹配。解决先看项目要求的 Python 版本课程设计一般 3.8 都行。装依赖时先不锁版本跑通后再pip freeze固化。遇到lxml装不上换pip install lxml --pre或直接用html.parser替代。6. 进阶技巧把分析结果接进 Web 界面并做参数化筛选最后一章说个实用的怎么把分析结果真正接到前端并且支持按时间、按用户分层筛选。很多人跑完脚本就停了图表是静态图片没法交互。我一般会加一个轻量接口# web/app.py from flask import Flask, render_template, request, jsonify import pandas as pd app Flask(__name__) df pd.read_csv(data/clean/user_profile.csv) app.route(/) def index(): return render_template(home.html) app.route(/api/users) def api_users(): level request.args.get(level, ) min_comments int(request.args.get(min_comments, 0)) sub df[df[comment_count] min_comments] if level: sub sub[sub[level] level] return jsonify(sub.head(100).to_dict(orientrecords)) if __name__ __main__: app.run(debugTrue, port5000)逻辑说明/api/users接收level和min_comments两个查询参数返回筛选后的前 100 条记录。前端用fetch调这个接口配合select2做下拉筛选就能实现动态刷新。debugTrue只在开发时开部署要关掉。前端调用示例// static/js/filter.js async function loadUsers(level, minComments) { const url /api/users?level${level}min_comments${minComments}; const resp await fetch(url); const data await resp.json(); const tbody document.querySelector(#user-table tbody); tbody.innerHTML data.map(u trtd${u.username}/tdtd${u.comment_count}/tdtd${u.level}/td/tr ).join(); } document.querySelector(#level-select).addEventListener(change, e { loadUsers(e.target.value, 0); });参数说明level对应下拉框的值min_comments可以再接一个输入框。fetch返回 JSON 后直接拼表格不用引入前端框架。这套组合在课程设计里足够撑起「交互式分析」的演示效果。验证方法启动 Flask 后访问http://127.0.0.1:5000/api/users?level高频min_comments5看返回的 JSON 里comment_count是不是都大于等于 5level是不是都是高频。对得上说明筛选逻辑通了。再打开首页切换下拉框表格实时刷新整个链路就闭环了。从那以后我每次拿到这类课程设计源码都强制先跑一遍最小闭环再按「爬虫 → 清洗 → 分析 → 接口 → 前端」的顺序逐层验证绝不一次性全跑。希望帮到你。本文还有配套的精品资源点击获取

相关新闻

QEMU 中的 Kyoto Microcomputer KZM-ARM11-01 板卡模拟(`kzm`):基于 i.MX31 SoC 的 ARM1136 评估板实战指南

QEMU 中的 Kyoto Microcomputer KZM-ARM11-01 板卡模拟(`kzm`):基于 i.MX31 SoC 的 ARM1136 评估板实战指南

虚拟化硬件仿真 【免费下载链接】qemu Official QEMU mirror. Please see https://www.qemu.org/contribute/ for how to submit changes to QEMU. Pull Requests are disabled. Please only use release tarballs from the QEMU website. 项目地址: https://gitcod…

2026/9/23 22:45:59 阅读更多 →
无人机巡维保障系统后端:状态机与轨迹数据处理实践

无人机巡维保障系统后端:状态机与轨迹数据处理实践

简介:基于Java语言的uav-patrol-backend巡维保障系统后端源码,面向无人机巡维业务的后端开发人员,提供了一套模块化、可扩展的服务端实现,可支撑无人机巡维任务管理、设备状态监控与数据上报等核心服务。项目包含51个文件、共93KB…

2026/9/25 1:05:32 阅读更多 →
12306抢票源码拆解:Java+Python多语言混编的自动化链路设计与实现

12306抢票源码拆解:Java+Python多语言混编的自动化链路设计与实现

简介:面向需要优化12306转移仓库管理效率的Java开发者,这套源码实现完整覆盖系统核心业务链路,从登录认证、余票查询、订单提交到人脸核验等环节均有对应代码模块,适合中高级程序员借鉴其多语言融合的工程化落地方式。资源包共86个…

2026/9/25 1:06:11 阅读更多 →

最新新闻

MT管理器核心功能实战:dex编辑、APK修改与签名技巧解析

MT管理器核心功能实战:dex编辑、APK修改与签名技巧解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/25 1:05:18 阅读更多 →
视频剪辑素材网站全攻略:免费商用素材库推荐与版权避坑指南

视频剪辑素材网站全攻略:免费商用素材库推荐与版权避坑指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/25 1:05:18 阅读更多 →
十年PLC老手用AI写ST程序:提示词模板与实战避坑指南

十年PLC老手用AI写ST程序:提示词模板与实战避坑指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/25 1:05:18 阅读更多 →
Elasticsearch 7.15.2安装IK中文分词器:解决中文搜索分词难题

Elasticsearch 7.15.2安装IK中文分词器:解决中文搜索分词难题

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/25 1:05:18 阅读更多 →
STM32寄存器与HAL库双视角开发实战:从点灯到项目进阶

STM32寄存器与HAL库双视角开发实战:从点灯到项目进阶

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/25 1:05:18 阅读更多 →
M.2接口与Key识别指南:从SSD到无线网卡不再买错

M.2接口与Key识别指南:从SSD到无线网卡不再买错

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/25 1:04:17 阅读更多 →

日新闻

AI元人文:从工具使用到思维重构的深度探索

AI元人文:从工具使用到思维重构的深度探索

最近半年我一直在琢磨一件事:AI元人文到底是什么?说白了,就是“用元视角重新审视人与AI的关系”,也在“探索AI如何反向逼着我们发现自己的思考边界”。标题里的“元探索”,在我看就是一层套一层的追问——当你用AI解决…

2026/9/25 0:00:41 阅读更多 →
Python+CNN车牌识别实战:从数据预处理到模型训练与部署

Python+CNN车牌识别实战:从数据预处理到模型训练与部署

简介:基于Python与卷积神经网络的车牌识别项目,面向计算机视觉初学者及智能交通开发者,目标是帮助用户掌握从数据预处理、模型构建到实际部署的完整流程。压缩包共25个文件,包含jpg/png图像样本、py训练脚本、md说明文档、dat数据…

2026/9/25 0:00:41 阅读更多 →
Vim基础操作全攻略:保存退出、模式切换与高频命令实战

Vim基础操作全攻略:保存退出、模式切换与高频命令实战

1. 项目概述1.1 核心需求解析今天聊聊Vim。写这个题目的原因是:几乎每个后端开发者、运维人员、数据工程师某天都会遇到一个场景——深夜加班,服务器登录界面只有黑底白字,编辑器只有vi/vim,你必须在五分钟内完成一次配置修改并保…

2026/9/25 0:00:41 阅读更多 →

周新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/24 14:34:13 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/24 9:10:42 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/24 14:33:56 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/24 12:50:34 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/24 14:33:48 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/24 12:49:17 阅读更多 →