一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

腳本之家,腳本語(yǔ)言編程技術(shù)及教程分享平臺(tái)!
分類(lèi)導(dǎo)航

Python|VBS|Ruby|Lua|perl|VBA|Golang|PowerShell|Erlang|autoit|Dos|bat|

服務(wù)器之家 - 腳本之家 - Python - 用Python實(shí)現(xiàn)一個(gè)模仿UP主彈幕控制的直播間功能

用Python實(shí)現(xiàn)一個(gè)模仿UP主彈幕控制的直播間功能

2022-03-11 10:21蠻三刀醬 Python

up主通過(guò)代碼實(shí)現(xiàn)了實(shí)時(shí)讀取直播間里的彈幕內(nèi)容,進(jìn)而控制自己的電腦,把彈幕翻譯成指令操控《賽博朋克2077》游戲,這篇文章主要介紹了用Python實(shí)現(xiàn)一個(gè)模仿UP主彈幕控制的直播間功能,需要的朋友可以參考下

靈感來(lái)源

之前在B站看到一個(gè)有意思的視頻:

【B站】【亦】終極云游戲!五千人同開(kāi)一輛車(chē),復(fù)現(xiàn)經(jīng)典群體智慧實(shí)驗(yàn)

用Python實(shí)現(xiàn)一個(gè)模仿UP主彈幕控制的直播間功能

大家可以看看,很有意思。

up主通過(guò)代碼實(shí)現(xiàn)了實(shí)時(shí)讀取直播間里的彈幕內(nèi)容,進(jìn)而控制自己的電腦,把彈幕翻譯成指令操控《賽博朋克2077》游戲。

觀眾也越來(lái)越多,最后甚至還把直接間搞崩了(當(dāng)然,其實(shí)是因?yàn)槟翘霣站全站崩了)。

我十分好奇到底是怎么做到的。

外行看熱鬧,內(nèi)行看門(mén)道,作為半個(gè)內(nèi)行,我們就模仿UP主的想法,自己做一個(gè)。

所以今天我的目標(biāo)就是復(fù)刻一個(gè) 通過(guò)彈幕控制直播間 的代碼,并且最終在自己的直播間開(kāi)播。

先給大家看看最終我的成品小視頻:

【B站】模仿UP主,做一個(gè)彈幕控制的直播間!

看起來(lái)是不是很像樣了。

初版設(shè)計(jì)思路

首先在腦海里規(guī)劃一個(gè)大致的思路,如下圖:

用Python實(shí)現(xiàn)一個(gè)模仿UP主彈幕控制的直播間功能

這個(gè)思路看起來(lái)很簡(jiǎn)單,不過(guò)還是得解釋一下,首先我們要搞清楚,彈幕的內(nèi)容是怎么抓到的。

大部分我們常見(jiàn)的直播平臺(tái),在瀏覽器端,彈幕都是通過(guò)WebSocket來(lái)推送給觀眾的。在手機(jī)平板等客戶端(非Web端),可能會(huì)有一些更加復(fù)雜的TCP進(jìn)行彈幕的推送。

關(guān)于TCP的消息投遞,有個(gè)很好的文章,就是美團(tuán)的這個(gè):美團(tuán)終端消息投遞服務(wù)Pike的演進(jìn)之路

歸根結(jié)底,這些彈幕都是通過(guò)在客戶端和服務(wù)端建立長(zhǎng)鏈接來(lái)實(shí)現(xiàn)的。

所以,我們需要做的就是用代碼作為客戶端,與直播平臺(tái)進(jìn)行長(zhǎng)鏈接。這樣就能拿到彈幕。

我們只是需要實(shí)現(xiàn)整個(gè)彈幕控制的流程,所以彈幕的抓取也不是本文的重點(diǎn),我們來(lái)淘一個(gè)現(xiàn)成的輪子!在Github上一頓找,找到了一個(gè)非常不錯(cuò)的開(kāi)源庫(kù),里面能夠獲取很多直播平臺(tái)的彈幕:

https://github.com/wbt5/real-url

獲取斗魚(yú)&虎牙&嗶哩嗶哩&抖音&快手等 58 個(gè)直播平臺(tái)的真實(shí)流媒體地址(直播源)和彈幕,直播源可在 PotPlayer、flv.js 等播放器中播放。

我們把代碼clone下來(lái),運(yùn)行main函數(shù),隨便輸入一個(gè)Bilibili直播間地址,就能拿到直播間實(shí)時(shí)的彈幕流:

用Python實(shí)現(xiàn)一個(gè)模仿UP主彈幕控制的直播間功能

代碼里把獲取到的一條條彈幕(包括用戶名)直接打印在了控制臺(tái)。

他是如何做到的呢?核心的Python代碼如下(不熟悉Python?不要緊,就當(dāng)做偽代碼,很容易看懂):

wss_url = "wss://broadcastlv.chat.bilibili.com/sub"
heartbeat = b"x00x00x00x1fx00x10x00x01x00x00x00x02x00x00x00x01x5bx6fx62x6ax65x63x74x20" 
                b"x4fx62x6ax65x63x74x5d "
  heartbeatInterval = 60

@staticmethod
async def get_ws_info(url):
    url = "https://api.live.bilibili.com/room/v1/Room/room_init?id=" + url.split("/")[-1]
    reg_datas = []
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as resp:
            room_json = json.loads(await resp.text())
            room_id = room_json["data"]["room_id"]
            data = json.dumps({
                "roomid": room_id,
                "uid": int(1e14 + 2e14 * random.random()),
                "protover": 1
            }, separators=(",", ":")).encode("ascii")
            data = (pack(">i", len(data) + 16) + b"x00x10x00x01" +
                    pack(">i", 7) + pack(">i", 1) + data)
            reg_datas.append(data)

    return Bilibili.wss_url, reg_datas

它連上了Bilibili的直播彈幕WSS地址,也就是WebSocket地址,然后偽裝成客戶端,接受彈幕推送。

OK,做完了第一步,下一步就是用消息隊(duì)列將彈幕發(fā)送出來(lái)。開(kāi)啟單獨(dú)的消費(fèi)者接收彈幕。

為了實(shí)現(xiàn)上盡量簡(jiǎn)單,就不上那些專(zhuān)業(yè)的消息隊(duì)列了,這里用了redis的list作為隊(duì)列,將彈幕內(nèi)容放進(jìn)去。

發(fā)送者核心代碼如下:

# 鏈接Redis
def init_redis():
    r = redis.Redis(host="localhost", port=6379, decode_responses=True)
    return r

# 消息發(fā)送者
async def printer(q, redis):
    while True:
        m = await q.get()
        if m["msg_type"] == "danmaku":
            print(f"{m["name"]}:{m["content"]}")
            list_str = list(m["content"])
            print("彈幕拆分:", list_str)
            for char in list_str:
                if char.lower() in key_list:
                    print("推送隊(duì)列:", char.lower())
                    redis.rpush(list_name, char.lower())

完成了彈幕內(nèi)容的發(fā)送后,需要寫(xiě)一個(gè)消費(fèi)者,消費(fèi)這些彈幕,把里面的指令都提取出來(lái)。

并且,在消費(fèi)者收到彈幕后,如何消費(fèi)呢?我們需要一個(gè)能夠用代碼指令控制電腦的辦法。

咱繼續(xù)本著不造輪子的原則,找到了一個(gè)Python的自動(dòng)化控制庫(kù)PyAutoGUI

PyAutoGUI is a cross-platform GUI automation Python module for human beings. Used to programmatically control the mouse & keyboard.

安裝上這個(gè)庫(kù),在代碼中引入,便可以通過(guò)他的API控制電腦鼠標(biāo)和鍵盤(pán)執(zhí)行對(duì)應(yīng)的操作。簡(jiǎn)直是完美啊!

消費(fèi)者(控制電腦)核心Python代碼如下:

