无聊的我写了个无聊的IPTV频道扫描程序

前言

这篇文章仅仅记录一下无聊的我做了一件比较无聊的事情:写了个IPTV频道扫描程序。

事先说明: 本文基本没有任何实用价值!

一方面觉得写代码挺麻烦的,另一方面代码写都写出来了,虽然没用,还是分享记录一下中间的曲折过程,算是个素材,瞬间觉得也不亏了。

前因

家里的IPTV本来就是有的,采用的方法是光猫IPTV口直接连接软路由网口,再通过软理由搭建udpxy,这样的方式好处就是脱离IPTV机顶盒,只要连上家里的网络都能观看IPTV。

前两天发现运营商新推出了几个4K超清频道,而且还分SDR以及HDR。对画质有要求的我抱着扫描一下整个IP地址段完整搜索一下看看具体有哪些4K频道的想法,开启了这段无聊的故事。

网上有一些分享的4K频道地址可以直接拿来用,但我猜测会不会有遗漏的,所以才会想要自己扫描。

一些说明

其实网上有很多现成的IPTV直播源,是互联网的链接,这一部分直播源只要导入一个地址就行,好处是省力,不需要自己维护,而且不需要搭建任何服务,开箱即用;坏处是频道固定,无法自定义添加或者删除一些无用频道。

我个人偏向于复杂的组播转单播,即搭建udpxy直接将运营商的组播地址拿来使用。坏处是过程相对复杂,组播地址需要自行找,m3u列表文件也要自己编辑;好处也比较显而易见,频道信号源非常稳定,频道可以自定义,看哪个频道就添加哪个频道。

最影响我的就是我这边地方台,没有与电信的IPTV进行合作,所以想看地方台,需要找到互联网的播放地址后添加到直播源m3u列表中。

也就是直接拿网上的直播源地址下载下来进行编辑,将地方台添加进去后,直播源的地址也是需要自行维护的,比较网上的直播源地址经常变动。

所以,自己使用组播地址是最稳定的方案,一次搞定之后基本不需要维护。

扫描方案

要扫描端口,就基本确定使用Python进行编写,大致框架确定,即:扫描端口,获取返回值。

因此,我写了一个程序,运行之后发现扫描不出来,获取到的频道数量为0

但是我在单独通过 curl 进行测试是,是能够正常返回数据的:

HTTP/1.1 200 OK
Server: udpxy 1.0-25.0
Content-Type: application/octet-stream

为此,搜索了一些资料,猜测可能的原因是:

  • 只有在客户端发送 正确的 User-Agent / Accept / Range持续读取流 时才会返回数据

  • 请求速度太快(高并发)、太小 chunk、或 HEAD 请求行为不同, 很可能被拒绝

于是,我尝试在代码中:

  1. 添加User-Agent来模拟播放器的行为

  2. 降低并发,从原来的500将为100,避免请求过多直接屏蔽

  3. 添加Range: bytes=0-,让 udpxy 发送真实 TS 数据

  4. 强制读取 4096 字节,避免 udpxy 误判断请求太短

更改了一整遍代码之后还是不行,扫描后依然结果为 0

于是只能再次查资料,联想到之前使用 curl 单个测试时可以正常显示,但是在现在的异步脚本一个都扫不出来,可能是线程的问题,而且,udpxy的特点是无论组播组存不存在,它都会立刻返回 HTTP 200 OK(不会 404),只有真正有组播流进来时,才会立刻开始吐 TS 数据包。

想着好吧,再次更改代码,结果还是不行。。。差点就没辙了,想着都到这份上了,死马当活马医,降低判断标准:“只要 1 秒内能收到 ≥ 2 个完整 188 字节 TS 包” 就算存活,以及再次降低并发

没想到还真的可以。。。但是速度一般般,不是很快。

代码及用法

前提条件: 目前网络配置是光猫ITV口直接连接路由器或者交换机直接播放组播地址,并且搭建了udpxy。

某些路由器可以省去搭建udpxy,比如华硕路由器。

代码:

scan.py

import asyncio
import aiohttp
import random
from tqdm.asyncio import tqdm_asyncio

ALIVE = []
BASE = "http://10.10.10.1:5999/rtp/239.49.{}.{}:{}"     # 替换为自己的IPTV单播地址及自己省市对应的IPTV地址段
PORTS = [6000, 8000, 9614, 9802, 9814, 9822]            # 替换为自己省市的常见IPTV端口列表
TOTAL = 10 * 256 * len(PORTS)

async def check(session, third, fourth, port, sem, pbar):
    async with sem:
        url = BASE.format(third, fourth, port)
        await asyncio.sleep(random.uniform(0.02, 0.09))
        try:
            async with session.get(url, timeout=4) as r:
                data = await r.content.read(1200)
                if len(data) > 100:
                    ALIVE.append(url)
                    pbar.set_postfix(found=len(ALIVE), refresh=False)
                    print(f"\n[+] 存活 → {url}")
        except:
            pass
        finally:
            pbar.update(1)

