從零開始寫Python爬蟲 --- 爬蟲應用: 利用鬥魚Api抓取彈幕
七月末的南京簡直開啟了「微波爐」模式,白天要學車的我,晚上自然選擇宅在家看直播,看著狗賊叔叔滿屏幕的彈幕,我就想著能不能把彈幕爬下來呢?說干就干
結果的展示:
這裡只抓到彈幕內容和發送用戶
並輸出在終端上,有興趣的小夥伴可以在這個基礎上接著開發,搜集彈幕做做數據分析也是很ok的啊!下面是展示圖:
資料的搜集
面向Google編程的我,第一件事當然是鍵入關鍵詞:「Python 彈幕」
吃驚的是,網上已經有了炒雞完善的彈幕第三方庫:「DanMU」
使用起來也是炒雞簡單,十幾行代碼就能輕鬆獲取直播間的彈幕了,
有興趣的同學可以去搜索看看。
本著練手和不折騰會死的態度,我還是想嘗試自己寫一個版本出來,
然後就找到了 鬥魚居然開放了Api,
這樣的話,只要稍微處理一下,就能愉快的獲取想要的信息了。
鬥魚Api介面文檔和接入協議
- 《鬥魚彈幕伺服器第三方接入協議v1.4.1》: http://dev-bbs.douyutv.com/forum.php?mod=viewthread&tid=115&extra=page%3D1
- 《鬥魚第三方開放平台API文檔v2.1》: http://dev-bbs.douyutv.com/forum.php?mod=viewthread&tid=113&extra=page%3D1
仔細觀察文檔之後,我發現只要自己實現一下協議頭,
就能接入彈幕伺服器了,
接著構造彈幕請求,
就能實時的獲取每一條彈幕了。
請求頭的構造
先看文檔的要求:
簡而言之呢:
請求一共分為三個部分:長度,頭部,數據部
分別按照文檔的要求構造就行,需要注意的是,獲取和返回的類型是都是 Bytes代碼:
def send_req_msg(msgstr):n 構造並發送符合鬥魚api的請求n msg = msgstr.encode(utf8)n data_length = len(msg) + 8n code = 689n # 構造協議頭n msgHead = int.to_bytes(data_length, 4, little) n + int.to_bytes(data_length, 4, little) + n int.to_bytes(code, 4, little)n client.send(msgHead)n sent = 0n while sent < len(msg):n tn = client.send(msg[sent:])n sent = sent + tnn
獲取彈幕
這裡的部分也是按照文檔要求寫就成
首先 發送登錄請求
接著 每隔固定時間發送【心跳請求】防止斷線def DM_start(roomid):n # 構造登錄授權請求n msg = type@=loginreq/roomid@={}/0.format(roomid)n send_req_msg(msg)n # 構造獲取彈幕消息請求n msg_more = type@=joingroup/rid@={}/gid@=-9999/0.format(roomid)n send_req_msg(msg_more)nn while True:n # 服務端返回的數據n data = client.recv(1024)n # 通過re模塊找發送彈幕的用戶名和內容n danmu_username = username_re.findall(data)n danmu_content = danmu_re.findall(data)n if not data:n breakn else:n for i in range(0, len(danmu_content)):n try:n # 輸出信息n print([{}]:{}.format(danmu_username[0].decode(n utf8), danmu_content[0].decode(encoding=utf8)))n except:n continuenndef keeplive():n n 保持心跳,15秒心跳請求一次n n while True:n msg = type@=keeplive/tick@= + str(int(time.time())) + /0n send_req_msg(msg)n print(發送心跳包)n time.sleep(15)n
tricky 的部分
上面的內容,說起來都不是很難,
但是想要完整的實現需求,這裡需要的知識還是比較多的:- socket相關
- 正則表達式相關
- signal相關
- 多線程、多進程相關
比如我想要實現捕捉「ctrl+c」的信號,
好在我們退出程序的時候,能夠正確的處理這時候就要用到signal相關的知識說起來,在今天之前,我完全不知道還可以這樣用。總之越是學到後面,
越是會覺得自己的知識儲備不足,
Python 作為一門十分強大和容易上手的語言,能夠幫助我們迅速的實現需求,但是不要認為他單單只能寫爬蟲哦,完整的代碼
有詳細的注釋哦:
n利用鬥魚彈幕 apin嘗試抓取鬥魚tv指定房間的彈幕nnnimport multiprocessingnimport socketnimport timenimport renimport signalnn# 構造socket連接,和鬥魚api伺服器相連接nclient = socket.socket(socket.AF_INET, socket.SOCK_STREAM)nhost = socket.gethostbyname("openbarrage.douyutv.com")nport = 8601nclient.connect((host, port))nn# 彈幕查詢正則表達式ndanmu_re = re.compile(btxt@=(.+?)/cid@)nusername_re = re.compile(bnn@=(.+?)/txt@)nnndef send_req_msg(msgstr):n 構造並發送符合鬥魚api的請求nn msg = msgstr.encode(utf-8)n data_length = len(msg) + 8n code = 689n # 構造協議頭n msgHead = int.to_bytes(data_length, 4, little) n + int.to_bytes(data_length, 4, little) + n int.to_bytes(code, 4, little)n client.send(msgHead)n sent = 0n while sent < len(msg):n tn = client.send(msg[sent:])n sent = sent + tnnnndef DM_start(roomid):n # 構造登錄授權請求n msg = type@=loginreq/roomid@={}/0.format(roomid)n send_req_msg(msg)n # 構造獲取彈幕消息請求n msg_more = type@=joingroup/rid@={}/gid@=-9999/0.format(roomid)n send_req_msg(msg_more)nn while True:n # 服務端返回的數據n data = client.recv(1024)n # 通過re模塊找發送彈幕的用戶名和內容n danmu_username = username_re.findall(data)n danmu_content = danmu_re.findall(data)n if not data:n breakn else:n for i in range(0, len(danmu_content)):n try:n # 輸出信息n print([{}]:{}.format(danmu_username[0].decode(n utf8), danmu_content[0].decode(encoding=utf8)))n except:n continuennndef keeplive():n n 保持心跳,15秒心跳請求一次n n while True:n msg = type@=keeplive/tick@= + str(int(time.time())) + /0n send_req_msg(msg)n print(發送心跳包)n time.sleep(15)nnndef logout():n n 與鬥魚伺服器斷開連接n 關閉線程n n msg = type@=logout/n send_req_msg(msg)n print(已經退出伺服器)nnndef signal_handler(signal, frame):n n 捕捉 ctrl+c的信號 即 signal.SIGINTn 觸發hander:n 登出鬥魚伺服器n 關閉進程n n p1.terminate()n p2.terminate()n logout()n print(Bye)nnnif __name__ == __main__:n #room_id = input(請輸入房間ID: )nn # 狗賊的房間號n room_id = 208114n # 開啟signal捕捉n signal.signal(signal.SIGINT, signal_handler)nn # 開啟彈幕和心跳進程n p1 = multiprocessing.Process(target=DM_start, args=(room_id,))n p2 = multiprocessing.Process(target=keeplive)n p1.start()n p2.start()n
每天的學習記錄都會 同步更新到:
微信公眾號: findyourownway知乎專欄:https://zhuanlan.zhihu.com/Ehco-pythonblog : www.ehcoblog.mlGithub: https://github.com/Ehco1996/Python-crawler
推薦閱讀:
※怎麼看待德雲色被鬥魚鎖人氣這件事?
※在鬥魚tv上班是一種什麼體驗?
※第八章:幾點建議 教你如何增加直播間人氣
※如何評價鬥魚皇室戰爭主播洪國健(嚴肅的kenny)?
※如何看待知名遊戲主播指法芬芳張大仙跳槽事件?