尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Python数据分析实战:爬取B站视频数据,解析播放量Top榜单

Python数据分析实战:爬取B站视频数据,解析播放量Top榜单 破亿截止2026B站播放量最高的六条投稿视频谁才是镇站之宝第一名毋庸置疑大家好作为一名长期关注技术趋势与数据可视化的开发者我发现在分析社区文化现象时数据本身往往比主观感受更有说服力。B站作为国内领先的视频社区其播放量榜单不仅是用户喜好的晴雨表更是内容创作趋势与技术传播的绝佳观察窗口。今天我们就从数据爬取、清洗、分析到可视化的全流程技术视角来深度解析“截止2026年B站播放量最高的六条投稿视频”这一现象并探讨其背后的技术实现路径。无论你是想学习Python数据分析还是对社区热点背后的技术逻辑感兴趣这篇文章都将提供一套完整的实战方案。1. 项目背景与核心概念在深入代码之前我们首先要明确这个分析项目的目标和边界。这不仅仅是一个“看热闹”的榜单罗列更是一个典型的数据工程与数据分析案例。1.1 项目目标我们的核心目标是通过技术手段自动化地获取、处理并分析B站历史投稿视频的播放量数据最终筛选出截至某个时间点如2026年播放量最高的视频并进行多维度的可视化展示与成因分析。这涉及到以下几个关键步骤数据获取如何合法、稳定、高效地爬取B站视频的元数据如播放量、弹幕数、点赞、投币等。数据清洗处理缺失值、异常值将非结构化的JSON数据转换为结构化的表格数据。数据分析应用排序、筛选、聚合等操作找出目标榜单。数据可视化将分析结果以图表形式直观呈现。归因分析结合视频内容、发布时间、创作者等信息尝试从技术传播、社区文化、算法推荐等角度解读榜单成因。1.2 技术栈选型为了实现上述目标我们将采用Python作为主力语言因其在数据科学领域的生态极其丰富。爬虫框架requests(HTTP请求) BeautifulSoup/parsel(HTML解析) 或直接调用B站官方/非官方API。数据处理与分析pandas(数据分析核心库) numpy(数值计算)。数据可视化matplotlibseaborn(静态图表) 或pyecharts/plotly(交互式图表)。异步与效率aiohttp(异步HTTP请求用于大规模爬取)。数据存储sqlite3(轻量级数据库) 或csv/json文件。重要概念区分播放量 vs 热度播放量是累计观看次数是历史数据的体现热度是B站综合播放、点赞、投币、分享等计算的实时指标反映当前流行度。本项目聚焦于历史累计播放量。投稿视频 vs 整体视频B站内容包含投稿视频、番剧、影视、课程等。本项目限定为UP主投稿的单体视频不包括系列合集、番剧单集因其发布主体和传播逻辑不同。2. 环境准备与版本说明在开始编写代码前请确保你的开发环境已就绪。以下版本为撰写本文时的稳定版本实际操作时可根据情况微调。操作系统Windows 10/11, macOS, 或 Linux (如Ubuntu 20.04)均可。Python版本Python 3.8 或以上。推荐使用 Python 3.9/3.10以获得更好的兼容性和性能。开发工具VS Code, PyCharm 或 Jupyter Notebook 皆可。本文示例将在标准Python脚本环境中演示。2.1 创建虚拟环境与安装依赖强烈建议使用虚拟环境来管理项目依赖避免污染系统环境。# 1. 创建项目目录并进入 mkdir bilibili_top_videos_analysis cd bilibili_top_videos_analysis # 2. 创建虚拟环境 (以 venv 为例) python -m venv venv # 3. 激活虚拟环境 # Windows (cmd或PowerShell) venv\Scripts\activate # macOS / Linux source venv/bin/activate # 4. 安装核心依赖库 pip install requests pandas matplotlib seaborn # 可选但推荐的库 pip install jupyter notebook sqlite3 aiohttp pyecharts安装完成后可以通过pip list检查主要库的版本。本文示例基于以下近似版本requests~2.28.1pandas~1.5.0matplotlib~3.6.0seaborn~0.12.02.2 项目结构规划一个清晰的项目结构有助于代码管理和协作。bilibili_top_videos_analysis/ ├── data/ # 存放原始和清洗后的数据 │ ├── raw/ # 原始JSON/HTML数据 │ └── processed/ # 清洗后的CSV数据 ├── src/ # 源代码 │ ├── crawler.py # 爬虫模块 │ ├── processor.py # 数据清洗处理模块 │ ├── analyzer.py # 数据分析模块 │ └── visualizer.py # 数据可视化模块 ├── config.py # 配置文件 (API密钥、请求头等) ├── main.py # 主程序入口 ├── requirements.txt # 项目依赖列表 └── README.md # 项目说明3. 核心原理与技术拆解3.1 数据获取原理与API分析直接爬取网页HTML效率低且易被反爬。更优的方法是寻找数据接口。B站的大部分数据通过其内部API返回我们可以通过浏览器开发者工具F12的“网络”(Network)选项卡进行抓包分析。以B站视频页https://www.bilibili.com/video/BV1xx411c7mD为例刷新页面后在XHR或Fetch请求中可以找到一个包含?aid或?bvid的请求其响应通常是JSON格式包含了视频的详细数据data字段。一个常见的获取视频信息的API端点示例非官方可能变动https://api.bilibili.com/x/web-interface/view?bvidBV1xx411c7mD此接口返回的数据结构包含data对象其中有stat(统计数据) 字段包含了我们需要的view(播放量)、danmaku(弹幕)、reply(评论)、favorite(收藏)、coin(投币)、share(分享) 等信息。关键点请求头模拟浏览器请求必须包含User-Agent有时还需要Referer。频率限制B站API有频率限制爬取时需添加延时 (time.sleep)避免IP被封。合法性仅用于个人学习与研究不得用于商业用途或对B站服务器造成压力。3.2 数据分析的核心操作拿到数据后pandas是我们的核心工具。数据加载将JSON或CSV数据读入DataFrame。数据筛选根据播放量 (view) 进行排序使用df.nlargest(6, ‘view’)快速获取前6名。数据清洗处理可能的空值 (df.dropna())、重复值并将字符串类型的数字转换为整型 (pd.to_numeric)。特征工程可以计算一些衍生指标如“互动率”(点赞投币收藏)/播放量来辅助分析视频质量。3.3 可视化设计思路对于“Top 6”这样的榜单最适合的图表是条形图或柱状图可以清晰对比各项数值。主图用水平条形图展示6个视频的播放量从高到低排列一目了然。辅助图可以用散点图或气泡图以播放量为X轴点赞/投币为Y轴观察播放量与互动质量的关系。趋势图如果获取了视频每日的播放增量数据可以绘制播放量增长曲线分析其爆发点和长尾效应。4. 完整实战案例从爬取到分析假设我们已经通过分析确定了一个相对稳定的数据获取思路。下面我们模拟一个完整的、简化的流程。4.1 步骤一编写爬虫获取单个视频信息首先我们编写一个函数根据视频的BV号如BV1GJ411x7h1获取其基本信息。# file: src/crawler.py import requests import time import pandas as pd from typing import Dict, Optional def get_video_info_by_bvid(bvid: str) - Optional[Dict]: 根据B站视频BV号获取视频信息 :param bvid: 视频的BV号例如 BV1GJ411x7h1 :return: 包含视频信息的字典如果请求失败返回None # B站视频信息API (此接口为示例实际使用时请确认其稳定性和可用性) url fhttps://api.bilibili.com/x/web-interface/view?bvid{bvid} # 重要的请求头模拟浏览器访问 headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36, Referer: https://www.bilibili.com, } try: response requests.get(url, headersheaders, timeout10) response.raise_for_status() # 检查HTTP请求是否成功 data_json response.json() # 检查API返回状态码 if data_json.get(code) ! 0: print(fAPI Error for {bvid}: {data_json.get(message)}) return None data data_json.get(data, {}) # 提取我们需要的关键信息 video_info { bvid: bvid, aid: data.get(aid), # 视频AV号 title: data.get(title, ), pubdate: data.get(pubdate, 0), # 发布时间戳 owner: data.get(owner, {}).get(name, ), # UP主名称 view: data.get(stat, {}).get(view, 0), # 播放量 danmaku: data.get(stat, {}).get(danmaku, 0), # 弹幕 reply: data.get(stat, {}).get(reply, 0), # 评论 favorite: data.get(stat, {}).get(favorite, 0), # 收藏 coin: data.get(stat, {}).get(coin, 0), # 投币 share: data.get(stat, {}).get(share, 0), # 分享 like: data.get(stat, {}).get(like, 0), # 点赞 } return video_info except requests.exceptions.RequestException as e: print(fNetwork error for {bvid}: {e}) return None except Exception as e: print(fUnexpected error for {bvid}: {e}) return None # 示例获取单个视频信息 if __name__ __main__: # 示例BV号《【春晚鬼畜】赵本山我就是念诗之王》 test_bvid BV1GJ411x7h1 info get_video_info_by_bvid(test_bvid) if info: print(f视频标题{info[title]}) print(f播放量{info[view]}) print(fUP主{info[owner]}) time.sleep(1) # 礼貌性延时避免请求过快4.2 步骤二批量获取与数据存储要分析Top 6我们需要一个初始的视频BV号列表。这个列表可以来源于已知的高播放量视频或者通过其他方式如爬取排行榜获取。这里我们假设我们已经有了一个候选列表。# file: src/crawler.py (续) def batch_fetch_video_info(bvid_list: list, delay: float 1.0) - pd.DataFrame: 批量获取视频信息并保存到DataFrame :param bvid_list: BV号列表 :param delay: 每次请求之间的延迟秒避免被封 :return: 包含所有视频信息的DataFrame all_videos_data [] for bvid in bvid_list: print(f正在获取 {bvid} 的信息...) video_info get_video_info_by_bvid(bvid) if video_info: all_videos_data.append(video_info) time.sleep(delay) # 遵守爬虫礼仪非常重要 # 将列表转换为DataFrame df pd.DataFrame(all_videos_data) return df # 示例批量获取这里用一些历史上高播放的BV号示例实际需要更全面的列表 if __name__ __main__: # 注意这些BV号仅为示例其播放量可能已发生变化且不一定是真正的历史前6。 candidate_bvids [ BV1GJ411x7h1, # 念诗之王 BV1xx411c7mD, # 改革春风吹满地 BV1Js411o76u, # 黑人抬棺 BV1Cx411d7K9, # 影流之主 BV1ut41197SV, # 两只老虎爱跳舞 BV1qW411n7jL, # 你从未离去 # ... 可以添加更多候选 ] videos_df batch_fetch_video_info(candidate_bvids, delay1.5) # 保存到CSV文件方便后续分析 if not videos_df.empty: videos_df.to_csv(../data/processed/videos_info_sample.csv, indexFalse, encodingutf-8-sig) print(f数据已保存共获取 {len(videos_df)} 条记录。) print(videos_df[[bvid, title, view, owner]].head())4.3 步骤三数据分析与Top 6筛选数据获取后我们进入分析阶段。# file: src/analyzer.py import pandas as pd def load_and_analyze_top_videos(csv_path: str, top_n: int 6) - pd.DataFrame: 加载数据并分析播放量最高的N个视频 :param csv_path: 数据文件路径 :param top_n: 要筛选的前N名 :return: 包含Top N视频的DataFrame按播放量降序排列 # 1. 加载数据 df pd.read_csv(csv_path, encodingutf-8-sig) # 2. 数据清洗与类型转换 # 确保数值列是数字类型 numeric_columns [view, danmaku, reply, favorite, coin, share, like] for col in numeric_columns: df[col] pd.to_numeric(df[col], errorscoerce) # 3. 按播放量降序排序并取前Top N df_sorted df.sort_values(byview, ascendingFalse) top_df df_sorted.head(top_n).copy() # 4. 计算一些衍生指标可选 # 例如互动率 (点赞投币收藏) / 播放量 * 100% top_df[interaction_rate] (top_df[like] top_df[coin] top_df[favorite]) / top_df[view] * 100 # 格式化显示为百分比保留两位小数 top_df[interaction_rate_pct] top_df[interaction_rate].round(4) # 5. 重置索引让排名更清晰 top_df.reset_index(dropTrue, inplaceTrue) top_df.index top_df.index 1 # 排名从1开始 return top_df if __name__ __main__: # 假设我们已经有数据文件 data_file ../data/processed/videos_info_sample.csv try: top_6_df load_and_analyze_top_videos(data_file, top_n6) print( 截止当前数据播放量最高的6个视频 ) # 选择要展示的列 display_columns [排名, bvid, title, owner, view, like, coin, interaction_rate_pct] top_6_display top_6_df.reset_index().rename(columns{index: 排名}) print(top_6_display[display_columns].to_string(indexFalse)) # 保存分析结果 top_6_df.to_csv(../data/processed/top_6_videos_analysis.csv, encodingutf-8-sig) print(\n详细分析结果已保存至 ‘top_6_videos_analysis.csv‘。) except FileNotFoundError: print(f数据文件 {data_file} 未找到请先运行爬虫脚本获取数据。)4.4 步骤四数据可视化呈现最后我们将分析结果用图表展示出来。# file: src/visualizer.py import matplotlib.pyplot as plt import seaborn as sns import pandas as pd import numpy as np def plot_top_videos_barh(top_df: pd.DataFrame, save_path: str None): 绘制Top N视频播放量的水平条形图 :param top_df: 包含Top视频数据的DataFrame需有‘title‘, ‘view‘列 :param save_path: 图片保存路径如果为None则显示图片 plt.figure(figsize(12, 8)) # 设置中文字体根据系统调整 # plt.rcParams[‘font.sans-serif‘] [‘SimHei‘, ‘Microsoft YaHei‘] # Windows # plt.rcParams[‘font.sans-serif‘] [‘PingFang SC‘, ‘Heiti SC‘] # Mac plt.rcParams[axes.unicode_minus] False # 解决负号显示问题 # 简化标题用于显示防止过长 top_df[title_short] top_df[title].apply(lambda x: (x[:20] ...) if len(x) 20 else x) # 创建条形图 bars plt.barh(top_df[title_short][::-1], top_df[view][::-1], colorsns.color_palette(husl, len(top_df))) plt.xlabel(播放量 (亿次), fontsize12) plt.title(fB站播放量最高的{len(top_df)}个投稿视频模拟数据, fontsize14, fontweightbold) plt.grid(axisx, linestyle--, alpha0.7) # 在条形末端添加播放量数值标签 for bar in bars: width bar.get_width() # 格式化播放量过亿显示为“x.xx亿” if width 1e8: label_text f{width/1e8:.2f}亿 else: label_text f{int(width/1e4)}万 plt.text(width max(top_df[view])*0.01, bar.get_y() bar.get_height()/2, label_text, vacenter, haleft, fontsize10) plt.tight_layout() if save_path: plt.savefig(save_path, dpi300, bbox_inchestight) print(f图表已保存至{save_path}) else: plt.show() def plot_interaction_scatter(top_df: pd.DataFrame): 绘制播放量与互动数点赞投币的散点图观察相关性 plt.figure(figsize(10, 6)) top_df[total_interaction] top_df[like] top_df[coin] scatter plt.scatter(top_df[view], top_df[total_interaction], stop_df[favorite]/1000, # 用收藏数大小表示点的大小 alpha0.6, edgecolorsw, linewidth0.5) # 为每个点添加视频简称标签 for i, row in top_df.iterrows(): plt.annotate(row[title_short], (row[view], row[total_interaction]), xytext(5, 5), textcoordsoffset points, fontsize9) plt.xlabel(播放量 (次)) plt.ylabel(点赞投币 (次)) plt.title(Top视频播放量与核心互动量关系图) plt.grid(True, linestyle--, alpha0.5) plt.tight_layout() plt.show() if __name__ __main__: # 加载上一步分析得到的数据 analysis_file ../data/processed/top_6_videos_analysis.csv try: top_6_df pd.read_csv(analysis_file, encodingutf-8-sig) # 绘制主要条形图 plot_top_videos_barh(top_6_df, save_path../top_6_videos_chart.png) # 绘制散点图 # plot_interaction_scatter(top_6_df) # 可选 except FileNotFoundError: print(分析结果文件未找到请先运行分析脚本。)5. 常见问题与排查思路在实际操作中你可能会遇到以下问题问题现象可能原因排查与解决方案爬虫返回403 Forbidden或412 Precondition Failed1. 请求头User-Agent不被接受。2. 缺少必要的Referer或Cookie。3. IP请求频率过高被暂时限制。1. 使用更常见浏览器的完整User-Agent字符串。2. 检查并添加正确的Referer通常为https://www.bilibili.com。3.关键大幅增加请求间隔 (time.sleep)例如3-5秒甚至更长。考虑使用代理IP池。API请求返回code: -404或message: “稿件不可见”1. 视频已被UP主删除或设置为私密。2. BV号无效或已过期。3. 接口地址或参数已变更。1. 确认BV号是否正确有效。2. 在浏览器中手动访问该视频链接确认状态。3. 通过浏览器开发者工具抓取最新的API请求地址和参数格式。pandas读取CSV文件时中文乱码CSV文件保存的编码与读取时指定的编码不一致。保存时使用df.to_csv(..., encoding‘utf-8-sig‘)读取时使用pd.read_csv(..., encoding‘utf-8-sig‘)。utf-8-sig能更好地处理Excel等软件打开时的BOM头。图表中中文显示为方框系统未安装中文字体或Matplotlib未正确配置字体。1.推荐使用英文标签避免字体问题。2. 安装中文字体如SimHei并在代码开头通过plt.rcParams指定。此方法跨平台兼容性较差。数据分析结果与预期榜单差异巨大1. 初始候选视频列表 (bvid_list) 不全面遗漏了真正的头部视频。2. 数据获取时间点不同播放量实时变化。3. 爬取的API接口可能不包含所有历史投稿如仅包含近期热门。1.根本解法需要更全面的视频源。可以尝试爬取全站排行榜如全站热门榜、历史累计榜来构建初始列表但这需要更复杂的爬虫策略和遵守Robots协议。2. 明确分析的时间范围并在报告中注明数据截止日期。运行速度慢尤其是批量爬取时1. 单线程同步请求受网络延迟和time.sleep影响。2. 请求间隔设置过短触发风控后等待时间更长。1. 对于大规模爬取考虑使用aiohttp进行异步请求但复杂度增加。2.平衡速度与稳定性在遵守规则的前提下适当优化代码逻辑如复用Session但首要保证不被封禁。6. 最佳实践与工程建议将一个小脚本变成一个健壮、可维护的数据项目需要遵循一些工程实践。6.1 爬虫伦理与合规性遵守Robots协议检查https://www.bilibili.com/robots.txt尊重网站的爬取限制。限制请求速率这是最重要的原则。添加显著的延时如time.sleep(3)避免对目标服务器造成负担。识别自己在User-Agent中可以考虑包含一个标识如MyResearchBot/1.0但不要伪装成主流浏览器。缓存数据对于不变的历史数据爬取一次后应保存到本地避免重复请求。仅用于学习本项目所有代码和思路仅供学习Python和数据技术之用。请勿用于任何商业用途或违反B站用户协议的行为。6.2 代码质量与可维护性配置文件将API URL、请求头、延时参数等放入config.py或config.yaml中与代码逻辑分离。日志记录使用logging模块替代print可以方便地控制输出级别DEBUG, INFO, ERROR并记录到文件。异常处理如示例代码所示对网络请求、JSON解析、文件IO等操作进行try-except包装使程序更健壮。数据验证在将数据存入DataFrame或数据库前进行简单的有效性检查如关键字段是否存在、类型是否正确。6.3 数据分析的严谨性数据源说明在最终报告或图表中明确注明数据来源、爬取日期和可能的局限性例如“数据来源于B站公开API截至2024年5月榜单为基于有限样本的模拟分析”。指标解读播放量高不一定代表视频“质量”最高或“口碑”最好。应结合点赞率、投币率、收藏率等互动指标进行综合评估。高播放量可能源于出圈效应、 meme 传播、官方推荐等多种因素。趋势而非快照如果条件允许定期如每月爬取一次数据观察榜单变化趋势这比单次排名更有分析价值。6.4 项目扩展方向定时任务使用schedule库或cron定时运行爬虫和分析脚本自动更新榜单。数据库集成使用SQLite或MySQL存储历史数据便于进行时间序列分析和复杂查询。构建Web应用使用Flask或Streamlit快速搭建一个展示榜单和数据图表的简易网站。深入归因分析除了播放量可以爬取视频的标签、分区、发布时间线、UP主粉丝数等使用机器学习模型如线性回归、决策树尝试预测或解释播放量的成因。通过这样一个完整的项目实践你不仅能得到一份有趣的“B站镇站之宝”榜单更重要的是掌握了从数据获取、处理、分析到可视化的全链路数据科学技能。技术是解读世界的工具希望这个案例能帮助你更好地使用这个工具。如果在复现过程中遇到任何问题欢迎在评论区交流探讨。
返回列表