python3网络爬虫--爬取B站视频弹幕(附源码)

news/2024/7/19 9:22:48 标签: 爬虫, python, 开发语言, B站, 弹幕, so文件, 解密

文章目录

  • 一.前言
  • 二.配置Protobuf 环境&生成编译文件
    • 1.配置Protobuf 环境
    • 2.生成编译文件
  • 三.解析弹幕
  • 四.自动解析弹幕
  • 五.总结
  • 六.参考

本篇博文记录一下爬取B站弹幕的主要思路以及完整代码

一.前言

B站在2023年将弹幕接口的返回值从.xml改成了.so文件
比如下面这个地址:

https://api.bilibili.com/x/v2/dm/wbi/web/seg.so?type=1&oid=1258114431&pid=575703555&segment_index=1&pull_mode=1&ps=0&pe=120000&web_location=1315873&w_rid=fec78ad870a48b68b35024304ba8460f&wts=1694223505

返回值示例:
在这里插入图片描述
很明显部分数据是被加密了。

二.配置Protobuf 环境&生成编译文件

1.配置Protobuf 环境

通过搜索知道了,这种格式叫做**Protobuf **,这个格式为二进制编码传输

Protobuf(Protocol Buffers)是一种轻量级的数据序列化协议,由Google开发。它可以用于结构化数据的序列化和反序列化,常用于网络通信、数据存储和配置文件等场景。
Protobuf使用简洁的语法定义数据结构,然后通过编译器生成相应的代码,用于在不同的编程语言中进行数据的序列化和反序列化操作。相比于其他序列化协议,Protobuf具有更高的性能和更小的数据体积。
使用Protobuf,你可以定义消息的字段类型、字段名称和字段顺序等信息,然后通过编译器生成的代码来进行数据的读写操作。Protobuf支持多种编程语言,包括C++、Java、Python等,因此可以在不同的平台和语言之间进行数据的传输和交换。
总的来说,Protobuf协议是一种高效、灵活和可扩展的数据序列化协议,适用于各种场景下的数据交换和存储需求。

简单来说就是一种比XML还轻量的数据。
需要解密这种格式数据需要我们下载Protobuf 的编译器(我的电脑是windows64位的,直接下载win64位即可)

https://github.com/protocolbuffers/protobuf/releases/tag/v3.17.3
在这里插入图片描述

下载完成后,解压出来
在这里插入图片描述
其中bin目录为可执行程序存放目录,我们把它加到环境变量里来:
win10的操作步骤是:
右击“此电脑”-高级系统设置-环境变量-双击path-新建-输入值-确定在这里插入图片描述

在cmd中输入protoc来验证我们的配置是否成功,如果你的控制台输出结果和我的一样,那么恭喜你,环境配置成功
在这里插入图片描述

2.生成编译文件

首先要去下载dm.proto

https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/grpc_api/bilibili/community/service/dm/v1/dm.proto

然后在控制台中输入

protoc --python_out=. dm.proto

在这里插入图片描述

就会在同目录下生成一个dm_pb2.py的文件
在这里插入图片描述
这个文件很关键。

三.解析弹幕

将上一步编译出来的dm_pb2.py文件放在脚本的同一级,这里演示解析本地.so文件
撰写代码

python">import dm_pb2
from google.protobuf import text_format

my_seg = dm_pb2.DmSegMobileReply()
with open('./seg.so', 'rb') as f:
    DATA = f.read()
my_seg.ParseFromString(DATA)

parse_data = text_format.MessageToString(my_seg.elems[0], as_utf8=True)
print(parse_data)

输出结果
在这里插入图片描述

四.自动解析弹幕

这里本人贡献出一种自动解析弹幕,输入视频的BVID即可

python">import json

import requests
import google.protobuf.text_format as text_format
import dm_pb2 as Danmaku
import re


