把上千个 IPTV 直播源整理得明明白白

一、项目缘起

IPTVlist 是一个围绕网络电视(IPTV)直播列表进行抓取、清洗与分类整理的小型工具项目。它的核心目标,是把分散在互联网各处、格式各异、命名混乱的直播源列表,汇聚成一份结构清晰、分类合理、可以直接被播放器(如 TVBox 等)使用的 M3U 播放列表。

在此之前,同级的 IPTV/ 目录中已经存在若干零散的脚本,分别负责下载、合并与生成列表,但功能彼此重叠、输出路径与规则也不统一。为了让这套流程更集中、更可控,本项目在独立的 IPTVlist/ 目录中重新构建了一个单一职责、开箱即用的脚本——generate_itv.py

IPTV 全球分布示意

图 1:IPTV 在全球的分布情况(来源:Wikimedia Commons)

二、会话约定

本项目在协作方式上确立了明确的约定。首先,整个会话被严格限制在 IPTVlist/ 目录内,所有读写操作都只在该目录中进行,避免误改仓库中的其他内容。其次,本项目所有对话均要求使用中文,包括分析、说明与思考过程,以保证交流的一致性与可读性。此外,项目建立了 工作日志.md,以时间线的方式记录每一次需求、每一处改动与每一次验证结果,使项目的演进过程可追溯、可复盘。

三、核心脚本 generate_itv.py

generate_itv.py 是整个项目的核心,它把「抓取—解析—分类—规范化—输出」串成一条完整的流水线。

网络电视盒子

图 2:网络电视盒子是 M3U 播放列表的常见载体(来源:Wikimedia Commons)

在抓取环节,脚本首先维护一份 weblist.txt,其中登记了需要下载的网络播放列表地址,默认包含经 gh-proxy 代理的 holive.m3u 以及 vbskycn/iptviptv4.m3u;同时脚本还会固定抓取主列表 tv.txt。下载过程支持 gzip 自动解压、失败重试,并在 gh-proxy 代理不可用时回退直连 raw.githubusercontent.com,以提高在不同网络环境下的成功率。

在解析环节,脚本需要面对两种截然不同的格式:一种是标准的 M3U(以 #EXTINF 描述频道、下一行为播放地址),另一种是 TPL 格式(形如 频道名称,播放地址,并以 分类,#genre# 划分段落)。项目早期只支持前者,导致 tv.txt 的频道一度完全未被收录;修复后,解析器同时兼容两种格式,并忽略 #genre# 之类的段落标记,从而保证所有来源的频道都能被正确读取。

在分类环节,脚本按照既定规则把频道划分为五个分组:名称中包含 CCTV 的归入「央视频道」,包含「卫视」的归入「卫视频道」,包含省、市、地区名称的归入「地方频道」,名称中带有类似 17:45 时间戳的直播条目单独归入「体育频道」,其余无法归类的则进入「数字频道」。分类优先级为体育、央视、卫视、地方、数字,确保规则冲突时有确定的归属。

在名称规范化环节,脚本做了两件重要的事。其一,央视频道的名称统一按照 tv.txt 的命名规则整理,例如把纯编号的 CCTV1 补全为 CCTV1综合,把 CCTV5+ 补全为 CCTV5+体育赛事,并保留 CCTV4欧洲CCTV4美洲 等带描述的变体,映射表从 tv.txt 动态生成,随上游更新而自动跟随。其二,对于汉字数量超过四个的频道名称,删除其中的「广播电视台」「频道」等冗余字样,例如「辽宁广播电视台体育休闲频道」被精简为「辽宁体育休闲」,让列表更清爽。

在输出环节,脚本按 URL 去重、先到先得,并让来自 tv.txt 的频道在每个分组内优先排列,其余来源依次在后;最终结果写入 web/itv.m3u,同时在控制台打印各分组的频道数量,便于快速核对。

四、逐步演进的需求

本项目并非一次性设计完成,而是在对话中逐步打磨:从最初「抓取并分类」,到「央视频道名称按 tv.txt 规则统一」,再到「含时间戳的频道单列体育频道」「清理名称中的冗余词」「tv.txt 频道优先」,每一步都对应一个具体诉求。正是这种迭代,让脚本从可用走向好用,也让 工作日志.md 成为一份完整的演进档案。

五、成果与意义

截至目前,generate_itv.py 可一键生成约千余个频道的分类列表,产出 weblist.txtweb/tv.txtweb/holive.m3uweb/iptv4.m3uweb/itv.m3u 等文件。它体积小巧、依赖仅限 Python 标准库,既能本地运行,也便于部署到服务器定时执行。更重要的是,它把一套原本零散、重复的列表处理工作,收敛为一条清晰、可维护、可持续迭代的流水线,为后续扩展到更多源、更细的分类与更智能的命名规则打下了坚实基础。

从有线电视转向流媒体

图 3:从有线电视转向网络流媒体的大趋势(来源:Wikimedia Commons)