最近又在重温nodejs,光看没用,还是得写点东西加深印象,然后又想爬点什么,这就盯上了B站热门,爬了几天数据,分析出了怎么才会上榜、什么类型的视频上榜的较多。
接口分析
打开B站热榜,往下滑动,会发现快到底部时就会请求一些接口
api.bilibili.com/x/web-inter…
api.bilibili.com/x/web-inter…
api.bilibili.com/x/web-inter…
可以发现这个接口的数据,就是对应热榜的数据,参数
ps就是pagesize,pn就是pagenum,每次20条数据,这里我只取到pn=5也就是100条数据进行了分析。
字段分析
从页面观察对应返回的数据,我只取了下面这些字段的数据
[
{key: 'aid', label: 'aid', isShow: false},
{key: 'bvid', label: 'bvid', isShow: false},
{key: 'cid', label: 'cid', isShow: false}, // 三个id到时候嵌入B站视频需要
{key: 'title', label: '标题', isShow: true, cType: 'href', width: '180px'},
{key: 'title_url', label: '视频地址', isShow: false},
{key: 'owner_name', label: '作者', isShow: true, cType: 'href', width: '120px'},
{key: 'owner_url', label: '作者连接', isShow: false},
{key: 'vdesc', label: '视频描述', isShow: false},
{key: 'tname', label: '视频分类', isShow: true},
{key: 'pic', label: '视频图片', isShow: false, cType: 'img'},
{key: 'ctime', label: '创建时间', isShow: false},
{key: 'pubdate', label: '发布时间', isShow: true},
{key: 'rcmd_reason', label: '推荐原因', isShow: true},
{key: 'videos', label: '视频数', isShow: false},
{key: 'copyright', label: '版权所有', isShow: false},
{key: 'view', label: '播放数', isShow: true},
{key: 'like_count', label: '点赞数', isShow: true},
{key: 'favorite', label: '收藏数', isShow: true},
{key: 'coin', label: '投币数', isShow: false},
{key: 'share', label: '分享数', isShow: false},
{key: 'data_date', label: '数据时间', isShow: true},
]
数据读写
请求接口用的是axios,对数据进行整理以后保存到json文件方便后续的读取。
const dates = dayjs(new Date).format('YYYYMMDD')
const fileName = `popular/bili_popular_${dates}.json`
const requests = Array.from({ length: 5 }).map((_, idx) =>
axios.get(`https://api.bilibili.com/x/web-interface/popular?ps=20&pn=${idx + 1}`)
)
const results = await Promise.all(requests)
results.map(rst => {
dList = dList.concat(rst.data.data.list.map(list => formatPopularData(list)))
})
fs.writeFile(fileName, JSON.stringify(dList), 'utf-8', (err) => {
if (err) console.log(err)
})
function formatPopularData(data){
return {
aid: data.aid,
bvid: data.bvid,
cid: data.cid,
title: data.title,
title_url: data.short_link_v2,
owner_name: data.owner.name,
owner_url: `https://space.bilibili.com/${data.owner.mid}`,
vdesc: data.desc,
tname: data.tname,
pic: data.pic,
ctime: dayjs(data.ctime*1000).format('YYYY-MM-DD'),
pubdate: dayjs(data.pubdate*1000).format('YYYY-MM-DD'),
rcmd_reason: data.rcmd_reason.content,
videos: data.videos,
copyright: data.copyright,
view: data.stat.view,
like_count: data.stat.like,
favorite: data.stat.favorite,
coin: data.stat.coin,
share: data.stat.share,
data_date: dayjs(new Date()).format('YYYY-MM-DD'),
}
}
读取数据
function getFileData(dates, ctx) {
const fileName = `popular/bili_popular_${dates}.json`
const exist = fs.existsSync(fileName);
let fileData = []
if (exist) {
const results = fs.readFileSync(fileName, 'utf8');
console.log(`读取${fileName}文件成功`)
fileData = JSON.parse(results)
}
return fileData
}
可视化展示
用的是Vue3 + Echarts5,展示了热榜分类的词云、热榜分类的前20的条形图、推荐原因的饼图。
vue3按需引入Echarts
安装echarts
npm install echarts --save
可单独创建一个useEcharts.js文件
// 引入 echarts 核心模块,核心模块提供了 echarts 使用必须要的接口。
import * as echarts from 'echarts/core';
// 引入柱状图图表,图表后缀都为 Chart
import { PieChart, BarChart } from 'echarts/charts';
// 引入提示框,标题,直角坐标系,数据集,内置数据转换器组件,组件后缀都为 Component
import {
TitleComponent,
TooltipComponent,
GridComponent,
DatasetComponent,
TransformComponent,
ToolboxComponent,
LegendComponent,
GraphicComponent
} from 'echarts/components';
// 标签自动布局、全局过渡动画等特性
import { LabelLayout, UniversalTransition } from 'echarts/features';
// 引入 Canvas 渲染器,注意引入 CanvasRenderer 或者 SVGRenderer 是必须的一步
import { CanvasRenderer } from 'echarts/renderers';
// 注册必须的组件
echarts.use([
TitleComponent,
TooltipComponent,
GridComponent,
DatasetComponent,
TransformComponent,
PieChart,
BarChart,
LabelLayout,
UniversalTransition,
CanvasRenderer,
ToolboxComponent,
LegendComponent,
GraphicComponent
]);
export default echarts
使用
import echarts from '@/utils/useEcharts.js'
let wordChartDiv = echarts.init(document.getElementById('wordChartDiv'))
wordChartDiv.setOption({...})
视频分类词云
这里的分类数据取得是当前数据所有的分类,下面的条形图取得是前20的分类
Echarts5已经没有自带的词云了,需要额外引入词云
npm install echarts-wordcloud
import 'echarts-wordcloud';
{
title: {
text: '热榜分类词云',
top: 6,
left: 6
},
tooltip: {
trigger: "item",
backgroundColor: 'rgba(255,255,255,0.98)',
borderColor: 'rgba(0,0,0,0)',
},
graphic: getGraphic(seriesData),
series: [
{
type: "wordCloud", // 词云类型
gridSize: 5, // 文字间隙
sizeRange: [12, 40], // 文字大小范围
rotationRange: [-90, 90], // 文字旋转角度范围
layoutAnimation: true, // 生成动画
shape: "circle", // 词云展示的形状
left: '0',
top: '0',
width: '100%',
height: '100%',
textStyle: {
fontFamily: 'sans-serif',
fontWeight: 'bold',
// 生成随机颜色
color: function () {
return 'rgb(' + [
Math.round(Math.random() * 160),
Math.round(Math.random() * 160),
Math.round(Math.random() * 160)
].join(',') + ')';
}
},
// hover时文字的样式
emphasis: {
shadowBlur: 10,
shadowColor: "#333",
},
data: seriesData,
},
],
}
视频分类条形图
之前总是在网上看到那种数据增长,排名交替的条形图的动画,想着自己也搞一个,就取了热榜分类前20的数据进行动画展示
没了解之前还以为这种东西会很复杂,做了之后发现,就是配置几个动画的属性,然后循环更改数据
option={
...
yAxis: {
animationDuration: 300,
animationDurationUpdate: 300,
},
animationDuration: 0,
animationDurationUpdate: 3000,
animationEasing: 'linear',
animationEasingUpdate: 'linear',
...
}
async function animationBar(datas, barValueTotal) {
let curIdx = 1, chartData=null
let interval = setInterval(function () {
run()
}, 3000);
function run(){
if (datas.length > 1) {
chartData = datas[curIdx++]
if (!chartData) {
clearInterval(interval)
interval = null
return
}
barChart.setOption(getPopularBarOptions(chartData.barYAxisDatas, chartData.barSeriesData, barValueTotal))
}
}
run()
}
推荐原因饼图
这里取的是所有数据的推荐原因,基本就是百万播放
因为取得是所有的数据推荐原因,所以图表的legend会很多,就需要采用翻页的形式展示,也就是配置一个属性type: scroll
legend: {
type: 'scroll',
orient: 'vertical', // 水平还是垂直
},
中间的文字展示配置
series:{
...
label: {
show: false, // 不hover图表时不展示
formatter: '{b}: {c}({d}%)',
position: 'center'
},
// hover图表时展示的样式
emphasis: {
label: {
show: true,
fontSize: 18,
fontWeight: 'bold'
}
},
...
}
嵌入B站视频
表格使用的是
Element Plus的table,嵌入视频就只需要一个iframe即可,src就需要数据中的aid、bid、cid
//player.bilibili.com/player.html?aid=${row.aid}&bvid=${row.bid}&cid=${row.cid}&page=1&high_quality=1
<iframe
:src="`//player.bilibili.com/player.html?aid=${row.aid}&bvid=${row.bid}&cid=${row.cid}&page=1&high_quality=1`"
width="60%" height="360" scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true"
sandbox="allow-top-navigation allow-same-origin allow-forms allow-scripts"> </iframe>
数据分析
现在的数据量不是很多,结果也不是那么准确,基本排名靠前的视频分类大概就是搞笑、手游、单机游戏、美食、日常等,能有过万点赞、百万播放的基本就能上热门。等数据量再大点的时候再看看什么分类多。