IPTV 系列②:IPTV 源总是不稳定?我写了一个自动测速过滤系统
🐴 赛博牛马出品 | 2026-03-30 系列定位:[全球 IPTV 直播源实战系列②]
前言
你有没有遇到过这种情况:兴冲冲找到一个 IPTV 直播源,丢进 VLC 满怀期待,结果点哪个哪个卡,点哪个哪个"无法播放"。或者今天看得好好的,明天打开发现大半个列表都红了叉。
IPTV 直播源的三大噩梦——死链、卡顿、频道消失——几乎是所有玩家都会碰到的痛点。网上分享的 m3u 文件,点开十个有五个是废的,剩下的八个里有三个播着播着就缓冲。
手动测速?那得一个一个链接点进去看,太费时间。靠群友分享?那更不稳定,人家源的寿命可能就两三天。
作为一个受够了这种折磨的程序员,我决定把问题彻底解决掉——写了一个自动测速 + 过滤的系统,接在 iptv-scraper 里,每次抓完源自动测速,低于阈值的直接踢掉,输出的列表拿来就能用。
这篇文章就来深入讲讲这个测速过滤系统的设计思路,以及一些你可能也会遇到的坑。
IPTV 源三大问题:死链、卡顿、消失
在说方案之前,先把问题理清楚。
死链:源站撤了、链接过期、域名被墙。这类链接 VLC 一尝试连接就会报网络错误,等半天最后给个红叉。
卡顿:源本身还活着,但带宽不够。播放个 720p 的信号实际需要 2~3Mbps 的稳定带宽,如果源只有 300KB/s(约 2.4Mbps),VLC 就会频繁缓冲,体验极差。
频道消失:源还在,但某个频道被悄悄下架了。列表里明明有,播的时候才发现已经没了。
现有解决方案的局限性: - 手动测试:逐一打开 VLC 验证——500 个频道要测到什么时候? - 群友分享:人家测过不代表你那边能用(网络环境不同),而且质量参差不齐 - 公共列表(如 iptv-org):覆盖广但没有速度过滤,播什么全靠运气
所以核心需求很明确:自动化 + 速度验证 + 持续维护。接下来看怎么实现。
测速模块设计:多线程 + curl 实测
核心原理
测速的本质,是下载一段数据,测量单位时间内的下载量。技术上用 curl 实现:
curl -r 0-524287 \ # 下载前 512KB
-w "%{speed_download}" \ # 输出实时速率
-o /dev/null \
-s --max-time 10 \
"http://example.com/stream.m3u8"curl 的 -w "%{speed_download}" 会输出字节/秒为单位的实时下载速率。我们取前 512KB 的数据测速,足以判断链路质量,又不会等太久(一个大文件源等它下完太耗时了)。
测得的结果乘以 8 就是 bps,除以 1024 就是 KB/s。除以 8 再除以 1024 就是 Mbps。
多线程设计
500+ 条直播源如果串行测速,每条平均 5 秒,光测速就要 40 分钟。所以必须上多线程并行。
iptv-scraper 里用的是 Python concurrent.futures.ThreadPoolExecutor,默认 10 个 workers 同时跑:
with ThreadPoolExecutor(max_workers=10) as executor:
futures = {executor.submit(test_speed, url): url for url in urls}
for future in as_completed(futures):
result = future.result()
# 写入缓存,写入结果列表10 个线程并行,每条源平均 3~5 秒出结果,500 条源大约 3~5 分钟完成测速+过滤全流程。
超时控制
网络不稳定时,一条链接可能卡在 DNS 解析或 TCP 握手阶段。为了不让单条链接把整个测速流程卡死,必须设置超时:
连接超时:3 秒(
--connect-timeout 3)总超时:10 秒(
--max-time 10)
超过 10 秒的链接直接标记为 TIMEOUT,不计入可用源。
架构总览
一张图总结测速模块的工作流程:

缓存机制:重复测速?不存在的
两个缓存文件
测速结果和验证结果各自独立缓存:
validation_cache.json:记录每个 URL 的有效/无效状态(有效=能连接)speedtest_cache.json:记录每个 URL 的实测速度(bytes/second)
每次运行新源时,系统先查缓存:
这条 URL 之前测过吗?
├── 测过,且 < 24 小时 → 直接用缓存结果 ✅
├── 测过,但 > 24 小时 → 重新测速
└── 没测过 → 执行完整测速流程为什么是 24 小时?
IPTV 直播源的稳定性不是恒定的——同一个源,可能上午快晚上慢,也可能今天能用明天就挂了。24 小时是一个合理的折中:既不会太频繁地重复测速(节省时间),又能保证速度数据不会太过时。
调试加速:SKIP_VALIDATION=1
本地开发调试时,如果只想看程序逻辑、不想真的跑一遍测速,可以设置环境变量 SKIP_VALIDATION=1 跳过所有网络请求,直接读取缓存或者跳过速度验证。这个开关在开发阶段节省了大量等 curl 的时间。
缓存命中流程

