斗鱼直播源解析

前言

  博主现在没时间玩游戏,偶尔无聊会在斗鱼上看看诸如PDD和周淑怡这种带喜剧效果的主播玩,可是每次都要登录才能看超清或者蓝光画质,这让已经懒习惯的博主很是头疼,输入来输入去就罢了,各种广告、礼物特效飞来飞去简直不要太烦,于是乎想着抓一抓直播源用别的播放器来看算了,但抓包过后博主发现事情远没有想象中那么简单……

  去网上搜了一下,发现斗鱼和别的直播平台与众不同,它的直播源貌似比较“宝贝”,各种加密、各种保护!那怎么办呢?动手搞呗!

巨人

  自己动手搞是不可能的,这辈子是不可能的,在博主坚定决心自己分析的时候,总有那么一些伟大的人在向博主喊着:“少年,我看你根骨奇佳,这份代码就交给你了。”

  没错,博主在搜索相关资料的时候居然发现了一份斗鱼直播源获取的源码,那还想什么?拿来呗。

  站在巨人的肩膀上看风景,那真可谓是一览众山小呀!话虽如此,但偷懒这种恶习还是不能让它根深蒂固的,博主还是决定分析完他的代码再找个时间自己抓包研究研究。(源码作者是wbt5,代码开源在github上。)

分析

  从其源码上看,获取斗鱼的直播源倒也没有太复杂,总结起来就是以form-data的形式向https://m.douyu.com/api/room/ratestream发送POST请求,如果成功,就会返回带有短效直播源地址的Json,将短效直播源地址修改一下就能够获得一个长效的直播源地址。

  而form-data的结构中,唯一比较复杂的一点在于sign值的获取。整个结构如下表:

form-data属性备注
v2501+tradetimetradetime为当天日期,例如:20191031
did10000000000000000000000000001501固定值
tttimestamp10位时间戳,例如:1572507694
signsign32位加密字符串
ver219032101固定值
ridroomid实际直播房间ID
rate-1固定值

  具体代码如下,具体分析看博主添加的注释,方便新手快速看懂。

tradetime和timestamp获取

1
2
3
4
5
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

roomid和sign获取

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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_rid


def 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

获取和修改直播源地址

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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()

  通过get_sign_url函数获得Json后可以从中提取到短效直播源地址。

  举个例子,下方是提取的短效直播源地址,提取里边的290935rl8pFB4Chu

1
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代码是怎么找到的?这些都需要博主抽空抓包去自己研究,学习本就应该刨根问底、追本溯源。

-------------本文结束❤感谢阅读-------------

本文标题:斗鱼直播源解析

文章作者:三水非冰

发布时间:2019年10月31日

最后更新:2019年10月31日

原始链接:https://www.sanshuifeibing.cn/posts/8146e2c4.html

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

如果觉得我的文章对您有用,请随意打赏,您的支持将鼓励我继续创作。