python爬虫----简单的抓取斗鱼弹幕
来源:互联网 发布:大数据目前发展情况 编辑:程序博客网 时间:2024/05/01 05:47
近几年来直播越来越火,看直播也成为了人们生活的娱乐项目
个人也是比较喜欢看直播,看着主播的搞笑的操作和弹幕不时会开怀大笑。
于是就想能不能把弹幕抓取下来,带着这个问题我就点开了一个直播间。按照以前学过的方法好像根本没有办法弄到弹幕那一块,
于是赶紧去网上查,发现网上有不少人已经做了。呃......怎么说,大概了解了获取弹幕的原理,就是通过socket向斗鱼弹幕服务器发送请求,
然后服务器会返回数据给你,但是他们的具体操作不是太明白。没办法只好继续搜索,终于看到了一个知乎用户的专栏里的一篇文章,
@Ehco的 从零开始写Python爬虫 --- 爬虫应用: 利用斗鱼Api抓取弹幕 地址:https://zhuanlan.zhihu.com/p/28164017,
因为斗鱼现在已经开放了弹幕服务器接入协议,我也看了其他人也提到了这个,但具体怎么用这个协议还是不明白。
通过读了Ehco他的文章后才一点点的弄清楚。
因为之前完全不知道怎么弄,所以代码写的和原作者十分类似。
但我在注释中写了一些自己的理解,如果觉得不清楚可以去看原作者的文章。
也十分感谢原作者分享了这么好的文章。
好吧,下面就来说说我的理解
首先是斗鱼协议
《斗鱼弹幕服务器第三方接入协议v1.4.1》:
http://dev-bbs.douyutv.com/forum.php?mod=viewthread&tid=115&extra=page%3D1
《斗鱼第三方开放平台API文档v2.0》:
http://dev-bbs.douyutv.com/forum.php?mod=viewthread&tid=108&extra=page%3D1
这里我们只需要看第一个就行了
然后再看协议的内容
首先是协议头,这个最重要了,每个请求前面都要带这个
这部分的代码:
def send_request_msg(msgstr): msg = msgstr.encode('utf-8')#协议规定所有协议内容均为 UTF-8 编码 data_lenth = len(msg) + 8 #data_lenth表示整个协议头的长度(消息长度),包括数据部分和头部,len(msg)就是数据部分,8就是头部的长度 code = 689 #根据协议消息类型字段用689 msghead = int.to_bytes(data_lenth,4,'little') + int.to_bytes(data_lenth,4,'little') + int.to_bytes(code,4,'little') #msghead是按照斗鱼第三方协议构造的协议头 #前2段表示的是消息长度,最后一个是消息类型 #这里还有个值得注意的一点,发送给服务器的类型和服务器返回的类型都是bytes,因此要把数据信息通过int.to_bytes()变成bytes client.send(msghead)#发送协议头 client.send(msg)#发送消息请求
获取弹幕的步骤是这样的:
先要向服务器发送登录请求消息,再发送入组消息用于加入房间,
在获取弹幕的过程中还要发送心跳消息来维持和服务器的连接。
获取弹幕的代码:
def get_danmu(roomid): denglu_msg = 'type@=loginreq/roomid@={}/\0'.format(roomid)#登录请求消息,最后面的'\0',是协议规定在数据部分结尾必须是'\0' send_request_msg(denglu_msg) join_room_msg = 'type@=joingroup/rid@={}/gid@=-9999/\0'.format(roomid)#加入房间分组消息 send_request_msg(join_room_msg) while True: data = client.recv(1024) #这个data就是服务器向客户端发送的消息 #具体的信息可以看斗鱼弹幕第三方接入协议 danmu_username = re.findall(user_id,data) dammu_content = re.findall(danmu,data) #print(data) if not data: break else: for i in range(0,len(danmu_username)): try: print('[{}]:{}'.format(danmu_username[i].decode('utf-8'),dammu_content[i].decode('utf-8'))) #返回的数据是bytes型,所以要用decode方法来解码 except: continuedef keeplive(): #维持与后台的心跳 #关于心跳消息,协议中有详细的解释 while True: live_msg = 'type@=keeplive/tick@=' + str(int(time.time())) + '/\0' send_request_msg(live_msg) time.sleep(15)
主体部分大概就是这么多了,接下来怎么使程序运作起来的问题了。
这其中涉及到了一些知识,主要是那几个模块的使用,还有因为发送给服务器信息和服务器返回的信息都是bytes,
因此还有一些python关于bytes类型的资料
我把我在查资料时觉得不错的资料列一下吧
socket模块的介绍:http://blog.csdn.net/rebelqsp/article/details/22109925
python3 bytes与str的区别:http://www.ituring.com.cn/article/1116
关于int.to_bytes函数的官方文档:https://translate.google.com/translate?depth=1&hl=zh-CN&prev=search&rurl=translate.google.com.hk&sl=en&sp=nmt4&u=https://docs.python.org/3/library/stdtypes.html#int.to_bytes
signal模块的介绍:http://blog.sina.com.cn/s/blog_c2839d2a0102x3j1.html
还有就是多进程的模块,也就是multiprocessing模块,网上都写的差不多,大家可以自己去搜搜。
最后一点很关键的一点,在程序写完后让它运行,发现在python自带的IDLE中没反应,就好像是好几个函数没用一样。
后面才发现要找到你写的代码的那个文件,也就是带.py的文件。点开它,弹幕就会出来了,是在windos下的cmd里才会显示出来。
经过测试
显示出的弹幕,在弹幕量大的时候好像显示得不完全,有些用户的弹幕获取不到?(不知道是不是我看错了没有),不过一般的弹幕量还是可以获取到的。
import reimport socketimport signalimport multiprocessingimport timeclient = socket.socket(socket.AF_INET,socket.SOCK_STREAM)port = 8602 # 端口8601、8602、12601、12602这几个端口号都是,但有时候有号些获取不到弹幕的信息,每个都试下总有一个可以host = socket.gethostbyname('openbarrage.douyutv.com')client.connect((host,port))danmu = re.compile(b'txt@=(.+?)/')user_id = re.compile(b'nn@=(.+?)/')def send_request_msg(msgstr): msg = msgstr.encode('utf-8')#协议规定所有协议内容均为 UTF-8 编码 data_lenth = len(msg) + 8 #data_lenth表示整个协议头的长度(消息长度),包括数据部分和头部,len(msg)就是数据部分,8就是头部的长度 code = 689 #根据协议消息类型字段用689 msghead = int.to_bytes(data_lenth,4,'little') + int.to_bytes(data_lenth,4,'little') + int.to_bytes(code,4,'little') #msghead是按照斗鱼第三方协议构造的协议头 #前2段表示的是消息长度,最后一个是消息类型 #这里还有个值得注意的一点,发送给服务器的类型和服务器返回的类型都是bytes,因此要把数据信息通过int.to_bytes()变成bytes client.send(msghead)#发送协议头 client.send(msg)#发送消息请求def get_danmu(roomid): denglu_msg = 'type@=loginreq/roomid@={}/\0'.format(roomid)#登录请求消息,最后面的'\0',是协议规定在数据部分结尾必须是'\0' send_request_msg(denglu_msg) join_room_msg = 'type@=joingroup/rid@={}/gid@=-9999/\0'.format(roomid)#加入房间分组消息 send_request_msg(join_room_msg) while True: data = client.recv(1024) #这个data就是服务器向客户端发送的消息 #具体的信息可以看斗鱼弹幕第三方接入协议 danmu_username = re.findall(user_id,data) dammu_content = re.findall(danmu,data) #print(data) if not data: break else: for i in range(0,len(danmu_username)): try: print('[{}]:{}'.format(danmu_username[i].decode('utf-8'),dammu_content[i].decode('utf-8'))) #返回的数据是bytes型,所以要用decode方法来解码 except: continuedef keeplive(): #维持与后台的心跳 #关于心跳消息,协议中有详细的解释 while True: live_msg = 'type@=keeplive/tick@=' + str(int(time.time())) + '/\0' send_request_msg(live_msg) time.sleep(15)def logout(): out_msg = 'type@=logout/' send_request_msg(out_msg) print('已退出服务器!')def signal_handler(signal,frame): #捕捉ctrl + c的信号,即signal.SIGINT p1.terminate()#结束进程 p2.terminate()#结束进程 logout()if __name__ == '__main__': roomid = 74751#房间号,主播开播才能获取到信息 signal.signal(signal.SIGINT,signal_handler) p1 = multiprocessing.Process(target = get_danmu,args = (roomid,)) p2 = multiprocessing.Process(target = keeplive) p1.start() p2.start()
写这么个东西没我想的那么容易,也用了不少的时间。不过也还是弄出来了,
可能写的也不是很好吧,但每次写一个新东西也是一次新的挑战,
也在其中学到了不少的东西。可能我的理解也表达不是那么清楚,可能也有一些错误,如果有发现错误的地方欢迎各位指正- python爬虫----简单的抓取斗鱼弹幕
- 用python抓取斗鱼网的弹幕
- 抓取斗鱼直播弹幕
- 简单的python爬虫抓取图片实例
- 原生js写的斗鱼弹幕
- 模仿斗鱼弹幕
- Python爬虫:斗鱼TV
- Android 获取斗鱼弹幕
- Python 实现简单的爬虫功能: 图片的抓取
- 视频直播应用,且配有弹幕显示,内容均从斗鱼抓取
- Python实现抓取页面上链接的简单爬虫分享
- 抓取网页所有url的简单Python爬虫源码
- Python实现抓取页面上链接的简单爬虫分
- 获取斗鱼直播间的弹幕信息
- Python抓取熊猫TV弹幕
- Android弹幕功能实现,模仿斗鱼直播的弹幕效果
- Android弹幕功能实现,模仿斗鱼直播的弹幕效果
- Android弹幕功能实现,模仿斗鱼直播的弹幕效果
- (14)问卷调查:两种方式className、div样式属性值改变、单选按钮性格测试
- git clone 遇到"unable to access '……':error setting certificate verify locations"问题
- Android开发--与后台通信(一)--API数据获取
- Js 执行上下文
- Java对象的序列化与反序列化那点事
- python爬虫----简单的抓取斗鱼弹幕
- Android View
- leetcode--Recover Binary Search Tree
- 【unity 5学习记录】 可编辑地形 网格 原理讲解 17.8.8
- CODE大全告诉你java是否开始没落了
- GAN公式原理推到
- Spring(六)SSM(Spring3+Struts2+MyBatis+JDK1.7)
- js事件实现通过键盘移动图片
- Nginx配置参数详解