按速度排序:把最好的源排在前面
排序逻辑
测速完成后,所有源按速度从高到低排序。SORT_BY_SPEED=true 这个配置项让输出的 m3u 文件中,卡得最少的频道排在最前面。
这样有两个好处: 1. 用户体验:打开播放列表,优先尝试的都是最快的源,不用翻到最底下才能找到能看的 2. 故障排查简单:如果列表后半段普遍不可用,说明整体源质量差,需要补充新的采集源
速度阈值:为什么默认是 500KB/s?
约 3.9~4.1 Mbps,这个数字是有依据的:
所以 500KB/s 是"流畅播放 720p"的保底速度。如果你的网络条件好(比如有 50Mbps 以上的带宽),可以把阈值调高到 1MB/s 甚至更高,过滤更严格。
阈值通过环境变量 MIN_SPEED_KB 设置,比如 MIN_SPEED_KB=1024 就是只保留 1MB/s 以上的源。
速度分布直方图
为了让大家对测速结果有个直观感受,下图是一次完整运行后所有频道的速度分布:

可以看到,大多数有效源集中在 1~3 Mbps区间,符合大多数直播信号的码率特征。红色虚线标记了 500KB/s(约 4Mbps)的最低阈值,高于这条线的才是可用源。
真实数据展示
一次完整运行的输出
以下是运行 iptv-scraper 的控制台输出:

从实际数据来看: - 总计测试 523 条源 - 312 条通过(速度 > 500KB/s,标记为 OK) - 145 条失败(速度不达标或连接错误,标记为 FAIL) - 66 条超时(超过 10 秒无响应,标记为 TIMEOUT)
通过率约 60%。这意味着即使从大量公开源中抓取,过滤后依然能保证六成以上的可用率。相比手动一个一个试,这个效率高太多了。
缓存效果
第二次运行时,由于大部分 URL 命中了 24 小时内的缓存,速度大幅提升——系统只需要对新增或过期缓存的 URL 执行真实测速,整体运行时间从 5 分钟缩短到几十秒。
与同类方案对比

可以看到,自建方案在速度过滤和自动化上有不可替代的优势。iptv-org 是好资源,但它是公共服务,不能针对你的网络环境做个性化过滤。
GitHub Actions 认证踩坑记
测速过滤系统搭好之后,下一步就是让它自动跑。我用 GitHub Actions 设置了每天凌晨 3 点自动执行。配置过程中踩了几个认证相关的坑,记录如下:
坑 1:权限不够导致 push 失败
Actions 默认的 GITHUB_TOKEN 没有写权限,需要在 workflow 文件里显式声明:
permissions:
contents: write坑 2:push 触发新的 workflow,形成循环
Actions push 代码后会触发新的 workflow,造成无限循环。用 paths-ignore 解决:
- uses: actions/checkout@v4
if: github.event_name == 'schedule'坑 3:token 认证被 GitHub 吞掉
直接 git push https://[email protected]/... 这种写法在某些版本会失败。更稳妥的做法是:
git remote set-url origin "https://x-access-token:[email protected]/owner/repo.git"三次 commit 才把认证问题修干净:

这些问题看起来小,但卡住了排查起来挺费时间的,记录下来希望能帮到有类似问题的朋友。
总结
IPTV 源不稳定的问题,靠谱的解法不是"找一个好源",而是建一套持续过滤的机制。
iptv-scraper 的测速过滤系统核心就三件事: 1. 多线程并行测速:10 个 workers 同时跑,500+ 源 5 分钟测完 2. 24 小时缓存:避免重复劳动,加速增量更新 3. 速度阈值过滤:低于 500KB/s 的源直接踢掉,输出拿来就能用
配合 GitHub Actions 每天自动跑,你拥有的不是一个静态的 m3u 文件,而是一个每天自动更新的活的播放列表。
系列文章: - ← IPTV 系列①:一行命令搭建私有 IPTV 直播源管理器 - IPTV 系列③:2026 年 IPTV 观看方案全对比 →
相关资源: - 🐴 iptv-scraper GitHub - 觉得有用的话给个 Star 吧! - 📺 全球 IPTV 直播源汇总 - 最新可用源列表
🐴 赛博牛马 | 2026-03-30觉得文章有用?关注我,你的支持是我继续写下去的动力。
评论区