添加up画像统计量

This commit is contained in:
Sheyiyuan 2025-03-19 09:30:30 +08:00
parent 008097764f
commit 4e792dc722
4 changed files with 152 additions and 16 deletions

BIN
.DS_Store vendored Normal file

Binary file not shown.

3
.gitignore vendored
View File

@ -1,3 +1,4 @@
./venv/
.idea/
data/
data/
*/.DS_Store

109
main.py
View File

@ -78,20 +78,19 @@ class BiliWebCrawler:
# 获取视频最高分辨率基于dimension对象
max_width = 0
max_height = 0
for format_info in video_data.get('formats', []):
dimension = format_info.get('dimension', {})
width = dimension.get('width', 0)
height = dimension.get('height', 0)
rotate = dimension.get('rotate', 0)
dimension = video_data.get('dimension', {})
width = dimension.get('width', 0)
height = dimension.get('height', 0)
rotate = dimension.get('rotate', 0)
# 处理视频旋转当rotate=1时宽高互换
if rotate == 1:
width, height = height, width
# 处理视频旋转当rotate=1时宽高互换
if rotate == 1:
width, height = height, width
# 通过像素总量比较分辨率
if (width * height) > (max_width * max_height):
max_width = width
max_height = height
# 通过像素总量比较分辨率
if (width * height) > (max_width * max_height):
max_width = width
max_height = height
# 将分辨率格式化为 "宽x高" 的字符串
resolution_str = f"{max_width}x{max_height}" if max_width and max_height else "未知"
@ -105,23 +104,96 @@ class BiliWebCrawler:
tag_data = [tag['tag_name'] for tag in tag_json.get('data', [])]
info = {
'BV号': self.bvid,
'title': video_data.get('title', ''),
'up主': video_data.get('owner', {}).get('name', ''),
'up主名称': video_data.get('owner', {}).get('name', ''), # 新增字段
'up主UID': video_data.get('owner', {}).get('mid', ''), # 新增UID字段
'播放量': video_data.get('stat', {}).get('view', 0),
'弹幕量': video_data.get('stat', {}).get('danmaku', 0),
'点赞量': video_data.get('stat', {}).get('like', 0),
'投币量': video_data.get('stat', {}).get('coin', 0),
'收藏量': video_data.get('stat', {}).get('favorite', 0),
'分享量': video_data.get('stat', {}).get('share', 0),
'评论量': video_data.get('stat', {}).get('reply', 0),
'发布时间的timestamp': video_data.get('pubdate', 0),
'发布时间': time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(video_data.get('pubdate', 0))),
'分区': video_data.get('tname', ''),
'标签': tag_data,
'视频方向': self._get_video_orientation(video_data.get('dimension', {})),
'视频最高分辨率': resolution_str,
'视频类型': video_data.get('copyright', 0),
'视频分p数': len(video_data.get('pages', []))
'视频类型': ["","自制", "转载"][video_data.get('copyright', 0)],
'视频分p数': len(video_data.get('pages', [])),
'视频总时长': self.get_video_length(video_data.get('pages', [])),
'简介': video_data.get('desc', '').replace('\n', '\\n'),
}
return info
def get_video_length(self,pages):
"""获取视频总时长"""
length = 0
for page in pages:
length += page.get('duration', 0)
return length
def _get_video_orientation(self, dimension):
"""判断视频方向(横屏/竖屏)"""
width = dimension.get('width', 0)
height = dimension.get('height', 0)
rotate = dimension.get('rotate', 0)
# 处理视频旋转90度或270度旋转时需要交换宽高
if rotate in [1, 3]:
width, height = height, width
return "横屏" if width >= height else "竖屏"
# 在类方法中添加以下新方法(建议放在 get_video_info 方法之后)
def get_up_info(self, mid):
"""获取UP主详细信息"""
if not mid:
return None
url = f"https://api.bilibili.com/x/web-interface/card?mid={mid}&photo=false"
resp = self._safe_request(url)
if not resp:
return None
try:
data = resp.json().get('data', {})
card = data.get('card')
up_info = {
'uid': mid,
'昵称': card['name'],
'性别': card['sex'],
'头像': card['face'],
'等级': card['level_info']['current_level'],
'粉丝数': card['fans'],
'稿件数': data['archive_count'],
'获赞数': data['like_num'],
}
except Exception as e:
print(f"解析UP主数据失败: {str(e)}")
return None
try:
# 获取投稿列表
archive_url = f'https://api.bilibili.com/x/space/arc/search?mid={mid}&ps=30'
archive_resp = self._safe_request(archive_url)
if archive_resp and archive_resp.status_code == 200:
archive_data = archive_resp.json()
print(archive_data)
videos = archive_data.get('data', {}).get('list', {}).get('vlist', [])
# 计算30天前的时间戳
month_ago = time.time() - 30 * 86400
# 统计符合时间条件的视频
recent_count = sum(1 for v in videos if v.get('created') > month_ago)
up_info['近一个月投稿数'] = recent_count
except Exception as e:
print(f"获取投稿数据失败: {str(e)}")
return up_info
def get_danmaku(self):
"""获取弹幕数据"""
if not self.bvid:
@ -277,6 +349,13 @@ class BiliWebCrawler:
comments_filename = os.path.join(video_dir, f'{self.bvid}_{len(comments)}_comments.csv')
self.save_to_csv(comments, comments_filename)
# 新增UP主信息记录
print("正在获取UP主信息...")
up_info = self.get_up_info(video_info.get('up主UID'))
up_info['BV号'] = self.bvid
up_csv_path = os.path.join(base_dir, 'up_info.csv')
self.save_to_csv([up_info], up_csv_path, mode='a')
print(f"抓取完成!结果已保存到 {video_dir}/")
else:
print("未获取到视频信息,无法进行抓取。")