class BEngine():
    """
    bilibili引擎
    """

    def __init__(self):
        self.headers = {
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36"}

    def do_request(self, url):
        headers = {
            "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36"
        }
        r = requests.get(url, headers=headers)
        if r.status_code == 200:
            r.encoding = 'utf-8'
            return r.text
        else:
            return False

    def get_video_cid(self, bvid):
        """
        通过bvid获取cid
        :param bvid:
        :return:
        """
        api_url = f'https://api.bilibili.com/x/web-interface/view?bvid={bvid}'
        try:
            html = self.do_request(api_url)
            if html:
                _json = json.loads(html)
                cid = _json['data'].get('cid')
                return cid
            else:
                return False
        except:
            return False

    def bvid_to_avid(self, bvid):
        """
        通过bvid获取avid
        :param bvid:
        :return:
        """
        table = 'fZodR9XQDSUm21yCkr6zBqiveYah8bt4xsWpHnJE7jL5VG3guMTKNPAwcF'
        tr = {}
        for i in range(58):
            tr[table[i]] = i
        s = [11, 10, 3, 8, 4, 6]
        xor = 177451812
        add = 8728348608

        def dec(x):
            r = 0
            for i in range(6):
                r += tr[x[s[i]]] * 58 ** i
            return (r - add) ^ xor

        return dec(bvid)

    def get_danmu(self, avid, cid):
        """
        通过so文件获取解密后的弹幕列表
        :return:
        """
        result = []
        url = 'http://api.bilibili.com/x/v2/dm/web/seg.so'
        params = {
            'type': 1,  # 弹幕类型
            'oid': cid,  # cid
            'pid': avid,  # avid
            'segment_index': 1  # 弹幕分段
        }
        resp = requests.get(url, params, headers=self.headers)
        data = resp.content
        danmaku_seg = Danmaku.DmSegMobileReply()
        danmaku_seg.ParseFromString(data)
        for j in danmaku_seg.elems:
            parse_data = text_format.MessageToString(j, as_utf8=True)
            result.append(parse_data.replace("\n", ",").rstrip(","))
        print(result)
        return result

    def parse_danmu(self, danmu_list):
        """
        解析出每个弹幕列表内容
        :param danmu_list:
        :return:
        """
        result = []
        for each_dm in danmu_list:
            res = re.findall(
                '''id: \d+,progress: (\d+),mode: (\d+),fontsize: (\d+),color: (\d+),midHash: "(.*?)",content: "(.*?)",ctime: (\d+),weight: (\d+),idStr: "(\d+)"''',
                each_dm)
            if res and len(res[0]) == 9:
                item = {
                    "progress": res[0][0],
                    "mode": res[0][1],
                    "fontsize": res[0][2],
                    "color": res[0][3],
                    "midHash": res[0][4],
                    "content": res[0][5],
                    "ctime": res[0][6],
                    "weight": res[0][7],
                    "idStr": res[0][8],
                }
                result.append(item)
            else:
                continue
        return result

    def getdanmu_format(self, bvid):
        """
        弹幕直接格式化
        :param bvid:
        :return:
        """
        avid = e.bvid_to_avid(bvid)
        cid = e.get_video_cid(bvid)
        danmu_raw = self.get_danmu(avid, cid)
        return self.parse_danmu(danmu_raw)


if __name__ == '__main__':
    e = BEngine()
    bvid = "BV1Dz4y1L7hj"
    print(e.getdanmu_format(bvid))

输出结果示例
在这里插入图片描述

五.总结

本次通过调研protobuf协议通过搭建环境,使用Python撰写代码实现了对B战弹幕的解析,对于大多数人而言,可能搭建本地环境那里有些难,在此奉上封装好的dm_pb2.py文件点击下载,大家放在自己的脚本同级目录下即可。最后祝大家玩得开心能给点个赞么?
在这里插入图片描述

六.参考

b站弹幕 Protobuf 格式解析

Python实现对Bilibili视频点赞等信息的爬取

b站弹幕 so文件解析/逆序列化

python进行B站av号和bv号的转换


http://www.niftyadmin.cn/n/5013193.html

相关文章

容器编排学习(三)Pod调度策略

一 Pod调度策略 1 概述 在 k8s 中,调度是将 Pod 分配到合适的计算节点上,然后对应节点上的 Kubelet 运行这些 pod kube-scheduler 是默认调度器,是集群的核心组件 调度器是如何工作的? 调度器通过 k8s的监测 (Watch) 机制来发现集群中…

React 中useImmer的使用

useImmer 是一个自定义 React 钩子,它结合了 React 和 immer,用于更轻松地管理状态。它可以帮助你处理不可变状态,同时减少繁琐的状态更新代码。要使用 useImmer 钩子,你需要按照以下步骤进行操作: 安装 use-immer 包&…

Java程序员所需Javascript知识

它是一种脚本语言&#xff0c;可以用来更改页面内容&#xff0c;控制多媒体&#xff0c;制作图像、动画等等 js 代码位置 <script>// js 代码 </script>引入 js 脚本&#xff0c;在js脚本中写js代码 <script src"js脚本路径"></script>注…

C++ 基础知识笔记(一)变量和数据的输入输出

C的基础知识包括如下内容&#xff1a; 变量和数据的输入输出数据类型和运算符比较运算符和布尔类型if-else 选择语句、多分支语句switch 分支语句逻辑运算符for 循环for 循环进阶数组数组进阶while 循环格式化输入输出浮点数和数据类型转换字符串和字符数组string 类型的字符串…

“数智+绿色”驱动,宏工科技助力线缆线材稳定高品质生产

9月4日-7日&#xff0c;WIRE CHINA 2023中国国际线缆及线材展览会在上海新国际博览中心举办。宏工科技现场展出线缆线材自动化生产一站式解决方案&#xff0c;与现场观众共商“数字化、智能化、绿色化”发展机遇。 线缆是制造业中最大或产品使用范围最广的基础性配套产业之一&a…

Java根据身份证号码提取出省市区,JSON数据格式

package com.rdes.talents.utils;import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern;/*** Author: 更多实用源码 www.cx1314.cn* Date: 2023/9/7 …

热迁移技术-QEMU

社区有言Talk is cheep, show me the code&#xff0c;我们尽量低纬度描述技术。 代码和版本&#xff1a; Qemu-5.0 #热迁移技术的实现者 Kernel-4.19 #提供kvm实现 热迁移的演进 Qemu有加载保存vm的功能&#xff0c;这是两个互补的操作&#xff08;--快照功能&#xff09;。保…

装备制造企业是否要转型智能装备后服务型公司?

一、从制造到服务&#xff1a;装备制造企业的转型之路 装备制造企业作为国家经济发展的重要支柱&#xff0c;面临着日益激烈的市场竞争。在这样的背景下&#xff0c;越来越多的装备制造企业开始意识到&#xff0c;通过转型为智能装备后服务型公司&#xff0c;可以更好地满足客…