斗鱼直播源解析
前言
我现在没时间玩游戏,偶尔无聊会在斗鱼上看看诸如PDD和周淑怡这种带喜剧效果的主播玩,可是每次都要登录才能看超清或者蓝光画质,这让已经懒习惯的我很是头疼,输入来输入去就罢了,各种广告、礼物特效飞来飞去简直不要太烦,于是乎想着抓一抓直播源用别的播放器来看算了,但抓包过后我发现事情远没有想象中那么简单……
去网上搜了一下,发现斗鱼和别的直播平台与众不同,它的直播源貌似比较“宝贝”,各种加密、各种保护!那怎么办呢?动手搞呗!
巨人
自己动手搞是不可能的,这辈子是不可能的,在我坚定决心自己分析的时候,总有那么一些伟大的人在向我喊着:“少年,我看你根骨奇佳,这份代码就交给你了。”
没错,我在搜索相关资料的时候居然发现了一份斗鱼直播源获取的源码,那还想什么?拿来呗。
站在巨人的肩膀上看风景,那真可谓是一览众山小呀!话虽如此,但偷懒这种恶习还是不能让它根深蒂固的,我还是决定分析完他的代码再找个时间自己抓包研究研究。(源码作者是wbt5,代码开源在github上。)
分析
从其源码上看,获取斗鱼的直播源倒也没有太复杂,总结起来就是以form-data的形式向https://m.douyu.com/api/room/ratestream发送POST请求,如果成功,就会返回带有短效直播源地址的Json,将短效直播源地址修改一下就能够获得一个长效的直播源地址。
而form-data的结构中,唯一比较复杂的一点在于sign值的获取。整个结构如下表:
form-data属性 值 备注
v 2501+tradetime tradetime为当天日期,例如:20191031
did 10000000000000000000000000001501 固定值
tt timestamp 10位时间戳,例如:1572507694
sign sign 32位加密字符串
ver 219032101 固定值
rid roomid 实际直播房间ID
rate -1 固定值
具体代码如下,具体分析看我添加的注释,方便新手快速看懂。
tradetime和timestamp获取
def get_tt():
tt1 = str(int(time.time())) #10位时间戳
tt2 = str(int((time.time() * 1000))) #13位时间戳
today = time.strftime('%Y%m%d', time.localtime()) #当天日期
return tt1, tt2, today
Python 复制
roomid和sign获取
def get_homejs(rid):
room_url = 'https://m.douyu.com/' + rid
response = requests.get(url=room_url)
pattern_real_rid = r'"rid":(\d{1,7})'
real_rid = re.findall(pattern_real_rid, response.text, re.I)[0] #获取roomid(有一些主播的房间ID是viprid,也就是表面上的rid,例如周淑怡的22222,实际上则是290935)
if real_rid != rid:
room_url = 'https://m.douyu.com/' + real_rid
response = requests.get(url=room_url)
homejs = ''
pattern = r'(function ub9.*)[\s\S](var.*)'
result = re.findall(pattern, response.text, re.I)
str1 = re.sub(r'eval.*;}', 'strc;}', result[0][0])
homejs = str1 + result[0][1] #获得第一段JS代码
return homejs, real_riddef get_sign(rid, post_v, tt, ub9):
docjs = execjs.compile(ub9) #执行第一段JS代码
res2 = docjs.call('ub98484234') #调用JS代码里的函数“ub98484234”
str3 = re.sub(r'\(function[\s\S]*toString\(\)', '\'', res2)
md5rb = hashlib.md5((rid + '10000000000000000000000000001501' + tt + '2501' +
post_v).encode('utf-8')).hexdigest()
str4 = 'function get_sign(){var rb=\'' + md5rb + str3
str5 = re.sub(r'return rt;}[\s\S]*','return re;};', str4)
str6 = re.sub(r'"v=.*&sign="\+', '', str5) #获得第二段JS代码
docjs1 = execjs.compile(str6) #执行第二段JS代码
sign = docjs1.call(
'get_sign', rid, '10000000000000000000000000001501', tt) #调用JS里的函数“get_sign”以获取sign值
return sign
Python 复制
获取和修改直播源地址
def get_sign_url(post_v, rid, tt, ub9):
sign = get_sign(rid, post_v, tt, ub9)
request_url = 'https://m.douyu.com/api/room/ratestream'
post_data = {
'v': '2501' + post_v,
'did': '10000000000000000000000000001501',
'tt': tt,
'sign': sign,
'ver': '219032101',
'rid': rid,
'rate': '-1'
}
header = {
'Content-Type': 'application/x-www-form-urlencoded',
'User-Agent': 'Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Mobile Safari/537.36'
}
response = requests.post(url=request_url, headers=header, data=post_data).json()
Python 复制
通过get_sign_url函数获得Json后可以从中提取到短效直播源地址。
举个例子,下方是提取的短效直播源地址,提取里边的290935rl8pFB4Chu。
http://hls1a.douyucdn.cn/live/290935rl8pFB4Chu_2000/playlist.m3u8?wsSecret=8e85c3c47dcfd12c0f3f626b7e9dc06e\u0026wsTime=1572509708\u0026token=h5-douyu-0-290935-a9b3efee00dd21938f948106b9d7c0df\u0026did=10000000000000000000000000001501\u0026origin=all\u0026vhost=play2
拼接成http://tx2play1.douyucdn.cn/live/290935rl8pFB4Chu.flv?uuid=即可。
后话
分析完这几段代码其实我还有些疑问,比如提交请求的API是怎么找到的?还有到那两段关键的JS代码是怎么找到的?这些都需要我抽空抓包去自己研究,学习本就应该刨根问底、追本溯源
最后编辑:2022 年 04 月 29 日 15:15
本文链接:https://blog.zlrm.net/index.php/23.html(转载时请注明出处及链接! )
作品采用: 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 许可协议授权。