前言这篇文章仅仅记录一下无聊的我做了一件比较无聊的事情:写了个IPTV频道扫描程序。
事先说明: 本文基本没有任何实用价值!
一方面觉得写代码挺麻烦的,另一方面代码写都写出来了,虽然没用,还是分享记录一下中间的曲折过程,算是个素材,瞬间觉得也不亏了。
前因家里的IPTV本来就是有的,采用的方法是光猫IPTV口直接连接软路由网口,再通过软理由搭建udpxy,这样的方式好处就是脱离IPTV机顶盒,只要连上家里的网络都能观看IPTV。
前两天发现运营商新推出了几个4K超清频道,而且还分SDR以及HDR。对画质有要求的我抱着扫描一下整个IP地址段完整搜索一下看看具体有哪些4K频道的想法,开启了这段无聊的故事。
网上有一些分享的4K频道地址可以直接拿来用,但我猜测会不会有遗漏的,所以才会想要自己扫描。
一些说明其实网上有很多现成的IPTV直播源,是互联网的链接,这一部分直播源只要导入一个地址就行,好处是省力,不需要自己维护,而且不需要搭建任何服务,开箱即用;坏处是频道固定,无法自定义添加或者删除一些无用频道。
我个人偏向于复杂的组播转单播,即搭建udpxy直接将运营商的组播地址拿来使用。坏处是过程相对复杂,组播地址需要自行找,m3u列表文件也要自己编辑;好处也比较显而易见,频道信号源非常稳定,频道可以自定义,看哪个频道就添加哪个频道。
最影响我的就是我这边地方台,没有与电信的IPTV进行合作,所以想看地方台,需要找到互联网的播放地址后添加到直播源m3u列表中。
也就是直接拿网上的直播源地址下载下来进行编辑,将地方台添加进去后,直播源的地址也是需要自行维护的,比较网上的直播源地址经常变动。
所以,自己使用组播地址是最稳定的方案,一次搞定之后基本不需要维护。
扫描方案要扫描端口,就基本确定使用Python进行编写,大致框架确定,即:扫描端口,获取返回值。
因此,我写了一个程序,运行之后发现扫描不出来,获取到的频道数量为0。
但是我在单独通过 curl 进行测试是,是能够正常返回数据的:
123HTTP/1.1 200 OKServer: udpxy 1.0-25.0Content-Type: application/octet-stream
为此,搜索了一些资料,猜测可能的原因是:
只有在客户端发送 正确的 User-Agent / Accept / Range 或 持续读取流 时才会返回数据
请求速度太快(高并发)、太小 chunk、或 HEAD 请求行为不同, 很可能被拒绝
于是,我尝试在代码中:
添加User-Agent来模拟播放器的行为
降低并发,从原来的500将为100,避免请求过多直接屏蔽
添加Range: bytes=0-,让 udpxy 发送真实 TS 数据
强制读取 4096 字节,避免 udpxy 误判断请求太短
更改了一整遍代码之后还是不行,扫描后依然结果为 0。
于是只能再次查资料,联想到之前使用 curl 单个测试时可以正常显示,但是在现在的异步脚本一个都扫不出来,可能是线程的问题,而且,udpxy的特点是无论组播组存不存在,它都会立刻返回 HTTP 200 OK(不会 404),只有真正有组播流进来时,才会立刻开始吐 TS 数据包。
想着好吧,再次更改代码,结果还是不行。。。差点就没辙了,想着都到这份上了,死马当活马医,降低判断标准:“只要 1 秒内能收到 ≥ 2 个完整 188 字节 TS 包” 就算存活,以及再次降低并发。
没想到还真的可以。。。但是速度一般般,不是很快。
代码及用法前提条件: 目前网络配置是光猫ITV口直接连接路由器或者交换机直接播放组播地址,并且搭建了udpxy。
某些路由器可以省去搭建udpxy,比如华硕路由器。
代码:
scan.py
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758import asyncioimport aiohttpimport randomfrom tqdm.asyncio import tqdm_asyncioALIVE = []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())
用法:
12345python3 -m venv iptvsource iptv/bin/activatepip install aiohttp tqdmpython3 scan.py
无用论回到开头,为什么说这个程序没什么用?
我全程扫了一圈,发现与网上分享的组播地址可以说是一模一样,即使有些比较冷门的频道被扫出来了,但是这类频道本身就几乎不会去看,所以没有用;
每个省市的IPTV组播地址以及端口都各不相同,扫描前要确定大致地址及端口,虽然现在全国大多数都固定使用8000端口了,但还有一些小众端口。正常情况下在这一步的时候,其实已经拿到了当前自身省市的组播地址了,再去扫描也最多是查漏补缺,就像是考试已经99分了,还去为了最后仅有的1分耗时耗力;
沉没成本比较大,即使硬着头皮去整个扫描一下,得到的与付出的完全不成正比,有这点时间不如做其他的事情。
综上所述,就是再给我一次机会,我是绝对不会去做这种事情的。
好人做到底在解决问题搜集资料的时候,看到的各省市的组播地址段分享给大家,如果非要尝试的也未尝不可。
省份
主要组播地址段
常用端口
备注
江苏
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组播源的信号是怎么判定的,到现在还是一知半解,也算是一个学习的过程。