社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

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

初与久歌_4a05 • 6 年前 • 844 次点击  

为了保护稿件信息安全,容纳更多投稿,维护UP主的权益,自2020年3月23日起,AV号将全面升级为BV号。与纯数字的AV号不同,BV号是一段由数字和大小写字母组成的字符串,经过算法自动生成。未来将统一使用BV号作为稿件标识。

B站官方解释,BV号是通过算法自动生成的,那么BV号和之前的AV号之间有联系吗?或者说两者可以进行互推吗?

知乎上有大佬给出了解答,亲测有效。
快膜!

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('BV1JK411p7pd'))
print(enc(498461045))

498461045
BV1JK411p7pd

具体思路如下:

互相转换脚本,如果算法没猜错,可以保证在 av 号 <2^{27} 也是正确的,同时在 <2^{30} 时也是正确的。此代码以 WTFPL 开源。

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

发现的方法:首先从各种渠道的信息来看,应该是 base58 编码的。设 x 是一个钦定的 av 号,查询 58k+x,58^2k+x,58^3k+x,58^4+x(k\in Z)。 这些 av 号对应的 bv 号,发现 bv 号的第 12、11、4、9、5 位分别会变化。所以猜测这些是 58 进制下的相应位。

但是直接 base58 是不行的,所以猜测异或了一个大数,并且 base58 的字符表可能打乱了。经过实验,bv 号最低位相同的数,av 号的奇偶性相同,这一定程度上印证了之前的猜想。

接下来找了一些 av 号 x,满足 x 和 x+1 对应 bv 号的第 11 位不同。设异或的数为 X ,那么 [\frac{X\oplus x}{58}]\neq \frac{X\oplus( x+1)}{58} ( \oplus 表示异或)。由于 av 号(除了最新的少量视频)最多只有 27 bits,所以可以设 X=2^{27}a+b(0\leqslant b <2^{27}) 。然后可以发现 X 只和 b 和 2^{27}a\ mod\ 58 有关,那么可以枚举这两个值(一共 2^{27}\times 58=7784628224 种情况)然后使用上面的式子检查,就能得到若干可能的 2^{27}a\ mod\ 58 和 b 。这里我得到的可能值如下:(左边是 2^{27}a\ mod\ 58 ,右边是 b )

22 90983642
22 90983643
50 43234084
50 43234085

有奇有偶是因为异或 1 之后也能找到轮换表。而 90983642+43234085=2^{27}-1 则使得模 58 的余数刚好变成 2^{27}-1 减它。我取了 b=43234084 ,然后处理最低位,可以得到一个字符表,即

fZodR9XQDSUm21yCkr6zBqiveYah8bt4xsWpHnJE7jL5VG3guMTKNPAwcF

。对于更高位,实际上还需要知道 2^{27}a\ mod\ 58^{2} , 2^{27}a\ mod\ 58^{3},… 这些值也可以 枚举 58 次得到,最后我得到的值是 2^{27}a\ mod\ 58^{4}=1749968 。

这时我发现,每一位的字符表是相同的(实际上只对 b=43234084 是这样的),然后再微调一下参数(上面代码中的两个 magic number就相当于这里的 a,b ),最后处理了一下 \geqslant 2^{27} 的情况就得到了这份代码。

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

更多文章:
用python爬取B站弹幕并绘制词云

python获取B站视频信息

Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/74260