就在昨天,2020年3月23日。可爱的B站宣布将使用BV这一新的视频编号来代替原本的AV编号..

运行环境 Runtime environment

1
2
操作系统: win10  
Python: 3.7.4

背景

2020年3月23日。可爱的B站宣布将使用BV这一新的视频编号来代替原本的AV编号..
据描述是为了保护B站视频UP的合法权益,
毕竟你懂的,现在那些用爬虫技术将B站视频批量盗取到抖音之类的地方套现的现象越来越严重。

算法推导

在此感谢网络上各位大佬的辛苦探究。
如何看待 2020 年 3 月 23 日哔哩哔哩将稿件的「av 号」变更为「BV 号」?
我有点担心,这帖子会不会有一天直接没了。我转载在这里。
公式1:公式1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
    互相转换脚本,如果算法没猜错,可以保证在 av 号  时正确,同时应该在  时也是正确的。此代码以 WTFPL 开源。

UPD:之前的代码中,所有数位都被用到是乱凑的,实际上并不需要,目前只要低 6 位就足够了。
(更大的 av 号需要 64 位整数存储,但是 b 站现在使用的应该还是 32 位整数,所以应该还要很久)

发现的方法:
首先从各种渠道的信息来看,应该是 base58 编码的。设 x 是一个钦定的 av 号,查询 ![公式1](equation.svg) 这些 av 号对应的 bv 号,发现 bv 号的第 12、11、4、9、5 位分别会变化。
所以猜测这些是 58 进制下的相应位。
但是直接 base58 是不行的,所以猜测异或了一个大数,并且 base58 的字符表可能打乱了。经过实验,bv 号最低位相同的数,av 号的奇偶性相同,这一定程度上印证了之前的猜想。

接下来找了一些 av 号 x,满足 x 和 x+1 对应 bv 号的第 11 位不同。设异或的数为 X,那么

( 表示异或)。

由于 av 号(除了最新的少量视频)最多只有 27 bits,所以可以设 。
然后可以发现 只和 和 有关,那么可以枚举这两个值(一共 种情况)然后使用上面的式子检查,就能得到若干可能的 和 。

这里我得到的可能值如下:(左边是 ,右边是 )

22 90983642
22 90983643
50 43234084
50 43234085

有奇有偶是因为异或 1 之后也能找到轮换表。
而 则使得模 58 的余数刚好变成 减它。

我取了 b=43234084,然后处理最低位,可以得到一个字符表,即 fZodR9XQDSUm21yCkr6zBqiveYah8bt4xsWpHnJE7jL5VG3guMTKNPAwcF。
对于更高位,实际上还需要知道 ,这些值也可以 枚举 58 次得到,最后我得到的值是 。
这时我发现,每一位的字符表是相同的(实际上只对 b=43234084 是这样的),然后再微调一下参数(上面代码中的两个 magic number 就相当于这里的 ),最后处理了一下 的情况就得到了这份代码。

作者:mcfx
链接:https://www.zhihu.com/question/381784377/answer/1099438784
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

图片留档:
知乎BV算法推导

代码实现

  1. python3

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    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

    def enc(x):
    x=(x^xor)+add
    r=list('BV1 4 1 7 ')
    for i in range(6):
    r[s[i]]=table[x//58**i%58]
    return ''.join(r)

    print(dec('BV17x411w7KC'))
    print(dec('BV1Q541167Qg'))
    print(dec('BV1mK4y1C7Bz'))
    print(enc(170001))
    print(enc(455017605))
    print(enc(882584971))

    # 作者:mcfx
    # 链接:https://www.zhihu.com/question/381784377/answer/1099438784
    # 来源:知乎
    # 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  2. PHP
    by esterTion
    PHP BV算法 实现

  3. Java
    by Feel_Sad
    Java BV算法 实现

总结

虽然我没有做过B站的采集,
但是,身为爬虫工程师,我是心疼的,这意味着B站采集的门槛抬高了。
哈哈哈,也没有关系,习惯了。说得我采集那几大电商巨头它们的商品ID是顺号的一样,采集都靠搜索挖掘。
出于一个三年经验的爬虫开发者,我认为bilibili是不可能会去把已有数据的所有视频AV编号直接改成BV号的,也更不可能删除。
对数据库大刀阔斧的修改会有难以计量的后果和动荡,很少有企业会这么干。

那么,如果是我,我会怎么实现B站这个AV to BV的需求呢?

1
2
3
答:对站上已有的庞大视频AV编号做一层加密封装,一个BV编号映射一个AV编号的方式。  
之后对待审和以后上传B站的视频直接使用BV号入库的方式。
我不确认以后的视频AV号是否还会在B站数据库中保留,但是很大的可能B站对外AV号的接口会逐渐关闭。

当然,我更希望我的推断是一场虚构推理。