文章最下面有工具鏈接!
前言
總所周知bilibili是沒有辦法直接查看彈幕的發送者的,這使得當我們看到一些nt彈幕的時候雖然生氣,卻無可奈何,但是B站是可以屏蔽某個用戶發送的彈幕的,這說明數據接口裏肯定有用戶信息,由於最近在學爬蟲,所以我想先找找彈幕接口,分析下里面的數據。
找接口
找接口當然是隨便打開一個視頻然後F12啦,可是當我找了兩圈後我傻眼了,沒找到啊。。得,不能把時間浪費在這種事情上,果斷打開百度,不出所料,找到了如下的兩個接口,都是XML格式網頁
https://comment.bilibili.com/+cid
https://api.bilibili.com/x/v1/dm/list.so?oid=+cid
這裏面的cid是一種每個視頻獨有的數字,也就是每一P都有一個cid,查找cid可以打開網頁然後F12,再ctrl+f搜索cid,一般八九位數的就是cid了。
這裏我找到了一個接口,可以通過aid找到cid
https://www.bilibili.com/widget/getPageList?aid=+aid
分析數據
彈幕數據是獲取到了,那麼我們就要從這一堆數據中分析他們的用途了
這裏大概能得到兩個信息,其中第6個數據爲時間戳,第8個數據爲用戶uid的某種加密方式。經查詢得到這是用戶uid經過crc32校驗得到的結果轉爲16進制數,所以只能通過uid得到對於的校驗碼,無法反推。。似乎只能通過彩虹表的方式查找數據了?那麼這串8位16進制的數字在數據庫中要用什麼方式保存呢?
選擇似乎有varchar和bigint,由於B站有差不多6億個用戶,在6億個數據中查找想要的字符串那速度必然很慢(但有人經測試得到varchar型數據和bigint型數據查找速度其實差的不多?)
就在我決定用bigint儲存數據時,我突然想到,8位16進制那就是2的32次方,int型的儲存上限時2的31次方,如果用無符號的方式保存正好是2的32次方,也就是能儲存到0xffffffff這麼大的數據,正好滿足要求。於是果斷換成無符號int,與之對應的id也爲無符號int,並將crc32b編碼過後的數據作爲主鍵,製成彩虹表存入我的服務器內。
(粗略的算了一下,6億數據就是需要27G左右的空間…而我的服務器一共才40G的大小…)
做成網頁供大家使用
接下來的操作似乎就水到渠成了,寫了個python腳本,該python腳本接受2個參數,視頻cid和想要搜索的彈幕關鍵字,返回用戶發送的彈幕,用戶的crc32b編碼,時間戳。然後用php的exec函數執行python代碼,並通過搜索數據庫找出用戶的uid,通過php返回json格式數據給前端。
python代碼(寫的很爛)
import requests
from bs4 import BeautifulSoup
import re
import io
import sys
sys.stdout = io.TextIOWrapper(sys.stdout.buffer,encoding='utf-8')
req = requests.get('https://comment.bilibili.com/'+sys.argv[1]+'.xml')
req.encoding = req.apparent_encoding
soup = BeautifulSoup(req.text, 'html.parser').find_all(name='d')
result = ""
for i in soup:
s = re.sub('<(.*?)>', '', str(i))
index = 0
if(len(sys.argv[2])>0):
index = s.find(str(sys.argv[2]))
if(index!=-1):
result+=str(i).split(",")[6]+","+s+","+str(i).split(",")[4]+","
print(result)
效果展示
前端代碼就是隨便寫的~至少功能實現了嘛
這裏說一下爲什麼是NULL,因爲我的服務器還在可憐巴巴的往數據庫內寫入彩虹表數據。。預計需要4天~
今天加了個暴力破解的功能,避免了查詢結果爲NULL,但是相對的查詢速度會非常慢。