精华内容
下载资源
问答
  • b站弹幕
    万次阅读 多人点赞
    2019-01-26 17:57:26

    一、B站弹幕的api接口

    1.'https://comment.bilibili.com/' + cid + '.xml'
    2.'https://api.bilibili.com/x/v1/dm/list.so?oid=' + cid
    e.g:
    cid = 72540443
    https://comment.bilibili.com/72540443.xml
    https://api.bilibili.com/x/v1/dm/list.so?oid=72540443

    经过测试两者的内容一致
    参考网址:https://blog.csdn.net/u014788374/article/details/80367285

     

    二、B站弹幕XML文件中的参数的含义

    <d p="157.47900,1,25,16777215,1548340494,0,389b20da,11114024647262210">啧啧,原来阿卡丽那么小?</d>
    参数1(157.47900):弹幕出现的时间,以秒数为单位
    参数2(1):弹幕的模式,1-3 滚动弹幕,4 底端弹幕,5顶端弹幕,6 逆向弹幕,7 精准定位,8 高级弹幕
    参数3(25):字号 (12非常小,16特小,18小,25中,36大,45很大,64特别大)
    参数4(16777215):字体的颜色;这串数字是十进制表示;通常软件中使用的是十六进制颜色码;
               e.g:
               白色   
               RGB值:(255,255,255)     
               十进制值:16777215      
               十六进制值:#FFFFFF
    参数5(1548340494):unix时间戳,从1970年1月1日(UTC/GMT的午夜)开始所经过的秒数
    参数6(0):弹幕池,0普通池,1字幕池,2特殊池 【目前特殊池为高级弹幕专用】
    参数7(389b20da):发送者的ID,用于“屏蔽此弹幕的发送者”功能
    参数8(11114024647262210):弹幕在弹幕数据库中rowID 用于“历史弹幕”功能。


    参考网站:https://zhidao.baidu.com/question/2053399219925598627.html

                      https://zhidao.baidu.com/question/1430448163912263499.html
    进制转换网站:http://tool.oschina.net/hexconvert/

     

    三、XML格式弹幕转换为ASS格式

    XML格式:可扩展标记语言,一种简单的数据存储语言 (eXtensible Markup Language)
    SRT格式:全称是SubRip Text;最常见的文本字幕,制作起来简单,时间代码+字幕。
    SSA格式:全称是S Station Alpha;功能上比src更强大支持各种颜色、字体等特效。
    ASS格式:全称是Advanced SubStation Alpha;包含ssa所有的功能并在ssa原有功能的基础上还进行了扩展。
    视觉角度上讲ssa和ass视觉效果更好一些。

    原料:XML文件
    工具:Danmu2Ass
    下载网址:https://archive.codeplex.com/?p=danmu2ass
                      http://www.wmzhe.com/soft-30545.html#download
     操作步骤: 
    1.下载一份XML
    2.下载Danmu2Ass
    3.解压Danmu2Ass
    4.将XML文件拖到解压出来的exe可执行文件上
    5.等待处理完毕,ass文件会出现在原XML的位置那

    问题1:新建下载任务,下载链接好像有问题,xml转化ass出错,不知道为什么
    推荐右键另存为保存为.xml文件,测试没有问题

    推荐阅读:
    《如何将Xml格式的弹幕转换为Ass格式的弹幕》https://www.bilibili.com/read/cv1022304/
    https://jingyan.baidu.com/article/1612d5007c24eae20e1eee1c.html
    bilibili ASS 弹幕在线转换 https://www.baidu.com/link?url=M5Yb23bJc5HUivlGXaMO1mPFXgdYcPnV_alPdIzYA8sahY1O04oWkO95E5GRlnMhDhB7d15TkJFtGwijtgDbT_&wd=&eqid=996bb2bb00097810000000035c4affe2

     

    四、播放弹幕方式

    1.转化为ass直接拖入播放器,好像和原bilibili视频字体大小有差别
    2.bililocal
    3.弹弹play 

    参考链接:
    [全格式本地弹幕播放器] 总贴 https://tieba.baidu.com/p/2319140116?red_tag=2354082521
    [BiliLocal][全格式本地弹幕播放器]Ver_0.4.2_NewYear https://tieba.baidu.com/p/3591706098?red_tag=2192108968

     

    五、历史弹幕

    之前说的 'https://comment.bilibili.com/' + cid + '.xml' ,是当前弹幕池的弹幕
    历史弹幕的接口
    https://api.bilibili.com/x/v2/dm/history?type=1&date=xxxx-xx-xx&oid=xxxxx
    e.g:
    date=2019-01-25
    oid=cid=72540443
    https://api.bilibili.com/x/v2/dm/history?type=1&date=2019-01-25&oid=72540443

    b站看历史弹幕:https://www.baidu.com/link?url=vZYuCffklR6UHHgJ4tFOVXxy3XiQKe8Awwh261ralnSkT_a3bZ34LarKh54uiZLKb3vOq4We9sTTT6bwsdR6EkBF2H5PggdAOlsGvObUOy_&wd=&eqid=b28b885a0002d7e7000000035c4bd9a1
    全弹幕装填:据说bililocal可以做到,好像现在也失效了

    https://tieba.baidu.com/p/5755040883?red_tag=3178834393

     

    六、弹幕反查用户

    b站的每一个视频都有唯一一个cid号,通过这个cid号可以查到视频的弹幕
    <d p="157.47900,1,25,16777215,1548340494,0,389b20da,11114024647262210">啧啧,原来阿卡丽那么小?</d>
    d是弹幕的节点,p是弹幕的属性
    <d p="弹幕出现时间,模式,字体大小,颜色,发送时间戳,弹幕池,用户Hash,数据库ID">啧啧,原来阿卡丽那么小?</d>
    参数7(389b20da):发送者的ID,用于“屏蔽此弹幕的发送者”功能


    用户 Hash 把数字 ID 用 ITU I.363.5 算法进行了 Hash,
    生成一个彩虹表,反查即可。
    使用一下API可以把HASH转化到数字ID:
    http://biliquery.typcn.com/api/user/hash/[用户Hash]
    直接在网页上改链接也可以,或者写程序请求也可以,会得到一串json
    {"error":0,"data":[{"id":17882889}]} // 比较老的用户
    {"error":0,"data":[{"id":390105526},{"id":21670130}]} // 一般新用户
    用户ID(uid)为后者。用B站的个人主页网址格式就能找到了弹幕发送者的主页了
    格式如下:https://space.bilibili.com/uid/#/


    参考链接:
    《B站从弹幕反查用户小记》https://www.baidu.com/link?url=sPAH80u8PTLGscNQxJzP1UKot81xhJJT7CAN6A5tx7PvkeIurn98AVktkWT5d5DG&wd=&eqid=d408769d00066ad0000000035c4add63
    《B 站弹幕查发送者》https://typcn.com/legacy/blog/posts/bilibili-comment-sender-digger.html
    bilibili工具箱:https://biliquery.typcn.com/

     

    七、Python时间转换

    >>> import datetime
    >>> datetime.datetime.fromtimestamp(1548422334)
    datetime.datetime(2019, 1, 25, 21, 18, 54)

    参考链接:
    https://www.cnblogs.com/shhnwangjian/p/6117602.html

    最后,网上信息太散,整理一下放在这里~~,虽然都是看来的,还是无耻的原创一下吧!

    相关链接:A站弹幕接口

    更多相关内容
  • B站弹幕抓取2021.zip

    2021-09-28 00:00:26
    抓取B站弹幕数据。 弹幕dmid,唯一 可用于操作参数 视频内弹幕出现时间,毫秒 弹幕类型,1 2 3:普通弹幕 4:底部弹幕 5:顶部弹幕 6:逆向弹幕 7:高级弹幕 8:代码弹幕 9:BAS弹幕(仅限于特殊弹幕专包) 弹幕字号...
  • 易语言-B站弹幕助手

    2021-06-29 00:23:07
    B站弹幕助手源码 可以在线编辑房间号啦hhh 可以获取up头像和名字
  • 说明:窗口程序,一键解析欲cha询的弹幕发送者的UID。
  • B站弹幕数据分析与可视化, 自动化提取网站弹幕。输入网站地址即可提取。 弹幕数量 词云分析 情感分析 使用分析
  • 运行程序,输入Bvid和爬取日期;程序运行完成后会在当前文件夹下生成一个csv格式文件。
  • YPERLINK " od弹幕实现:基于B站弹幕开源系统1) Android弹幕实现:基于B站弹幕开源系统( 如今的视频播放流行在视频上飘弹幕这里面做的相对比较成熟稳定使用量较多的弹幕系统当推弹幕系统,弹幕系统已经作为开源...
  • 说明 :利用算法解析B站弹幕发送者的uid。 ' Copyright 2020 Liv. ' Author:Liv ' email:1319923129@qq.com ' 本项目遵循GPL开源协yi,请勿商用与闭源。
  • B站弹幕源码

    2015-07-07 07:50:27
    当下最火的弹幕源码...有兴趣的可以下载来看看
  • B站弹幕助手-易语言

    2021-06-12 15:02:36
    B站弹幕助手
  • B站弹幕发送者UID解析器源码 https://bbs.125.la/forum.php?mod=viewthreadtid=14647762 请支持原作者 @liv 算法非原创 使用鱼刺线程池 调试的时候可能会很慢,编译之后速度非常快,基本上不到10s就能解析2000条了 请...
  • 哔哩哔哩 B站 PHP H5播放器 解析源码
  • 类似B站弹幕播放器,可以发弹幕有单独数据库,可以设置禁发关键词,还可以设置暂停广告等,功能多全开源,可进行二次开发
  • bilibili_danmaku_subtitles_terminal_script这是一个基于nodejs的终端B站弹幕脚本HXD们能不能帮忙点个star呀怎么用?理论上你是需要使用npm安装依赖的,分别是fetch,xml2js,sleep然后就可以用nodejs *.js,然后输入...
  • 对于视频网站来说弹幕是一个十分常见的功能, 目前业界比较出名的弹幕库是B站的DanmakuFlameMaster(不过很久没有更新了),这个弹幕库的功能还是十分完善和稳定的,它里面的弹幕主要分为两种:视频播放时用户实时发送的...

    对于视频网站来说弹幕是一个十分常见的功能, 目前业界比较出名的弹幕库是B站的DanmakuFlameMaster(不过很久没有更新了),这个弹幕库的功能还是十分完善和稳定的,它里面的弹幕主要分为两种:

    视频播放时用户实时发送的

    视频加载时服务端下发的弹幕集合

    由于整个弹幕库涉及到的逻辑还是非常多的, 本文主要分析一下用户发送一条从右向左滚动的弹幕的实现逻辑(不涉及视频弹幕时间同步等相关逻辑):

    下图是用户发送一条弹幕时DanmakuFlameMaster的大致工作逻辑图:

    dd469c98f288a4486c289ee2c345fdd6.png

    涉及到的各个类大致的作用

    R2LDanmaku : 一个弹幕对象, 里面包含x、y坐标, 缓存的Bitmap等属性

    DanmakuView : 用来承载弹幕显示的ViewGroup, 除了它之外还有DanmakuSurfaceView、DanmakuTextureView

    DrawHandler : 一个绑定了异步HandlerThread的Handler, 控制整个弹幕的显示逻辑

    CacheManagingDrawTask : 维护需要绘制的弹幕列表, 控制弹幕缓存逻辑

    DrawingCacheHolder : 弹幕缓存的实现,缓存的是Bitmap, 与BaseDanmaku绑定

    DanmakuRenderer : 对弹幕做一些过滤、碰撞检测、测量、布局、缓存等工作

    Displayer : 持有Canvas画布, 绘制弹幕

    在向DanmakuView中添加弹幕时会触发弹幕的显示流程:

    DanmakuView.java

    public void addDanmaku(BaseDanmaku item) {

    if (handler != null) {

    handler.addDanmaku(item);

    }

    }

    复制代码

    DrawHandler调度引起DanmakuView的渲染

    将弹幕添加到CacheManagingDrawTask的弹幕集合danmakuList中

    CacheManagingDrawTask.CacheManager创建弹幕缓存DrawingCache

    通过Choreographer来不断渲染DanmakuView

    第一步其实就是把弹幕添加到一个集合中,这里就不细看了,直接看DrawingCache.DrawingCacheHolder的创建

    创建弹幕缓存DrawingCacheHolder

    其实这里的缓存说白了就是一个Bitmap对象, 因为DanmakuFlameMaster的弹幕绘制的实现是 : 先把弹幕画在一个Bitmap上, 然后再把Bitmap绘制在Canvas上

    CacheManagingDrawTask.CacheManager里面有一个HandlerThread,他会异步创建DrawingCache.DrawingCacheHolder,不过在创建DrawingCache前,会先尝试从缓存池中复用(找有没有可以复用的Bitmap):

    byte buildCache(BaseDanmaku item, boolean forceInsert) {

    ...

    DrawingCache cache = null;

    // 找有没有可以完全复用的弹幕,文字,宽,高,颜色等都相同

    BaseDanmaku danmaku = findReusableCache(item, true, mContext.cachingPolicy.maxTimesOfStrictReusableFinds); //完全复用

    if (danmaku != null) {

    cache = (DrawingCache) danmaku.cache;

    }

    if (cache != null) {

    ...

    cache.increaseReference(); //增加引用, 同屏上完全相同的弹幕时可以复用同一个缓存的

    item.cache = cache;

    mCacheManager.push(item, 0, forceInsert);

    return RESULT_SUCCESS;

    }

    // 找有没有差不多可以复用的弹幕

    danmaku = findReusableCache(item, false, mContext.cachingPolicy.maxTimesOfReusableFinds);

    if (danmaku != null) {

    cache = (DrawingCache) danmaku.cache;

    }

    if (cache != null) {

    danmaku.cache = null;

    cache = DanmakuUtils.buildDanmakuDrawingCache(item, mDisp, cache, mContext.cachingPolicy.bitsPerPixelOfCache); //redraw

    item.cache = cache;

    mCacheManager.push(item, 0, forceInsert);

    return RESULT_SUCCESS;

    }

    ...

    cache = mCachePool.acquire(); //直接创建出来一个弹幕

    cache = DanmakuUtils.buildDanmakuDrawingCache(item, mDisp, cache, mContext.cachingPolicy.bitsPerPixelOfCache);

    item.cache = cache;

    boolean pushed = mCacheManager.push(item, sizeOf(item), forceInsert);

    ....

    }

    复制代码

    上面这个方法其实主要分为3步:

    寻找完全可以复用的弹幕,即内容、颜色等完全相同的, 同屏上完全相同的弹幕时可以复用同一个缓存的

    寻找差不多可以复用的,这里的差不多其实是指找到一个比要画的弹幕大的弹幕(当然要大在一定范围内的)

    没有缓存的话就创建一个

    上面2、3两步都要走一个核心方法DanmakuUtils.buildDanmakuDrawingCache():

    DrawingCache buildDanmakuDrawingCache(BaseDanmaku danmaku, IDisplayer disp, DrawingCache cache, int bitsPerPixel) {

    ...

    cache.build((int) Math.ceil(danmaku.paintWidth), (int) Math.ceil(danmaku.paintHeight), disp.getDensityDpi(), false, bitsPerPixel);

    DrawingCacheHolder holder = cache.get();

    if (holder != null) {

    ...

    ((AbsDisplayer) disp).drawDanmaku(danmaku, holder.canvas, 0, 0, true); //直接把内容画上去

    ...

    }

    return cache;

    }

    复制代码

    即先build,然后draw:

    DrawingCache.build():

    public void buildCache(int w, int h, int density, boolean checkSizeEquals, int bitsPerPixel) {

    boolean reuse = checkSizeEquals ? (w == width && h == height) : (w <= width && h <= height);

    if (reuse && bitmap != null) {

    bitmap.eraseColor(Color.TRANSPARENT);

    canvas.setBitmap(bitmap);

    recycleBitmapArray(); //一般没什么用

    return;

    }

    ...

    bitmap = NativeBitmapFactory.createBitmap(w, h, config);

    if (density > 0) {

    mDensity = density;

    bitmap.setDensity(density);

    }

    if (canvas == null){

    canvas = new Canvas(bitmap);

    canvas.setDensity(density);

    }else

    canvas.setBitmap(bitmap);

    }

    复制代码

    其实就是如果这个DrawingCache中有Bitmap的话,那么就擦干净。如果没有Bitmap,那么就在native heap上创建一个Bitmap,这个Bitmap会和DrawingCache.DrawingCacheHolder的canvas管关联起来。

    这里在native heap上创建Bitmap会减小java heap的压力,避免OOM

    AbsDisplayer.drawDanmaku()

    这个方法的调用逻辑挺长的,就不把源码展开分析了,其实最终是通过DrawingCacheHolder.canvas把弹幕画在了DrawingCacheHolder.bitmap上:

    SimpleTextCacheStuffer.java

    @Override

    public void drawDanmaku(BaseDanmaku danmaku, Canvas canvas...) {

    ...

    drawBackground(danmaku, canvas, _left, _top);

    ...

    drawText(danmaku, lines[0], canvas, left, top - paint.ascent(), paint, fromWorkerThread);

    ...

    }

    复制代码

    上面build和draw两步做的事简单来说就是: 在异步线程中给Danmaku准备好一个渲染完成的Bitmap

    ok, 走完上面这些步骤,其实一个绘制完成的弹幕的Bitmap就已经就绪了,接下来就是把这个Bitmap画到真正显示在平面上的画布Canvas上了

    通过Choreographer来不断渲染DanmakuView

    在最开始就已经知道DrawHandler用来控制整个弹幕逻辑,它会通过Choreographer来引起DanmakuView的渲染(draw):

    private void updateInChoreographer() {

    ...

    Choreographer.getInstance().postFrameCallback(mFrameCallback);

    ...

    d = mDanmakuView.drawDanmakus();

    ...

    }

    复制代码

    mFrameCallback其实就是个套娃,即不断调用updateInChoreographer,mDanmakuView.drawDanmakus()其实是一个抽象方法,对于DanmakuView来说, 它会调用到View.postInvalidateCompat(),即触发DanmakuView.onDraw(), 从这里之后其实又有很复杂的逻辑, 也不把源码一一展开了, 最终调用到DanmakuRenderer.accept():

    //main thread

    public int accept(BaseDanmaku drawItem) {

    ...

    // measure

    if (!drawItem.isMeasured()) {

    drawItem.measure(disp, false);

    }

    ...

    // layout 算x, y坐标

    mDanmakusRetainer.fix(drawItem, disp, mVerifier);

    ...

    drawItem.draw(disp);

    }

    复制代码

    measure()这里就不看了,其实就是根据弹幕内容测量应该占多大空间; mDanmakusRetainer.fix()最终会调用到R2LDanmaku.layout() :

    public class R2LDanmaku extends BaseDanmaku {

    @Override

    public void layout(IDisplayer displayer, float x, float y) {

    if (mTimer != null) {

    long currMS = mTimer.currMillisecond;

    long deltaDuration = currMS - getActualTime();

    if (deltaDuration > 0 && deltaDuration < duration.value) {

    this.x = getAccurateLeft(displayer, currMS); // 根据时间进度, 和当前显示器的宽度,来确定当前显示的x坐标

    if (!this.isShown()) {

    this.y = y;

    this.setVisibility(true);

    }

    mLastTime = currMS;

    return;

    }

    mLastTime = currMS;

    }

    ...

    }

    }

    复制代码

    y坐标其实是由更上一个层的类确定好的, R2LDanmaku.layout主要是确定x坐标的逻辑,他的核心算法是 : 根据时间进度,和当前显示器的宽度,来确定当前显示的x坐标

    接下来看怎么绘制一个弹幕的, 这里其实会调用到AndroidDisplayer.draw()

    public int draw(BaseDanmaku danmaku) {

    boolean cacheDrawn = sStuffer.drawCache(danmaku, canvas, left, top, alphaPaint, mDisplayConfig.PAINT);

    int result = IRenderer.CACHE_RENDERING;

    if (!cacheDrawn) {

    ...

    drawDanmaku(danmaku, canvas, left, top, false); // 绘制bitmap

    result = IRenderer.TEXT_RENDERING;

    }

    }

    复制代码

    首先这里的canvas是DanmakuView.onDraw(canvas)的canvas, sStuffer.drawCache()其实就是把前面画好的Bitmap画在这个Canvas上, 如果没有现存的Bitmap可以去画,直接把画到Canvas上。

    其实这里几乎90%的情况下都会走到sStuffer.drawCache()中

    到这里就简单的分析完了整个实现流程,上面讲的可能不是很详细,不过基本流程都讲到了

    DanmakuSurfaceView

    单独开辟一个Surface来处理弹幕的绘制操作,即绘制操作是可以在子线程(DrawHandler),不会造成主线程的卡顿

    public long drawDanmakus() {

    ...

    Canvas canvas = mSurfaceHolder.lockCanvas();

    ...

    RenderingState rs = handler.draw(canvas);

    mSurfaceHolder.unlockCanvasAndPost(canvas);

    ...

    return dtime;

    }

    复制代码

    DanmakuTextureView

    直接继承自TextureView, TextureView与View和SurfaceView的不同之处是 :

    不同于SurfaceView, 它可以像普通View那样能被缩放、平移,也能加上动画

    不同于普通View的硬件加速渲染, TextureView不具有Display List,它们是通过一个称为Layer Renderer的对象以Open GL纹理的形式来绘制的, 不过依然要同步于主线程的绘制操作

    简单的性能分析

    将DanmakuFlameMaster的Demo运行1分钟后,通过CPU Memory Profiler可以看到 : DanmakuView的Graphics占用内存比较多 , 其实主要原因是因为View硬件加速渲染时大量纹理由CPU同步到GPU消耗了大量的内存

    那么如何优化呢?

    个人感觉可以在现有的基础上使用GLSurfaceView或者GLTextureView通过Open GL来完成弹幕的渲染。

    更多Android相关文章见Android进阶计划

    b739ec46bb5c46d9c0aa4ce35ba1ea56.png

    关于找一找教程网

    本站文章仅代表作者观点,不代表本站立场,所有文章非营利性免费分享。

    本站提供了软件编程、网站开发技术、服务器运维、人工智能等等IT技术文章,希望广大程序员努力学习,让我们用科技改变世界。

    [B站弹幕库DanmakuFlameMaster源码浅析]http://www.zyiz.net/tech/detail-139031.html

    展开全文
  • 默认关闭哔哩哔哩视频弹幕,并提供常用快捷键。 这是一个简单小巧的扩展(不到 8K),它的主要功能是默认关闭哔哩哔哩(Bilibili)视频弹幕,同时提供了几个方便的播放快捷键。 目前支持如下快捷键: ∙ D 键:开启或...
  • 新手爬取b站单一视频弹幕信息,可供参考。本文需要先获取视频的oid值,可通过视频页面开发者模式,在NETWORK中搜索oid,可得知。
  • 用宋浩老师的视频爬取弹幕数据,然后做成词云显示
  • B站专用合成弹幕

    2018-08-27 21:30:55
    B站专用合成弹幕
  • Android弹幕实现:基于B站弹幕开源系统(1).docx
  • 哔哩哔哩 B站 PHP H5播放器 解析源码
  • Python实战:B站弹幕分析

    千次阅读 2021-11-10 19:49:50
    B站弹幕的数据分析时,我们怎么把B站的所有弹幕下载下来呢? 1. 流程 其实B站已经给了获取弹幕的接口,我们只需知道对应视频的cid号即可 接口如下:http://comment.bilibili.com/{cid}.xml 如我获取到的视频cid号...



    做B站弹幕的数据分析时,我们怎么把B站的所有弹幕下载下来呢?
    在这里插入图片描述

    1. 流程

    其实B站已经给了获取弹幕的接口,我们只需知道对应视频的cid号即可
    接口如下:http://comment.bilibili.com/{cid}.xml
    或者:https://api.bilibili.com/x/v1/dm/list.so?oid={cid}
    两个都可以

    如我获取到的视频cid号为:438959674,只需要上面网址改为:https://comment.bilibili.com/438959674.xml,即可得到弹幕xml文件,右键保存xml文件即可,在对文件提取弹幕生成txt文件。 再对xml稍微做点爬取处理,得到弹幕的txt文本文件
    在这里插入图片描述
    那怎么获取视频的cid号呢?


    2. 获取视频的cid号

    在对应视频页面,按F12查看页面源代码,Network->heartbeat->cid
    我的浏览器是Chrome,参考博客:https://blog.csdn.net/weixin_44899139/article/details/94770812
    在这里插入图片描述
    然后按1.流程方法


    3. 对xml文件提取弹幕,保存为txt文件

    参考博客:https://blog.csdn.net/qq_45554010/article/details/115359659

    Python代码如下:修改下cid号就可以用了

    """
    Author: Chen Chunhan
    Date  : 2021-3-31 Wed.
    提示:如果想爬取其他视频的弹幕信息请更改url和cid
    """
    import re
    
    from bs4 import BeautifulSoup
    import requests
    
    
    headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
                             'Chrome/89.0.4389.90 Safari/537.36 Edg/89.0.774.63'}
    
    # 获取视频名称和作者
    # url = 'https://www.bilibili.com/video/BV1f4411M7QC?from=search&seid=13006207604878782683'
    # response = requests.get(url, headers)
    # response.encoding = 'utf-8'
    # page_text = response.text
    # soup = BeautifulSoup(page_text, 'lxml')
    # video_title = soup.find('span', class_='tit tr-fix').text
    # print('视频名称:' + video_title)
    # uploader = soup.find('a', attrs={'report-id': 'name'}).text.strip()
    # print('UP主:' + uploader)
    
    # 获取弹幕文件
    cid = '438959674'
    xml = "https://comment.bilibili.com/{}.xml".format(cid)
    # xml = 'https://api.bilibili.com/x/v1/dm/list.so?oid={}'.format(cid)
    response = requests.get(xml, headers)
    response.encoding = 'utf-8'
    xml_text = response.text
    soup = BeautifulSoup(xml_text, 'lxml')
    barrages = [re.sub(r'\s+', '', bar.text) for bar in soup.find_all('d')]
    
    # 查看弹幕数量
    print('弹幕数量:' + str(len(barrages)))
    
    # 将弹幕写入文件
    with open('./barrages.txt', 'w', encoding='utf-8') as output_file:
        for bar in barrages:
            output_file.write(bar + '\n')
    print('弹幕信息已成功写入文件!')
    





    其他稍微有点点效参考链接:
    链接一
    链接二
    链接三
    链接四

    av号、bv号互转(不需要用到):
    链接
    链接

    展开全文
  • https://blog.csdn.net/skylibiao/article/details/119060357?spm=1001.2014.3001.5502
  • 自助b 站弹幕服务器连接器主程序负责保持与弹幕服务器的连接和解析弹幕数据,其他功能由插件提供。 自动加载plugins 文件夹下的js 文件,插件导出一个类,所有插件在程序启动时进行初始化,传入一个ebus,ebus 目前...
  • 哔哩哔哩(b站)直播发送弹幕源码
  • B站直播弹幕获取 - 用python写一个B站弹幕姬吧

    千次阅读 多人点赞 2020-04-21 16:43:08
    原本也有想过可以利用现有的弹幕姬做个插件来解决的,但无奈不会C#,所以只能自己研究b站弹幕协议。 后来有写过一个C++版本的,不过有一些小问题,这在后文中会提到。 开码 一丶利用 POST 方式获取 B 直播弹幕 ...

    前言

    关于这个小项目的由来。
    最开始是想要利用b站的弹幕进行一些互动之类的。原本也有想过可以利用现有的弹幕姬做个插件来解决的,但无奈不会C#,所以只能自己研究b站的弹幕协议。
    后来有写过一个C++版本的,不过有一些小问题,这在后文中会提到。

    开码

    一丶利用 POST 方式获取 B 站直播弹幕

    参考:【python】b站直播弹幕获取
    首先,随便打开一个b站的直播页面,按F12打开控制台,点进“网络(Network)”标签,刷新一下,然后审计一下里面的内容,可以找到“gethistory”这个文件里面就是我们要的弹幕了。
    打开的直播页面
    实际上,仔细观察便不难发现,请求 gethistory 的时候返回的是请求时最近的10条历史弹幕,不过根据这些就可以写出来一个简易的弹幕姬了。具体做法就是每隔一定的时间请求一次,然后与上次的请求做对比。不同的部分就是这段时间新发的弹幕了,这样就可以对弹幕进行一些操作了。
    我们点进“headers”标签:
    headers标签
    有了这些我们就可以开写一个弹幕姬了。
    虽然headers很乱,不过实际上我们在请求弹幕的时候并不需要这么多headers,具体哪些headers是必要的可以用实验试出来,不过具体过程和结果我就直接略去了。最后的代码可以参考:
    B站直播弹幕爬取
    或我自己写的C++版本:
    【笔记/学习】c++实现b站弹幕姬
    (代码有点长而且不是本文的重点这里就不放了)
    注:之前的时候获取弹幕的URL是:https://api.live.bilibili.com/ajax/msg,不过我写这篇文再去复现的时候发现这个URL已经没了,经过观察发现变成了 https://api.live.bilibili.com/xlive/web-room/v1/dM/gethistory 截至写文时二者都能用。不过这些都不是重点了。

    二丶利用 WebSocket 获取 B 站弹幕

    前文利用 POST 的方式获取B站弹幕。这种方法虽然简单,但也有不方便的地方。我设的时间间隔为3s,但如果3s内发送的弹幕数量超过了10条,这种方法就会丢失一部分的弹幕,而如果简单的减小时间间隔,不仅会占用更多的网络资源,如果太过频繁的话还可能会被封IP。
    而 HTTP 请求的这种缺陷也正好就是 WebSocket 的出现所为了解决的问题。事实上,我们在看B站直播的时候正是通过 WebSocket 的方式与服务器通信的。
    让我们继续打开 F12 :
    b站弹幕的websocket
    这个 sub 就是与弹幕服务器通信的 WebSocket 啦。
    点进 Message 标签,会看见一大堆东西。不过我们并不需要自己去研究这个通信协议,在 Github 上已经有了B站的API可以直接使用。
    弹幕WS协议
    API文档使用 JavaScript 写的,不过这并不妨碍我们移植一个 Python 版本的。
    由 API 可知,我们与服务器进行通信所发送的数据大多是 json 的数据,偶尔还会有 zlib 数据。所以我们自然需要导入这两个包。我们与服务器使用 WebSocket 进行通信,但原生 Python 并不能直接发送 WebSocket,我们自然也不可能使用 socket 去造轮子。不过好在已经有很多好用的 WebSocket 的库可供我们使用了。
    目前常用的 WebSocket 库有: websocket-client, websockets, aiowebsocket 三个。其中 websocket-client 是同步的,因为我们在收弹幕的同时还得要发送心跳包才能不被服务器断开连接,使用异步io会方便一些。所以不用他。另外两个我也都试过。感觉上 aiowebsocket 更稳定一些,所以这里我们使用这个库。
    安装:

    pip install aiowebsocket
    

    除了 aiowebsocket 要安装外,其他的库都是 python 自带的,直接导入就行了。自然不要忘了用了异步操作要加上 asyncio 库哦。

    import asyncio
    import zlib
    from aiowebsocket.converses import AioWebSocket
    import json
    

    之后我们写好入口函数:

    if __name__ == '__main__':
        remote = 'wss://broadcastlv.chat.bilibili.com:2245/sub'
        try:
            asyncio.get_event_loop().run_until_complete(startup(remote))
        except KeyboardInterrupt as exc:
            pring('Quit.')
    

    remote 自然就是API中弹幕服务器的地址了。然后是startup()

    roomid = '5322'
    
    data_raw='000000{headerLen}0010000100000007000000017b22726f6f6d6964223a{roomid}7d'
    data_raw=data_raw.format(headerLen=hex(27+len(roomid))[2:], roomid=''.join(map(lambda x:hex(ord(x))[2:],list(roomid))))
    
    async def startup(url):
        async with AioWebSocket(url) as aws:
            converse = aws.manipulator
            
            await converse.send(bytes.fromhex(data_raw))
            tasks=[receDM(converse), sendHeartBeat(converse)]
            await asyncio.wait(tasks)
    

    在连接到弹幕服务器后必须先发一个数据包写出进入的房间,否则连接会被断开。这里我是直接从浏览器抄的。数据包中的包长度必须要正确,所以这里要计算一下包长度。
    然后这里先把接受弹幕的 receDM() 和发送心跳包的 sendHeartBeat 先写好。接下来是这两个函数:

    hb = '00000010001000010000000200000001'
    async def sendHeartBeat(websocket):
        while True:
            await asyncio.sleep(30)
            await websocket.send(bytes.fromhex(hb))
            print('[Notice] Sent HeartBeat.')
    
    async def receDM(websocket):
        while True:
            recv_text = await websocket.receive()
            printDM(recv_text)
    

    B站的弹幕服务器是如果70秒没有心跳就断开连接,这里是30s发送一次。因为只需要发一个没有内容的数据包就行了,所以这里也是直接从浏览器抄的。。
    对于接收到的数据包的处理比较复杂,这里我们单独写一个函数来处理它。
    首先,由API我们可以看到每个数据包的头部是怎样的:

    位置0-34-56-78-1112-1516-
    说明数据包长度数据包头部长度协议版本操作类型数据包头部长度数据包内容

    不过这些内容我们并不都需要用到。
    下面上代码,具体说明在注释中写了:

    # 将数据包传入:
    def printDM(data):
        # 获取数据包的长度,版本和操作类型
        packetLen = int(data[:4].hex(),16)
        ver = int(data[6:8].hex(),16)
        op = int(data[8:12].hex(),16)
    
        # 有的时候可能会两个数据包连在一起发过来,所以利用前面的数据包长度判断,
        if(len(data)>packetLen):
            printDM(data[packetLen:])
            data=data[:packetLen]
    
        # 有时会发送过来 zlib 压缩的数据包,这个时候要去解压。
        if(ver == 2):
            data = zlib.decompress(data)
            printDM(data)
            print('db3')
            return
        
        # ver 为1的时候为进入房间后或心跳包服务器的回应。op 为3的时候为房间的人气值。
        if(ver == 1):
            if(op == 3):
                print('[RENQI]  {}'.format(int(data[16:].hex(),16)))
            return
    
        # ver 不为2也不为1目前就只能是0了,也就是普通的 json 数据。
        # op 为5意味着这是通知消息,cmd 基本就那几个了。
        if(op==5):
            try:
                jd = json.loads(data[16:].decode('utf-8', errors='ignore'))
                if(jd['cmd']=='DANMU_MSG'):
                    print('[DANMU] ', jd['info'][2][1], ': ', jd['info'][1])
                elif(jd['cmd']=='SEND_GIFT'):
                    print('[GITT]',jd['data']['uname'], ' ', jd['data']['action'], ' ', jd['data']['num'], 'x', jd['data']['giftName'])
                elif(jd['cmd']=='LIVE'):
                    print('[Notice] LIVE Start!')
                elif(jd['cmd']=='PREPARING'):
                    print('[Notice] LIVE Ended!')
                else:
                    print('[OTHER] ', jd['cmd'])
            except Exception as e:
                pass
    

    这样,一个简单的弹幕姬就完成了!

    三丶试试搞一些其他的事情吧!

    至此,我们已经有了一个可以在控制台输出弹幕内容的弹幕姬了。不过,这并不是结束,有了这个我们就可以利用弹幕搞事情了(
    先放个简单的功能:

    把弹幕保存至本地

    先到如下时间:

    import time
    

    然后我们把前面的print()函数改掉:

    def log(typ, body):
    	with open('D:/danmu.txt','a') as fd:
    		fd.write(time.strftime("[%H:%M:%S] ", time.localtime()))
            fd.write(body+'\n')
    

    这样就可以爬取弹幕到本地了。

    利用SAPI朗读弹幕

    利用 SAPI 朗读需要导入相应的包:

    import win32com.client
    

    然后改写log函数:

    def log(typ, body):
    		speak = win32com.client.Dispatch("SAPI.SpVoice")
            #创建发声对象
            speak.Speak(body)
            #使用发生对象读取文字
    	with open('D:/danmu.txt','a') as fd:
    		fd.write(time.strftime("[%H:%M:%S] ", time.localtime()))
            fd.write(body+'\n')
    

    来使python自动朗读弹幕。
    一般 Windows 都可以直接使用,不能用的话再上网查吧。。

    利用聊天机器人实现自动聊天

    首先打开b站一个直播间,发条弹幕截下包:
    测试弹幕
    照着参考,可以大致写出一份发送弹幕的python脚本

    import requests
    import time
    form_data = {
        'color': '65532',
    	'fontsize': '25',
    	'mode': '1',
    	'msg': 'test',
    	'rnd': int(time.time()),
    	'roomid': '1136753',
    	'csrf_token': 'cce335cbfa5bfd292a049b813175bd12',
    	'csrf': 'cce335cbfa5bfd292a049b813175bd12'
    }
    # 设置cookie值帮助我们在发送弹幕的时候,服务器识别我们的身份
    cookie = { '你的cookie(上图红色部分)' }
    res = requests.post('https://api.live.bilibili.com/msg/send', cookies=cookie, data=form_data)
    print (res.status_code)
    

    上面的 csrfcsrf_token 在使用的时候最好也换成自己的。
    然后可以去注册图灵机器人/思知机器人等API(不推荐图灵,之前还好,后来一去看感觉有点贵),申请到 appid。
    具体可以参考我以前写的这篇文章
    最后代码差不多是这样:

    def talk(msg):
        form_data = {
            'color': '65532',
            'fontsize': '25',
            'mode': '1',
            'msg': 'test',
            'rnd': int(time.time()),
            'roomid': roomid,
            'csrf_token': 'cce335cbfa5bfd292a049b813175bd12',
            'csrf': 'cce335cbfa5bfd292a049b813175bd12'
        }
        cookie = { '你的cookie(上图红色部分)' }
        payload = {
            'appid': '你的appid',
            'userid': '1234',
        }
        payload['spoken'] = msg
        res1 = requests.get("https://api.ownthink.com/bot", params=payload)
        form_data['msg'] = res1.json()['data']['info']['text']
        res2 = requests.post('https://api.live.bilibili.com/msg/send', cookies=cookie, data=form_data)
    

    好啦,去直播间发条弹幕看看效果:
    效果
    注意使用的时候加上限制不要对机器人的回复再去回复就行了

    。。。

    后记

    嗯。。。暂时就先写这么多吧,还有什么要补充的以后再说吧。。
    源码什么的之后再传吧。。

    展开全文
  • 成果展示 项目地址爬取弹幕可以看我之前写的这篇文章:10行代码下载B站弹幕下载代码# download.py'''依赖模块pip install requests'''import reimport requestsurl = input('请输入B站视频链接: ')res = requests....
  • Android弹幕实现:基于B站弹幕开源系统(7)QQ、微信聊天气泡样式的弹幕在附录文章得基础上,改进普通文本弹幕,实现一种特殊效果的文本弹幕,像QQ、微信一样的带有气泡背景的弹幕。实现的重点是在SpannedCacheStuffer...
  • python按日期爬取b站弹幕 2.0版

    千次阅读 2021-01-07 14:36:54
    [分析爬取b站视频弹幕](https://blog.csdn.net/HandsomeFishman/article/details/112171386) 代码 直接附上完整代码: import requests from lxml import etree import pandas as pd from wordcloud import ...
  • 所以我就写了个爬虫把弹幕爬下来,看看到底有多少个宝藏,然后顺便添加了一个词云的功能。 第三方库 界坝 词云 xml文件 用法 直接运行程序,输入网址和视频的oid,oid号应该是B站视频的唯一编码,按f12找到list.so...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 15,613
精华内容 6,245
关键字:

b站弹幕