56
指标体系构建.md Normal file
View File

@ -0,0 +1,56 @@
## 外在属性指标
### 1.基础流量指标
需要视频BV号。
- [x] 播放量
- [x] 点赞量
- [x] 投币量
- [x] 收藏量
- [x] 分享量
- [x] 评论数
- [x] 弹幕数
### 2.up画像指标
需要up主UID。
- [x] 粉丝数
- [x] 总获赞数
- [x] 投稿数
- [ ] 近一个月投稿数
### 3.衍生指标
- [x] 点赞率=点赞量/播放量
- [x] 互动率=(点赞量+投币量+收藏量+分享量+评论数+弹幕数)/播放量
- [x] 外溢系数=分享量/收藏量(反映内容外溢性)
## 内在属性指标
### 1.内容属性指标
- [x] 时长
- [x] 发布时间
- [x] 标题
- [x] 分区
- [x] 标签
- [x] 最高清晰度
### 2.内容结构指标
- [ ] 是否分章节
- [x] 是否分P
- [ ] 是否有字幕
## 特殊指标(可能无法直接爬取,需特殊处理)
同时需要人工智能和能工智人。
### 1.较易处理
- [x] 是否为联合投稿Sy这个可以直接获取没这么麻烦
- [ ] 是否为系列作品(标题关键词分析)
- [x] 原创or搬运只能投一个币为搬运Sy这个也可以直接获取没这么麻烦
- [x] 横屏or竖屏Sy这个还是可以直接获取没这么麻烦
- [ ] <mark>是否进入热门</mark>(作为机器学习的预测目标)
### 2.较难处理
产生较大数据量。
- [ ] 标题原创性见DS代码
- [ ] 标签区分度见DS代码
- [ ] 弹幕情感倾向得分(单独处理)
- [ ] 封面(图片分析可以单独写一章了)
## 展望(即做不了的)
鉴于标题吸引力、剪辑质量、音频质量、封面设计、BGM体验等因素涉及主观判断
平均播放时长这种B站几年没做外显没法算完播率无法直接获取
领域垂直度等指标很难算,
点击率等指标爬不到,
我们希望后来者能克服这些困难进一步分析(如利用问卷等),
也可以考虑时间序列等因素构建更复杂的模型。
(总之我们不做)