Python实战:爬取B站“每周必看”栏目数据并进行可视化
简介:对 Bilibili 网站的“每日必看”栏目爬取热门视频的信息,包括视频期数、标题、类型、观看数等,爬取数据上千条,对数据进行分析并实现数据可视化
环境:python 3.9,requests,beautifulsoup4,pandas,pyecharts,jupyter notebook 等
网站分析
要分析的网页:
https://www.bilibili.com/v/popular/weekly/?num=265
右键页面 -> 检查 -> Network
这里以我喜欢的UP主为例,通过查找UP主名“小约翰可汗”,找到一个请求URL
这个URL得到的就是每一期“每周必看”栏目的视频数据,其中包括了视频名称、视频地址、播放数、点赞数等等
请求URL:
https://api.bilibili.com/x/web-interface/popular/series/one?number=265
对于该URL,我们可以修改number={265}的期数,来获得每一期的数据
数据爬取
1、导入库
import re
import requests
import pandas as pd
import time
2、爬取数据
df = pd.DataFrame()
for week in range(200,267):
# 爬取数据
url = f"https://api.bilibili.com/x/web-interface/popular/series/one?number={week}"
header = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:125.0) Gecko/20100101 Firefox/125.0",
"Referer": "https://www.bilibili.com",
}
time.sleep(3)
json_data = requests.get(url, headers=header).json()
# pandas初始化
_df = pd.json_normalize(json_data['data']['list'], errors='ignore')
_df['num'] = week
# 将每一期的DataFrame数据进行拼接
df = pd.concat([df, _df])
3、对数据进行预处理
# 对列重新进行排序
df = df.loc[:,
['num', 'owner.name', 'owner.mid', 'title', 'rcmd_reason', 'tname', 'bvid', 'short_link_v2', 'stat.view',
'stat.danmaku', 'stat.reply', 'stat.like', 'stat.favorite', 'stat.coin', 'stat.share', 'pubdate', 'duration',
'videos', 'rights.is_cooperation', 'pub_location', 'owner.face', 'pic']]
# 对列重命名
mydict = {'num': '期数', 'owner.name': 'UP主名', 'owner.mid': 'UID', 'title': '标题', 'rcmd_reason': '推荐原因',
'tname': '视频类型', 'bvid': '视频号', 'short_link_v2': '视频链接', 'stat.view': '观看数',
'stat.danmaku': '弹幕数', 'stat.reply': '评论数', 'stat.like': '点赞数', 'stat.favorite': '收藏数',
'stat.coin': '投币数', 'stat.share': '分享数', 'pubdate': '发布时间', 'duration': '视频时长',
'videos': '视频数', 'rights.is_cooperation': '合作视频', 'pub_location': '发布所在地',
'owner.face': 'UP主头像链接', 'pic': '视频封面链接'}
df.rename(columns=mydict, inplace=True)
4、保存数据
# csv_file 文件路径
csv_file = "./bilibili.csv"
# 保存 DataFrame 到 csv 文件
df.to_csv(csv_file, index=False, encoding='utf-8')
print(f"爬取的数据共计{df.shape[0]}条")
print("数据已保存到csv文件:", csv_file)
思路:
用for循环爬取多期视频数据。
使用 requests 获取指定 URL 的页面内容。
对json数据的key重新进行排序,方便后面的操作。
对json的列重命名,方便观看。
将json数据以csv格式保存下来。
数据处理
使用 Jupyter Notebook
1、读取csv数据
import pandas as pd
df = pd.read_csv("./bilibili.csv", encoding='gbk')
df
2、把发布时间的时间戳格式化
df['发布时间'] = pd.to_datetime(df['发布时间'], unit='s')
# 格式化时间戳为特定的时间格式
# 格式化为年-月-日 时:分:秒
df['发布时间'] = df['发布时间'].dt.strftime('%Y-%m-%d %H:%M:%S')
df['发布时间']
3、对视频时长数据格式化
视频时长的数据形式为秒数
若视频时长大于等于1小时,转换成 小时:分钟:秒,否则转换成 分钟:秒
df['视频时长'] = pd.to_timedelta(df['视频时长'], unit='s')
# 计算小时、分钟和秒数
df['小时'] = df['视频时长'].dt.components['hours']
df['分钟'] = df['视频时长'].dt.components['minutes']
df['秒'] = df['视频时长'].dt.components['seconds']
# 根据条件进行格式转换
df['视频时长'] = df.apply(lambda row: "{:02d}:{:02d}:{:02d}".format(row['小时'], row['分钟'], row['秒']) if row['小时'] >= 1 else "{:02d}:{:02d}".format(row['分钟'], row['秒']), axis=1)
# 将临时使用的列删除
df = df.drop(columns=['小时', '分钟', '秒'])
df[['视频时长']]
4、修改“合作视频”一栏
合作视频数据为 1或0
将其修改成 是或否
df['合作视频'].replace({0: '否', 1: '是'}, inplace=True)
df[['合作视频']]
数据存储
1、把处理好的csv数据备份成bilibili_backup.csv
# 保存 DataFrame 到 csv 文件
csv_file = './bilibili_backup.csv'
df.to_csv(csv_file, index=False)
2、将备份的csv文件上传到腾讯云
官方文档
https://cloud.tencent.com/document/product/436/12269
from qcloud_cos import CosConfig
from qcloud_cos import CosS3Client
import sys
import logging
# 正常情况日志级别使用 INFO,需要定位时可以修改为 DEBUG,此时 SDK 会打印和服务端的通信信息
logging.basicConfig(level=logging.INFO, stream=sys.stdout)
# 1. 设置用户属性, 包括 secret_id, secret_key, region 等。Appid 已在 CosConfig 中移除,请在参数 Bucket 中带上 Appid。Bucket 由 BucketName-Appid 组成
secret_id = '************************************' # 用户的 SecretId,建议使用子账号密钥,授权遵循最小权限指引,降低使用风险。子账号密钥获取可参见 https://cloud.tencent.com/document/product/598/37140
secret_key = '*************************************' # 用户的 SecretKey,建议使用子账号密钥,授权遵循最小权限指引,降低使用风险。子账号密钥获取可参见 https://cloud.tencent.com/document/product/598/37140
region = 'ap-guangzhou' # 替换为用户的 region,已创建桶归属的 region 可以在控制台查看,https://console.cloud.tencent.com/cos5/bucket
# COS 支持的所有 region 列表参见 https://cloud.tencent.com/document/product/436/6224
token = None # 如果使用永久密钥不需要填入 token,如果使用临时密钥需要填入,临时密钥生成和使用指引参见 https://cloud.tencent.com/document/product/436/14048
scheme = 'https' # 指定使用 http/https 协议来访问 COS,默认为 https,可不填
config = CosConfig(Region=region, SecretId=secret_id, SecretKey=secret_key, Token=token, Scheme=scheme)
client = CosS3Client(config)
bucket = '******************'
# key:上传到cos后的名字
# local_file:本地文件名字
def upload(key, local_file):
logging.info(f"开始上传{local_file}")
client.upload_file(
Bucket=bucket,
Key=key,
LocalFilePath=local_file,
EnableMD5=False,
progress_callback=None
)
url = f"{scheme}://{bucket}.cos.{region}.myqcloud.com/{key}"
return url
upload('bilibili_backup.csv', './bilibili_backup.csv')
数据可视化
这里使用 pyecharts 实现可视化,这个库非常的好用
下面是 pyecharts v1/v2 的官方文档
https://pyecharts.org/#/zh-cn/intro
1、导入库
from pyecharts.charts import Pie
from pyecharts.charts import Bar
from pyecharts import options as opts
2、统计视频类型
# 统计视频类型
y_data = df.groupby('视频类型')['视频号'].count()
datas = [(item, int(y_data[item])) for item in y_data.index]
# 绘制饼图
pie = (
Pie()
.add(
"视频类型",
datas, percent_precision=1,
center=["40%", "50%"],
)
.set_global_opts(
title_opts=opts.TitleOpts(title="视频类型分布"),
legend_opts=opts.LegendOpts(pos_left="75%", orient="vertical"),
)
.set_series_opts(
label_opts=opts.LabelOpts(formatter="{b}:{c}"),
tooltip_opts=opts.TooltipOpts(formatter="{b}:{c}")
)
)
pie.render("video_type_pie_chart.html")
3、排序并统计出播放数最多的十个视频
# 对播放数进行排序,采用降序,播放数多的靠前
sorted_df = df.sort_values(by='播放数', ascending=False)
# 取出播放数最多的前10个视频
top10 = sorted_df.head(10)
# 绘制柱状图
bar = (
Bar()
.add_xaxis(top10['UP主名'].tolist()[::-1])
.add_yaxis("播放数", top10['播放数'].tolist()[::-1])
.set_series_opts(label_opts=opts.LabelOpts(position="right")) # 标签显示在右侧
.reversal_axis()
.set_global_opts(
title_opts=opts.TitleOpts(title="视频播放数统计TOP10"),
)
)
bar.render("top10_video_play_count.html")
小结
算是对爬虫的一次深层次的学习
数据可视化部分还有matplotlib 和 seaborn 可以用,今后也会去了解一些
作者:TyreBurst