春节期间,各商场又响来刘德华的《恭喜发财》,许多网友戏称这是数字生命解冻了。既然大家那么关心,那我们就爬去一下B站里刘德华《恭喜发财》的弹幕数据,来看一看有什么有趣的现象。
我原来的想法是爬取视频上线以来的数据,不过操作后发现我还是太年轻了。从2022年1月30日视频上线至今,弹幕量高达8个多G,所以我只统计每天有多少条弹幕,以及弹幕的累计数据。
这里我用flask做了前后端分离,把数据存在了Mysql中,实现了图表。
在这个图表中,我们会发现,23年春节以后,视频的弹幕量有一个显著的提升。而23年春节就是《流浪地球2》的上映时间,也可以看出《流浪地球2》确实是当年的热门话题,并给刘德华带来了一波流量。
不过,我对这个图表还是不大满意,时间跨度太长了,如果能为时间加入一个筛选功能就能更好的观察一段时间内的弹幕变化。
我们试着简单写一个筛选功能,在页面中加上时间的选择按钮。
html
<label for="year-select">选择年份:</label>
<select id="year-select">
<option value="">未选择</option>
<option value="2022">2022</option>
<option value="2023">2023</option>
<option value="2024">2024</option>
</select>
<label for="month-select">选择月份:</label>
<select id="month-select">
<option value="">未选择</option>
<option value="1">1月</option>
<option value="2">2月</option>
<option value="3">3月</option>
<option value="4">4月</option>
<option value="5">5月</option>
<option value="6">6月</option>
<option value="7">7月</option>
<option value="8">8月</option>
<option value="9">9月</option>
<option value="10">10月</option>
<option value="11">11月</option>
<option value="12">12月</option>
</select>
我们要向服务器端发送这个时间的参数。
python
# 获取来自前端的查询参数
selected_year = request.args.get("year", None)
selected_month = request.args.get("month", None)
# 构建查询
query = db.session.query(danmu1.id, danmu1.time, danmu1.number, danmu1.allnumber)
# 如果有年份参数,则根据年份进行过滤
if selected_year:
query = query.filter(extract("year", danmu1.time) == int(selected_year))
# 如果有月份参数,则根据月份进行过滤
if selected_month:
query = query.filter(extract("month", danmu1.time) == int(selected_month))
在服务器端,我们用request 方法取得选择的时间,用filter方法对数据进行筛选。因为服务器中的time是按照时间格式存储的,可以用extract函数对其中的year和month进行匹配。
JS函数在接收服务器信息的时候也要进行调整,因为我们用的是GET方法,关于日期的信息会跟在请求的url链接后面。
这里最好加上一个条件判断,这样只输入年而没有月时也能正常筛选。
html
var option;
var selectedYear = document.getElementById('year-select').value;
var selectedMonth = document.getElementById('month-select').value;
var url = "/data?year=" + selectedYear;
if (selectedMonth !== "") {
url += "&month=" + selectedMonth;
}
不过这里其实还有个问题,当数据量过大时,服务器向浏览器发送的数据不一定完整,最好再人为的进行处理。
服务器:
python
from flask import Flask, render_template, session, jsonify, request
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import extract
from datetime import datetime
app = Flask(__name__)
HOSTNAME = "127.0.0.1"
PORT = 3306
USERNAME = "root"
PASSWORD = ""
DATABASE = "bisystem"
DB_URI = f"mysql+pymysql://{ USERNAME }:{ PASSWORD }@{ HOSTNAME }:{ PORT }/{ DATABASE }?charset=utf8mb4"
app.config["SQLALCHEMY_DATABASE_URI"] = DB_URI
db = SQLAlchemy(app)
# 映射员工表
class danmu1(db.Model):
__tablename__ = "danmu1"
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
time = db.Column(db.DateTime)
number = db.Column(db.String(100))
allnumber = db.Column(db.String(100))
def to_dict(self):
return {
"id": self.id,
"time": self.time,
"number": self.number,
"allnumber": self.allnumber,
}
@app.route("/")
def to_index():
return render_template("index.html")
@app.route("/data")
def get_data():
# 获取来自前端的查询参数
selected_year = request.args.get("year", None)
selected_month = request.args.get("month", None)
# 构建查询
query = db.session.query(danmu1.id, danmu1.time, danmu1.number, danmu1.allnumber)
# 如果有年份参数,则根据年份进行过滤
if selected_year:
query = query.filter(extract("year", danmu1.time) == int(selected_year))
# 如果有月份参数,则根据月份进行过滤
if selected_month:
query = query.filter(extract("month", danmu1.time) == int(selected_month))
# 执行查询
datas = [
{"id": items[0], "time": items[1], "number": items[2], "allnumber": items[3]}
for items in query
]
print(datas)
# 返回结果
return jsonify(data=datas)
if __name__ == "__main__":
app.run(debug=True)
浏览器
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/echarts/5.4.3/echarts.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.7.1/jquery.js"></script>
</head>
<body>
<label for="year-select">选择年份:</label>
<select id="year-select">
<option value="">未选择</option>
<option value="2022">2022</option>
<option value="2023">2023</option>
<option value="2024">2024</option>
</select>
<label for="month-select">选择月份:</label>
<select id="month-select">
<option value="">未选择</option>
<option value="1">1月</option>
<option value="2">2月</option>
<option value="3">3月</option>
<option value="4">4月</option>
<option value="5">5月</option>
<option value="6">6月</option>
<option value="7">7月</option>
<option value="8">8月</option>
<option value="9">9月</option>
<option value="10">10月</option>
<option value="11">11月</option>
<option value="12">12月</option>
</select>
<div style="width:100%;height: 600px;"></div>
<script>
function createchart() {
var option;
var selectedYear = document.getElementById('year-select').value;
var selectedMonth = document.getElementById('month-select').value;
var url = "/data?year=" + selectedYear;
if (selectedMonth !== "") {
url += "&month=" + selectedMonth;
}
$.ajax({
type: "GET",
url: url,
success: function (response) {
const agg = {}
console.log(response.data)
response.data.forEach(function (item) {
var id = item.id;
var time = item.time;
var number = item.number;
var allnumber = item.allnumber;
var fulltime = new Date(time)
var year = fulltime.getUTCFullYear();
var month = fulltime.getUTCMonth() + 1;
var day = fulltime.getUTCDay()
var ym = year + "-" + (month < 10 ? "0" + month : month)
var ymd = year + "-" + (month < 10 ? "0" + month : month) + "-" + (day < 10 ? "0" + day : day)
if (!agg.hasOwnProperty(ymd)) {
agg[ymd] = {
name: ymd,
value: number,
allnumber: allnumber
}
}
})
const days = Object.keys(agg)
const seriesData = Object.values(agg).map(item => {
return {
name: item.name,
value: item.value,
allnumber: item.allnumber
}
});
var chart = echarts.init(document.querySelector("div"))
console.log(days)
option = {
title: {
text: '每日弹幕统计',
left: 'center'
},
legend: {
data: ['弹幕']
},
xAxis: {
type: 'category',
data: days
},
yAxis: {
type: 'value'
},
series: [{
type: "line",
data: seriesData,
itemStyle: {
color: "rgba(237, 125,49,0.7)"
},
}]
};
option && chart.setOption(option);
}
})
}
</script>
<script>
document.addEventListener('DOMContentLoaded', function () {
createchart()
});
// 监听年份和月份选择框的变化,当变化时重新生成图表
document.getElementById('year-select').addEventListener('change', createchart);
document.getElementById('month-select').addEventListener('change', createchart);
</script>
</body>
</html>