拆解 DouyinLiveRecorder:跨 40+ 平台直播间 ID 提取的三层解析思路
【免费下载链接】DouyinLiveRecorder可循环值守和多人录制的直播录制软件,支持抖音、TikTok、Youtube、快手、虎牙、斗鱼、B站、小红书、pandatv、sooplive、flextv、popkontv、twitcasting、winktv、百度、微博、酷狗、17Live、Twitch、Acfun、CHZZK、shopee等40+平台直播录制项目地址: https://gitcode.com/gh_mirrors/do/DouyinLiveRecorder
群聊里丢来一条直播间短链,点开是网页,想把它录下来,却拿不到真正能播的流地址。DouyinLiveRecorder 是一个跨平台的直播录制工具,覆盖抖音、快手、B站、Twitch、TikTok 等 40 多个站点,它要解决的第一件事就是把直播间 ID 提取出来,再一路走到流地址。
🧩 这个项目到底在解决什么
它是一款基于 FFmpeg 的循环值守式直播录制软件:把一批直播间地址填进配置文件,程序按间隔反复检测,谁开播了就自动开录,支持按清晰度选流、分片保存、开播状态推送。对普通用户来说门槛是"填链接";对开发来说有意思的是它背后那套跨平台的直播间 ID 提取方案——从拿到一个可用标识,到定位流地址,再到长期挂机的稳定性。
🧵 为什么"拿到一个直播间"比想象中麻烦
直播间 ID 可以理解为每个平台的房间门牌号:拿到它,才能查到房间里挂着的流地址。麻烦在于,门牌号的"挂牌方式"每个平台都不一样。
三个矛盾几乎绕不开:
- 链接形态不统一:短链、长链、带参链接并存。
live.douyin.com/一串数字和v.douyin.com/xxx指向同一个房间,后者的数字还得靠重定向才能看出来。 - 页面结构频繁变动:不少平台把房间信息内嵌在页面的一坨 JSON 里,字段位置说挪就挪,解析规则隔段时间就得修。
- 安全策略各异:有的平台接口裸奔可直接访问,有的要签名、有的要 Cookie,有的还会对高频请求直接封 IP。
所以"提取直播间 ID"从来不是一个问题,而是一组需要分级处理的问题。
🪜 分层解析管线:先粗筛,再精解,最后兜底
核心思路是不走单通道,而是把直播间 ID 提取做成一条逐层递进的管线:能用便宜方式解决,就不动用昂贵方式。
直播间 URL │ ├─ 第1层 URL 直解 正则能切出门牌号 ────────┐ │ │ ├─ 第2层 页面内嵌 JSON 抓页面找初始状态数据 ─────┤ │ │ └─ 第3层 开放接口 带签名调官方 API ─────────┤ ▼ 标准房间数据结构(主播/状态/流地址)三层各自的成本和能力边界完全不同:
def extract_room(url: str) -> dict: # 第 1 层:URL 直解,成本几乎为零 m = re.search(r'live\.douyin\.com/(\d+)', url) if m: return room_from_web_rid(m.group(1)) # 第 2 层:抓页面,在初始状态数据里找房间字段 page = fetch(url) state = re.search(r'window\.__INITIAL_STATE__=(\{.*?\});', page) if state: return pick_room_field(json.loads(state.group(1))) # 第 3 层:页面也拿不到,降级到开放接口 return query_room_api(url) # 需要 Cookie / 签名,按平台定制每层都是独立分支,某一层失效不会拖累其他层;能走第一层就不发第二个请求。核心爬虫模块 里大量平台函数都是这种"页面优先、接口兜底"的两段式写法。
🎮 抖音深水区:短链重定向到 X-Bogus 的一路闯关
抖音的解析链路是全项目里最长的一条,可以拆成四关。
第一关是短链重定向。v.douyin.com的短链跟到底后会落在带reflow/的路由上,room_id和sec_user_id分别藏在路径尾段和查询串里:
resp = await client.get(share_url, follow_redirects=True) final = str(resp.url) room_id = final.split('?')[0].rsplit('/', 1)[-1] sec_uid = re.search(r'sec_user_id=([\w\-_]+)', final).group(1)第二关是签名。直接调webcast.amemv.com的接口会被风控挡回来,因为请求必须带X-Bogus参数。这个算法是抖音前端混淆过的 JS,项目把它逆向出来放在本地文件里,用 Node 执行、Python 侧通过execjs把 query 串和 UA 传进去换回签名字符串。
xb = execjs.compile(open('javascript/x-bogus.js').read()).call('sign', query, ua) api_url = f"{base}?{urlencode(params)}&X-Bogus={xb}"第三关是调接口。room_id + sec_user_id拼进参数后,从响应的data.room.owner.web_rid里取出真正能用的直播间 ID。整个抖音链路就是"重定向 → 正则 → 签名 → 接口"四步串联,具体实现集中在 直播间信息模块。每一关都可能失效,所以代码里都留了降级出口:重定向拿不到就回头解析页面,接口拿不到就换 app 通道再试一次。
📈 生产级稳定性:缓存、重试与请求治理
直播间检测是长时间挂机的活儿,稳定性靠的不是单点技巧,而是几套机制叠在一起:
循环间隔加随机抖动:每次检测完不是等固定的 300 秒,而是随机加减压秒数,让请求节奏"不像机器",同时天然起到了请求间隔控制的作用。
动态并发线程数:用一个 10 长度的滑动窗口统计错误率,错误偏高就把同一时间访问网络的线程数减 1,错误率回落再慢慢加回来:
if error_rate > 5: max_request -= 1 elif error_rate < 2.5 and max_request < preset: max_request += 1错误惩罚:瞬时错误数超过 20,本轮循环直接追加 60 秒延迟,给对端喘息的时间。
UA 与指纹管理:不同平台用不同的 UA、Referer 和 Cookie 组合,海外平台还能按平台白名单单独挂代理,而不是全局一刀切。
重试策略则体现在"解析失败自动换通道"上:比如抖音页面解析炸了会自动切到 app 接口通道,TikTok 页面读不到状态就按固定节奏重新抓。失败计数会写进上面那个错误窗口,参与限速决策,而不是单纯 sleep 死等。
🏗️ 架构设计:每个平台一个独立适配器
主程序其实是一个大分发器:按直播间 URL 的域名特征,用一长串 if-elif 把请求路由到各平台的专属函数——抖音走抖音函数,虎牙走虎牙函数。每个适配函数按同一契约返回"主播名 + 直播状态 + 流地址"的标准结构,下游的清晰度选择、ffmpeg 参数拼装只认这个结构。
# main.py 的调度骨架(伪代码) def dispatch(room_url: str) -> dict: if "douyin.com/" in room_url: return run(spider.get_douyin_stream_data, room_url, dy_cookie) if "www.huya.com/" in room_url: return run(spider.get_huya_stream_data, room_url, hy_cookie) if "live.bilibili.com/" in room_url: return run(spider.get_bilibili_room_info, room_url, bili_cookie) # ... 其余平台分支这种"一个平台一个适配器"的写法让新增平台的成本被压到很低:在调度处加一条域名分支,再实现一个返回标准结构的函数。清晰度选择、录制参数、文件命名、推送逻辑统统不用动,改动范围就锁死在一个函数里。
⚡ 30 秒跑通第一个例子
最小步骤只有三条:
git clone https://gitcode.com/gh_mirrors/do/DouyinLiveRecorder.git cd DouyinLiveRecorder && pip install -r requirements.txt # 在 config/URL_config.ini 里写一行直播间地址,然后: python main.py程序会立刻进入循环监测,开播即调用 FFmpeg 开录,文件落在downloads目录。只想验证某个平台的直播间 ID 提取效果,也可以直接调解析函数看返回数据,不需要跑整条录制链路:
import asyncio from douyinliverecorder import spider room = asyncio.run(spider.get_douyin_stream_data("https://live.douyin.com/745964462470"))🧭 直播间 ID 提取策略怎么选
| 解析层级 | 单请求成本 | 抗变性 | 什么时候用 |
|---|---|---|---|
| URL 直解 | 几乎为零 | 最脆 | 长链里直接带数字 ID 的平台 |
| 页面内嵌 JSON | 一次页面请求 | 靠正则,需持续维护 | 信息都渲染进页面状态的大多数平台 |
| 开放接口 | 一次 API 调用,可能要签名 | 最稳 | 带风控的抖音、需登录态的海外平台 |
项目后续主要靠社区持续跟踪各平台接口变化,再逐步补上自动化的回归测试,把"某个平台突然取不到 ID"的响应周期压短。
🔚 一条链接到一段录像
回到开头那个群链接的场景:它现在能解释清楚是怎么变成下载目录里 ts 文件的。先 URL 直解、再翻页面、最后打接口,每层失败都只是降级到下一层的信号——这套分层思路不只适用于直播录制,写任何跨站数据采集都值得借鉴。平台页面和接口会一直变,但"由易到难、每层独立兜底"的决策顺序本身是不需要频繁重写的。
【免费下载链接】DouyinLiveRecorder可循环值守和多人录制的直播录制软件,支持抖音、TikTok、Youtube、快手、虎牙、斗鱼、B站、小红书、pandatv、sooplive、flextv、popkontv、twitcasting、winktv、百度、微博、酷狗、17Live、Twitch、Acfun、CHZZK、shopee等40+平台直播录制项目地址: https://gitcode.com/gh_mirrors/do/DouyinLiveRecorder
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考