# 鏈接Redis
def init_redis():
    r = redis.Redis(host="localhost", port=6379, decode_responses=True)
    return r

# 消費(fèi)者
def control(key_name):
    print("key_name =", key_name)
    if key_name == None:
        print("本次無(wú)指令發(fā)出")
        return
    key_name = key_name.lower()
    # 控制電腦指令
    if key_name in key_list:
        print("發(fā)出指令", key_name)
        pyautogui.keyDown(key_name)
        time.sleep(press_sec)
        pyautogui.keyUp(key_name)
        print("結(jié)束指令", key_name)

if __name__ == "__main__":
    r = init_redis()
    print("開(kāi)始監(jiān)聽(tīng)彈幕消息, loop_sec =", loop_sec)
    while True:
        key_name = r.lpop(list_name)
        control(key_name)
        time.sleep(loop_sec)

ok,大功告成,我們打開(kāi)彈幕發(fā)送隊(duì)列和消費(fèi)者,這個(gè)不斷循環(huán)消費(fèi)的隊(duì)列就開(kāi)始運(yùn)行了。一旦彈幕中有wsad這種控制游戲常用的按鍵,電腦就會(huì)自己給自己發(fā)出指令。

用Python實(shí)現(xiàn)一個(gè)模仿UP主彈幕控制的直播間功能

初版運(yùn)行中的問(wèn)題

我興沖沖的打開(kāi)自己的B站直播間,開(kāi)始調(diào)試,結(jié)果發(fā)現(xiàn)我還是太天真了。這個(gè)初版代碼暴露了非常多的問(wèn)題。我們一個(gè)個(gè)來(lái)說(shuō)下是什么問(wèn)題,我是如何解決的。

指令不人性化

水友們其實(shí)很喜歡發(fā)送類(lèi)似www dddd這類(lèi)重復(fù)單詞(疊詞),但初版的實(shí)現(xiàn)只支持單個(gè)字幕,水友們發(fā)現(xiàn)不得勁,沒(méi)有作用后,就從直播間走了。

這點(diǎn)很容易解決,把彈幕內(nèi)容拆分成每個(gè)單詞,然后再推送給隊(duì)列。

解決方法:拆解彈幕,把DDD,拆成D,D,D,發(fā)送個(gè)消費(fèi)者。

危險(xiǎn)指令

首先是玩家的指令超出了應(yīng)該有的范圍。

在我把賽博朋克游戲打開(kāi),讓彈幕觀眾控制游戲里的開(kāi)車(chē)時(shí),有個(gè)神秘觀眾進(jìn)了直播間,默默發(fā)了個(gè)“F”,然后。。。

然后游戲里的V(主角名)就從車(chē)?yán)锵聛?lái)了,淦,我是讓你們開(kāi)車(chē)的,不是讓你們下來(lái)和警察斗毆的。。。

解決方法:添加彈幕過(guò)濾器。

# 將彈幕進(jìn)行拆分,只發(fā)送指定的指令給消費(fèi)者
key_list = ("w", "s", "a", "d", "j", "k", "u", "i", "z", "x", "f", "enter", "shift", "backspace")
list_str = list(m["content"])
            print("彈幕拆分:", list_str)
            for char in list_str:
                if char.lower() in key_list:
                    print("推送隊(duì)列:", char.lower())
                    redis.rpush(list_name, char.lower())

上面兩個(gè)問(wèn)題解決后,發(fā)送者就像下面這樣運(yùn)行了:

用Python實(shí)現(xiàn)一個(gè)模仿UP主彈幕控制的直播間功能

彈幕指令堆積

這是個(gè)很大的問(wèn)題,如果處理所有水友發(fā)送的全部彈幕指令,一定會(huì)存在消費(fèi)不過(guò)來(lái)的問(wèn)題。

解決方法:需要固定時(shí)間處理彈幕,其他拋棄。

