斗鱼直播录制的逻辑主要涉及 spider.py, stream.py 和 main.py。以下是代码如何获取并录制斗鱼直播流的详细解析:
1. 获取斗鱼直播信息
在 spider.py 中,函数 get_douyu_info_data(url, proxy_addr, cookies) 负责获取斗鱼直播的基本信息:
@trace_error_decorator
async def get_douyu_info_data(url: str, proxy_addr: OptionalStr = None, cookies: OptionalStr = None) -> dict:
headers = {
'User-Agent': 'ios/7.830 (ios 17.0; ; iPhone 15 ...)',
'Referer': 'https://m.douyu.com/...',
'Cookie': 'dy_did=413b835d2ae00270f0c69f6400031601; ...'
}
if cookies:
headers['Cookie'] = cookies
match_rid = re.search('rid=(.*?)(?=&|$)', url)
if match_rid:
rid = match_rid.group(1)
else:
rid = re.search('douyu.com/(.*?)(?=\\?|$)', url).group(1)
html_str = await async_req(url=f'https://m.douyu.com/{rid}', proxy_addr=proxy_addr, headers=headers)
json_str = re.findall('', html_str)[0]
json_data = json.loads(json_str)
rid = json_data['pageProps']['room']['roomInfo']['roomInfo']['rid']
headers['User-Agent'] = 'Mozilla/5.0 (Windows NT 10.0; ...)'
url2 = f'https://www.douyu.com/betard/{rid}'
json_str = await async_req(url=url2, proxy_addr=proxy_addr, headers=headers)
json_data = json.loads(json_str)
result = {
"anchor_name": json_data['room']['nickname'],
"is_live": False
}
if json_data['room']['videoLoop'] == 0 and json_data['room']['show_status'] == 1:
result["title"] = json_data['room']['room_name'].replace(' ', '')
result["is_live"] = True
result["room_id"] = json_data['room']['room_id']
return result
解析
通过访问 https://m.douyu.com/{房间号} 获取基础信息。
解析出 room_id,判断 show_status 是否为 1,表示当前直播是否在线。
返回主播昵称 (anchor_name),直播标题 (title) 和 is_live 状态。
2. 获取斗鱼直播流地址
在 spider.py 中,函数 get_douyu_stream_data(rid, rate, proxy_addr, cookies) 负责获取斗鱼的直播流:
@trace_error_decorator
async def get_douyu_stream_data(rid: str, rate: str = '-1', proxy_addr: OptionalStr = None, cookies: OptionalStr = None) -> dict:
did = '10000000000000000000000000003306'
params_list = await get_token_js(rid, did, proxy_addr=proxy_addr)
headers = {
'User-Agent': 'ios/7.830 (ios 17.0; ...)',
'Referer': 'https://m.douyu.com/...',
'Cookie': 'dy_did=413b835d2ae00270f0c69f6400031601; ...'
}
if cookies:
headers['Cookie'] = cookies
data = {
'v': params_list[0],
'did': params_list[1],
'tt': params_list[2],
'sign': params_list[3],
'ver': '22011191',
'rid': rid,
'rate': rate, # 0蓝光、3超清、2高清、-1默认
}
app_api = f'https://www.douyu.com/lapi/live/getH5Play/{rid}'
json_str = await async_req(url=app_api, proxy_addr=proxy_addr, headers=headers, data=data)
json_data = json.loads(json_str)
return json_data
解析
需要生成 params_list 作为认证信息。
访问 https://www.douyu.com/lapi/live/getH5Play/{rid} 获取直播流信息。
rate 参数决定了视频清晰度:
0:蓝光
3:超清
2:高清
-1:默认
3. 解析直播流 URL
在 stream.py,函数 get_douyu_stream_url(json_data, video_quality, cookies, proxy_addr) 负责最终解析直播流:
@trace_error_decorator
async def get_douyu_stream_url(json_data: dict, video_quality: str, cookies: str, proxy_addr: str) -> dict:
if not json_data["is_live"]:
return json_data
video_quality_options = {
"OD": '0',
"BD": '0',
"UHD": '3',
"HD": '2',
"SD": '1',
"LD": '1'
}
rid = str(json_data["room_id"])
json_data.pop("room_id")
rate = video_quality_options.get(video_quality, '0')
flv_data = await get_douyu_stream_data(rid, rate, cookies=cookies, proxy_addr=proxy_addr)
rtmp_url = flv_data['data'].get('rtmp_url')
rtmp_live = flv_data['data'].get('rtmp_live')
if rtmp_live:
flv_url = f'{rtmp_url}/{rtmp_live}'
json_data |= {'quality': video_quality, 'flv_url': flv_url, 'record_url': flv_url}
return json_data
解析
传入 video_quality 选择清晰度。
通过 get_douyu_stream_data 获取 rtmp_url 和 rtmp_live。
生成最终的 flv_url 用于录制。
4. 录制直播流
在 main.py,函数 start_record(url_data: tuple, count_variable: int = -1) 负责执行录制:
elif record_url.find("https://www.douyu.com/") > -1:
platform = '斗鱼直播'
with semaphore:
json_data = asyncio.run(spider.get_douyu_info_data(
url=record_url, proxy_addr=proxy_address, cookies=douyu_cookie))
port_info = asyncio.run(stream.get_douyu_stream_url(
json_data, video_quality=record_quality, cookies=douyu_cookie, proxy_addr=proxy_address
))
之后,调用 ffmpeg 录制:
ffmpeg_command = [
'ffmpeg', "-y",
"-v", "verbose",
"-rw_timeout", "15000000",
"-loglevel", "error",
"-hide_banner",
"-user_agent", user_agent,
"-protocol_whitelist", "rtmp,crypto,file,http,https,tcp,tls,udp,rtp,httpproxy",
"-thread_queue_size", "1024",
"-analyzeduration", analyzeduration,
"-probesize", probesize,
"-fflags", "+discardcorrupt",
"-re", "-i", real_url,
"-bufsize", bufsize,
"-sn", "-dn",
"-reconnect_delay_max", "60",
"-reconnect_streamed", "-reconnect_at_eof",
"-max_muxing_queue_size", max_muxing_queue_size,
"-correct_ts_overflow", "1",
"-avoid_negative_ts", "1"
]
解析
ffmpeg 读取 flv_url 进行录制。
-re 选项保证实时录制,防止 ffmpeg 过快读取导致流中断。
总结
获取直播间信息 → spider.get_douyu_info_data()
获取直播流 URL → spider.get_douyu_stream_data()
解析最终直播地址 → stream.get_douyu_stream_url()
使用 ffmpeg 录制 → start_record()
这套逻辑确保了斗鱼直播录制的稳定性和高效性。