1. 项目概述
最近在做一个很有意思的数据分析小项目 - 用Python抓取B站全站热榜和实时在线人数数据。这个项目最初源于我对B站内容生态的好奇,想了解哪些视频能登上热榜,以及用户活跃度的变化规律。
通过这个项目,我们能够:
- 获取B站全站热门视频的实时数据
- 分析不同时段的热门内容变化趋势
- 监测B站实时在线人数波动情况
- 建立简单的数据分析模型预测热门内容
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 技术选型与准备
2.1 开发环境配置
我使用的是Python 3.8+环境,主要依赖以下库:
- requests:用于发送HTTP请求
- BeautifulSoup:HTML解析
- pandas:数据处理和分析
- matplotlib/seaborn:数据可视化
- aiohttp:异步请求(可选)
安装命令:
bash复制pip install requests beautifulsoup4 pandas matplotlib seaborn aiohttp
2.2 接口分析
B站虽然没有公开的官方API,但我们可以通过分析网页请求来找到数据接口:
- 热榜数据接口:
code复制https://api.bilibili.com/x/web-interface/ranking/v2?rid=0&type=all
- 实时在线人数接口:
code复制https://api.bilibili.com/x/web-interface/online
提示:这些接口可能会随时间变化,建议使用时先检查接口是否仍然有效。
3. 核心功能实现
3.1 获取热榜数据
python复制import requests
import json
def get_bilibili_hotlist():
url = "https://api.bilibili.com/x/web-interface/ranking/v2?rid=0&type=all"
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"
}
try:
response = requests.get(url, headers=headers)
response.raise_for_status()
data = response.json()
if data["code"] == 0:
return data["data"]["list"]
else:
print(f"获取热榜失败: {data['message']}")
return None
except Exception as e:
print(f"请求异常: {str(e)}")
return None
3.2 获取实时在线人数
python复制def get_online_count():
url = "https://api.bilibili.com/x/web-interface/online"
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"
}
try:
response = requests.get(url, headers=headers)
response.raise_for_status()
data = response.json()
if data["code"] == 0:
return {
"total": data["data"]["total"],
"web_online": data["data"]["web_online"],
"play_online": data["data"]["play_online"]
}
else:
print(f"获取在线人数失败: {data['message']}")
return None
except Exception as e:
print(f"请求异常: {str(e)}")
return None
4. 数据处理与分析
4.1 数据清洗与存储
python复制import pandas as pd
from datetime import datetime
def process_hotlist_data(hotlist):
processed_data = []
for item in hotlist:
processed_data.append({
"rank": item["rank"],
"title": item["title"],
"bvid": item["bvid"],
"author": item["owner"]["name"],
"view": item["stat"]["view"],
"danmaku": item["stat"]["danmaku"],
"reply": item["stat"]["reply"],
"favorite": item["stat"]["favorite"],
"coin": item["stat"]["coin"],
"share": item["stat"]["share"],
"like": item["stat"]["like"],
"score": item["score"],
"timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
})
return pd.DataFrame(processed_data)
4.2 数据分析示例
python复制import matplotlib.pyplot as plt
import seaborn as sns
def analyze_hotlist(df):
# 热门视频类型分布
plt.figure(figsize=(12, 6))
sns.countplot(data=df, y="author", order=df["author"].value_counts().index[:10])
plt.title("Top 10 Most Frequent Authors in Hotlist")
plt.xlabel("Count")
plt.ylabel("Author")
plt.tight_layout()
plt.show()
# 互动指标相关性分析
plt.figure(figsize=(10, 8))
sns.heatmap(df[["view", "danmaku", "reply", "favorite", "coin", "share", "like"]].corr(),
annot=True, cmap="coolwarm")
plt.title("Correlation Heatmap of Interaction Metrics")
plt.tight_layout()
plt.show()
5. 定时任务与数据持久化
5.1 定时抓取实现
python复制import time
import sqlite3
def setup_database():
conn = sqlite3.connect("bilibili_data.db")
cursor = conn.cursor()
# 创建热榜数据表
cursor.execute("""
CREATE TABLE IF NOT EXISTS hotlist (
id INTEGER PRIMARY KEY AUTOINCREMENT,
rank INTEGER,
title TEXT,
bvid TEXT,
author TEXT,
view INTEGER,
danmaku INTEGER,
reply INTEGER,
favorite INTEGER,
coin INTEGER,
share INTEGER,
like INTEGER,
score INTEGER,
timestamp TEXT
)
""")
# 创建在线人数表
cursor.execute("""
CREATE TABLE IF NOT EXISTS online_count (
id INTEGER PRIMARY KEY AUTOINCREMENT,
total INTEGER,
web_online INTEGER,
play_online INTEGER,
timestamp TEXT
)
""")
conn.commit()
conn.close()
def run_scheduled_task(interval_minutes=30):
setup_database()
conn = sqlite3.connect("bilibili_data.db")
while True:
try:
# 获取热榜数据
hotlist = get_bilibili_hotlist()
if hotlist:
df = process_hotlist_data(hotlist)
df.to_sql("hotlist", conn, if_exists="append", index=False)
# 获取在线人数
online_data = get_online_count()
if online_data:
online_data["timestamp"] = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
pd.DataFrame([online_data]).to_sql("online_count", conn, if_exists="append", index=False)
print(f"数据抓取完成于 {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
except Exception as e:
print(f"定时任务出错: {str(e)}")
time.sleep(interval_minutes * 60)
6. 高级分析与可视化
6.1 热榜内容变化趋势分析
python复制def analyze_trends(conn):
# 从数据库读取历史数据
hotlist_history = pd.read_sql("""
SELECT
strftime('%Y-%m-%d %H:00:00', timestamp) as hour,
author,
title,
view,
like
FROM hotlist
WHERE timestamp >= datetime('now', '-7 days')
""", conn)
# 按小时统计热门作者出现次数
author_trend = hotlist_history.groupby(["hour", "author"]).size().unstack().fillna(0)
plt.figure(figsize=(14, 8))
author_trend.sum().sort_values(ascending=False).head(10).plot(kind="bar")
plt.title("Top 10 Authors by Appearance Count in Hotlist (Last 7 Days)")
plt.ylabel("Count")
plt.xticks(rotation=45)
plt.tight_layout()
plt.show()
# 热门视频互动指标变化
top_videos = hotlist_history.groupby("title")["view"].max().sort_values(ascending=False).head(5).index
video_trends = hotlist_history[hotlist_history["title"].isin(top_videos)]
plt.figure(figsize=(14, 8))
for title, group in video_trends.groupby("title"):
plt.plot(pd.to_datetime(group["hour"]), group["view"], label=title[:30]+"...")
plt.title("View Trends for Top 5 Videos (Last 7 Days)")
plt.ylabel("Views")
plt.xlabel("Time")
plt.legend()
plt.tight_layout()
plt.show()
6.2 在线人数时间序列分析
python复制def analyze_online_trends(conn):
online_history = pd.read_sql("""
SELECT
strftime('%Y-%m-%d %H:00:00', timestamp) as hour,
AVG(total) as avg_total,
AVG(web_online) as avg_web,
AVG(play_online) as avg_play
FROM online_count
WHERE timestamp >= datetime('now', '-7 days')
GROUP BY hour
ORDER BY hour
""", conn)
online_history["hour"] = pd.to_datetime(online_history["hour"])
plt.figure(figsize=(14, 8))
plt.plot(online_history["hour"], online_history["avg_total"], label="Total Online")
plt.plot(online_history["hour"], online_history["avg_web"], label="Web Online")
plt.plot(online_history["hour"], online_history["avg_play"], label="Play Online")
plt.title("Bilibili Online Users Trend (Last 7 Days)")
plt.ylabel("User Count")
plt.xlabel("Time")
plt.legend()
plt.grid(True)
plt.tight_layout()
plt.show()
# 按小时分析
online_history["hour_of_day"] = online_history["hour"].dt.hour
hourly_avg = online_history.groupby("hour_of_day")[["avg_total", "avg_web", "avg_play"]].mean()
plt.figure(figsize=(14, 8))
hourly_avg.plot(kind="line", marker="o")
plt.title("Average Online Users by Hour of Day (Last 7 Days)")
plt.ylabel("User Count")
plt.xlabel("Hour of Day")
plt.xticks(range(24))
plt.grid(True)
plt.legend(["Total", "Web", "Play"])
plt.tight_layout()
plt.show()
7. 项目优化与扩展
7.1 性能优化建议
- 异步请求:使用aiohttp替代requests提高抓取效率
python复制import aiohttp
import asyncio
async def fetch_data(session, url):
async with session.get(url) as response:
return await response.json()
async def get_hotlist_async():
url = "https://api.bilibili.com/x/web-interface/ranking/v2?rid=0&type=all"
headers = {"User-Agent": "Mozilla/5.0..."}
async with aiohttp.ClientSession(headers=headers) as session:
data = await fetch_data(session, url)
if data["code"] == 0:
return data["data"]["list"]
return None
-
数据缓存:实现简单的缓存机制减少API调用
-
错误重试:添加指数退避重试机制应对临时错误
7.2 功能扩展方向
-
内容分类分析:通过视频标题和标签进行内容分类统计
-
情感分析:对热门视频的评论进行情感倾向分析
-
预测模型:基于历史数据建立热门内容预测模型
-
实时监控告警:设置阈值触发异常流量告警
8. 常见问题与解决方案
8.1 请求被限制或封禁
现象:返回403错误或数据为空
解决方案:
- 添加合理的请求间隔(建议≥30秒)
- 使用代理IP轮换
- 模拟更真实的浏览器行为(添加更多请求头)
8.2 数据解析错误
现象:JSON解析失败或字段缺失
解决方案:
- 添加健壮的错误处理
- 检查API响应结构是否变化
- 使用try-except包裹关键解析代码
8.3 数据库性能问题
现象:随着数据量增大,查询变慢
解决方案:
- 添加适当的数据库索引
- 定期归档历史数据
- 考虑使用更专业的时序数据库
9. 项目部署与运行
9.1 本地运行
- 安装Python和依赖库
- 创建数据库文件
- 运行主程序
9.2 服务器部署
推荐使用以下方式部署为长期运行的服务:
- 使用systemd服务(Linux)
ini复制# /etc/systemd/system/bilibili_monitor.service
[Unit]
Description=Bilibili Hotlist Monitor
After=network.target
[Service]
User=your_username
WorkingDirectory=/path/to/project
ExecStart=/usr/bin/python3 /path/to/project/main.py
Restart=always
[Install]
WantedBy=multi-user.target
- 使用Docker容器
dockerfile复制FROM python:3.8-slim
WORKDIR /app
COPY . .
RUN pip install -r requirements.txt
CMD ["python", "main.py"]
- 添加日志监控:配置日志轮转和监控告警
10. 实际应用案例
10.1 内容创作者分析
通过分析热榜数据,可以帮助内容创作者:
- 了解当前热门内容趋势
- 分析高互动视频的共同特征
- 优化发布时间(根据在线人数高峰时段)
10.2 运营决策支持
平台运营人员可以利用这些数据:
- 监测社区活跃度变化
- 识别异常流量波动
- 评估内容推荐算法效果
10.3 学术研究应用
研究人员可以使用这些数据进行:
- 网络文化传播研究
- 用户行为模式分析
- 社交网络动力学研究
在实际使用中,我发现这个项目最有价值的部分是能够捕捉到一些突发热点事件的早期信号。比如某次我注意到一个平时不太常见的内容类型突然进入热榜,后来证实是一个重要新闻事件在B站上的早期传播。这种实时监测能力对于很多应用场景都非常有用。