if __name__ == "__main__":
    r = init_redis()
    print("開(kāi)始監(jiān)聽(tīng)彈幕消息, loop_sec =", loop_sec)
    while True:
        key_name = r.lpop(list_name)
        # 每次只取出一個(gè)指令,然后把list清空,也就是這個(gè)時(shí)間窗口內(nèi)其他彈幕都扔掉!
        r.delete(list_name)
        control(key_name)
        time.sleep(loop_sec)

彈幕從發(fā)出到觀眾看到結(jié)果有延遲

在最開(kāi)始的視頻里,你們也能感受到了,從觀眾的指令發(fā)出,到最終被觀眾看到,大概要經(jīng)歷5秒的延遲。其中,起碼有3秒,都是網(wǎng)絡(luò)直播流的延遲,這一點(diǎn),很難去優(yōu)化。

回爐重造后的版本

經(jīng)過(guò)一系列調(diào)優(yōu)和涉及,我們的版本也算是從V0.1到了V0.2了。猛虎落淚。

下面是重構(gòu)后的結(jié)構(gòu)圖:

用Python實(shí)現(xiàn)一個(gè)模仿UP主彈幕控制的直播間功能

后記

在寫(xiě)完這個(gè)項(xiàng)目后,我在直播間試了很多次,體驗(yàn)已經(jīng)無(wú)限接近UP主當(dāng)時(shí)的視頻了。我開(kāi)播掛在那邊好久,但是,人氣最高的時(shí)候,也只有20幾個(gè)人,寥寥十幾條彈幕,還有很多是我發(fā)的。我還期望著觀眾能夠拉更多人進(jìn)來(lái)一起玩呢,事與愿違啊。

由此可得出結(jié)論,我,先得有粉絲,才能玩得起來(lái)啊,嗚嗚嗚嗚。大家要是不介意,可以關(guān)注下我的B站賬號(hào),也叫:蠻三刀醬。我會(huì)偶爾抽風(fēng)發(fā)點(diǎn)有趣的技術(shù)視頻的。

本文實(shí)現(xiàn)的全部代碼已經(jīng)開(kāi)源在了Github上,大家可以在自己的直播間里試試呀:

https://github.com/qqxx6661/live_comment_control_stream

到此這篇關(guān)于用Python實(shí)現(xiàn)一個(gè)模仿UP主彈幕控制的直播間功能的文章就介紹到這了,更多相關(guān)python彈幕控制的直播間內(nèi)容請(qǐng)搜索服務(wù)器之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持服務(wù)器之家!

原文鏈接:https://www.cnblogs.com/rude3knife/p/15635306.html

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 四虎影院在线免费观看 | 免费超级乱淫视频播放性 | 国产欧美日韩视频在线观看一区二区 | 国产良心大作白丝精厕 | 国产福利不卡视频在免费 | 牛牛色婷婷在线视频播放 | 好大好湿好硬好爽好深免费视频 | 亚洲 日韩 在线 国产 视频 | 经典三级四虎在线观看 | 亚洲久操| 亚洲日本中文字幕天天更新 | 亚洲 综合 自拍 精品 在线 | 免费观看国产视频 | 国产成人久久精品推最新 | 亚洲欧美成人中文在线网站 | 国产精品自在线 | 免费观看一区二区 | 国产精品拍拍拍福利在线观看 | 亚洲国产一区二区三区a毛片 | 非洲黑女人性xxxx | 91麻豆精品国产自产在线观看 | 性德国高清xxxxbbbb | 午夜理论电影在线观看亚洲 | 亚洲H成年动漫在线观看不卡 | 亚洲国产成人超福利久久精品 | 成人午夜视频一区二区国语 | 欧美精品日韩 | 国产在线观看精品 | 狠狠涩 | 欧美二区视频 | 高h巨肉play 高h短篇辣肉各种姿势bl | 久久99亚洲AV无码四区碰碰 | 乳环调教 | 久久三级视频 | 经典三级四虎在线观看 | 男人j放进女人的p免费看视频 | 91视频破解版 | 国产成人高清视频 | 深夜福利在线播放 | 9热在线精品视频观看 | 2019中文字幕在线视频 |