async def main():
    print("IPTV单播地址扫描")
    sem = asyncio.Semaphore(10)
    connector = aiohttp.TCPConnector(limit=15, limit_per_host=15)
    timeout = aiohttp.ClientTimeout(total=5)

    async with aiohttp.ClientSession(connector=connector, timeout=timeout) as session:
        with tqdm_asyncio(total=TOTAL, desc="扫描进度", colour="cyan",
                         bar_format="{l_bar}{bar}| {n_fmt}/{total_fmt} [{elapsed}<{remaining}, {rate_fmt}] 已发现: {postfix}") as pbar:

            tasks = []
            for third in range(10):
                for fourth in range(256):
                    for port in PORTS:
                        tasks.append(check(session, third, fourth, port, sem, pbar))

                    if len(tasks) >= 300:
                        await asyncio.gather(*tasks)
                        tasks.clear()
                        await asyncio.sleep(0.5)

            if tasks:
                await asyncio.gather(*tasks)

    # 保存结果
    with open("result.txt", "w", encoding="utf-8") as f:
        f.write("\n".join(sorted(ALIVE)) + "\n")

    print(f"\n扫描完成!共发现 {len(ALIVE)} 个真实频道")
    print("完整列表已保存: result.txt")

asyncio.run(main())

用法:

python3 -m venv iptv
source iptv/bin/activate

pip install aiohttp tqdm
python3 scan.py

无用论

回到开头,为什么说这个程序没什么用?

  1. 我全程扫了一圈,发现与网上分享的组播地址可以说是一模一样,即使有些比较冷门的频道被扫出来了,但是这类频道本身就几乎不会去看,所以没有用;

  2. 每个省市的IPTV组播地址以及端口都各不相同,扫描前要确定大致地址及端口,虽然现在全国大多数都固定使用8000端口了,但还有一些小众端口。正常情况下在这一步的时候,其实已经拿到了当前自身省市的组播地址了,再去扫描也最多是查漏补缺,就像是考试已经99分了,还去为了最后仅有的1分耗时耗力;

  3. 沉没成本比较大,即使硬着头皮去整个扫描一下,得到的与付出的完全不成正比,有这点时间不如做其他的事情。

综上所述,就是再给我一次机会,我是绝对不会去做这种事情的。

好人做到底

在解决问题搜集资料的时候,看到的各省市的组播地址段分享给大家,如果非要尝试的也未尝不可。

省份 主要组播地址段 常用端口 备注
江苏 239.49.0.0 ~ 239.49.9.255 8000(主力) 9614/9610/9802/9602等老端口残留 全省统一,南京/苏州/无锡通用,140+频道
上海 239.45.0.0 ~ 239.45.255.255 233.18.204.0/24(新增) 5140(主力) 2025年2月新增233网段,4K HDR多
广东 239.253.0.0 ~ 239.253.255.255 8000(主力) 南方电信经典段,广州/深圳通用
浙江 239.51.0.0 ~ 239.51.255.255 8000(主力) 杭州主力,温州部分仍混用239.49
北京 239.97.0.0 ~ 239.97.255.255 8000 北方常见
山东 239.98.0.0 ~ 239.98.255.255 8000 部分地市混用239.49
安徽 239.94.0.0 ~ 239.94.255.255 8000 合肥/芜湖通用,2025年8月仍有更新
福建 239.93.0.0 ~ 239.93.255.255 5140/8000 福州/厦门主力
四川/重庆 239.80.0.0 ~ 239.80.255.255 8000 西南主力
湖北 239.95.0.0 ~ 239.95.255.255 8000 武汉通用
湖南 239.96.0.0 ~ 239.96.255.255 8000 长沙主力
河南 239.99.0.0 ~ 239.99.255.255 8000 郑州通用
河北 239.91.0.0 ~ 239.91.255.255 8000 石家庄主力
山西 239.92.0.0 ~ 239.92.255.255 8000 太原通用
陕西 239.90.0.0 ~ 239.90.255.255 8000 西安主力
甘肃/宁夏/青海 239.89.0.0 ~ 239.89.255.255 8000 西北统一
新疆 239.88.0.0 ~ 239.88.255.255 8000 乌鲁木齐主力
广西 239.254.0.0 ~ 239.254.255.255 8000 南宁通用
江西 239.107.x.x 或混用239.49 8000 南昌部分仍用老段

最后

这篇文章就是随便写写,反正也是无聊,写了无聊的程序,写了无聊的文章。

这个过程大概用了两天时间,关于代码的优化以及IPTV组播源的信号是怎么判定的,到现在还是一知半解,也算是一个学习的过程。

0 0 投票数
文章评分
订阅评论
提醒
guest
0 评论
最旧
最新 最多投票
内联反馈
查看所有评论
滚动至顶部
0
希望看到您的想法,请您发表评论x