在TVBox中,通过 chaquopy 实现了基于 python 爬虫的接口抽象。目前在一些更新比较频繁的类TVBox软件中均已支持,例如 Fongmi 影视、影视仓等。本文以 Fongmi 影视为参考,详细解读其中 Python 爬虫接口如何适配,各函数接口输入输出参数含义,使用场景等。
相关源代码见 https://github.com/FongMi/TV/tree/fongmi/chaquo/src/main/python/base/spider.py
init
def init(self, extend=""):pass
init 接口主要负责初始化。
extend 入参为字符串格式,内容来自 json 配置文件中关联该py脚本的站点下的 ext
。在 json 配置文件中,你可以根据脚本需要完全自定义 ext 中的内容,例如传递网址、登录的cookie参数等等。
{"key": "py_butailing","name": "不太灵","type": 3,"api": "./api/butailing.py","searchable": 1,"changeable": 1,"quickSearch": 1,"filterable": 1,"playerType": 2,"ext": {"text":"ext-test","data":[1,2,3,4,5]},"style": {"type": "rect","ratio":0.75}
}
在实际运行时,最先被调用的就是 init 接口。因此你可以将一些通用的参数的初始化放在这个接口里,如 host 地址。
homeContent
homeContent 接口主要负责处理站点分类、筛选以及首页视频列表。
在 TVBox 中,一个站点通常在顶部有多个可供用户选择的分类按钮,例如电影、电视、综艺等等。而在这些分类选中后,还可以提供筛选功能,例如电影可以选择动作片、恐怖片、科幻片等等。在这些分类还未选中时,首页还需要提供用于展示的视频列表信息。
filter 入参为布尔型变量,其内容来自 json 配置中的 filterable
参数,0 表示不可筛选,1 表示可筛选。
homeContent 返回的是一个 json,其格式参考如下:
{"class": [{"type_name": "电影","type_id": 20},{"type_name": "电视剧","type_id": 21}],"filters": {"20": [{"key": "class","name": "类型","value": [{"n": "Netflix","v": "Netflix"},{"n": "喜剧","v": "喜剧"}]},{"key": "area","name": "地区","value": [{"n": "大陆","v": "大陆"},{"n": "香港","v": "香港"}]}],"21": [{"key": "class","name": "类型","value": [{"n": "Netflix","v": "Netflix"},{"n": "古装","v": "古装"}]},{"key": "area","name": "地区","value": [{"n": "大陆","v": "大陆"},{"n": "韩国","v": "韩国"}]}]},"list": [{"vod_id": 69780,"vod_name": "绝世战魂","vod_pic": "https://img.ffzy888.com/upload/vod/20221114-1/4f2a3910e3f0ad0f1878eb9932ff6a33.jpg","vod_remarks": "更新至127集"},{"vod_id": 148464,"vod_name": "地狱旅馆","vod_pic": "https://img.lzzyimg.com/upload/vod/20220909-1/6a60270e5b91796482f1557d814b4fa0.jpg","vod_remarks": "更新至04集"}]
}
json 内容一共包括三大块:class、filters、list。
class 为一数组,子元素由 type_name
和 type_id
构成,type_name 为分类名称,最终显示在顶部的分类选项就是它;type_id 是用于后续识别分类的值,一般可将其与站点网址中的分类路径相关联。
filters 是一个字典,子元素的键名与class中子元素的 type_id 对应,表示在该分类下所产生的筛选选项。子元素是一个列表,因为筛选时可以有多个筛选维度。对于其中某一个维度,其内容由 key
、name
、value
构成。其中 key
用于后续识别当前筛选维度,name
用于显示,value
是一个列表,筛选时有多个选项,这些选项一般是互斥的(即只能选一个)。各个选项由 n
和 v
构成。n
表示名称,用于显示,v
为用于识别选项的值。
list 是一个列表,其子元素即为每个视频的信息,通常这里的信息是简略的,只要包括链接详情页的地址id,视频标题,视频封面,视频标签(如豆瓣评分)等。这里的 vod 形式实际上参考的是 苹果cms 。
homeVideoContent
homeVideoContent 主要负责处理首页的推荐视频列表,返回的是一个json,具体格式如下
{"list": [{"vod_id": 69780,"vod_name": "绝世战魂","vod_pic": "https://img.ffzy888.com/upload/vod/20221114-1/4f2a3910e3f0ad0f1878eb9932ff6a33.jpg","vod_remarks": "更新至127集"},{"vod_id": 148464,"vod_name": "地狱旅馆","vod_pic": "https://img.lzzyimg.com/upload/vod/20220909-1/6a60270e5b91796482f1557d814b4fa0.jpg","vod_remarks": "更新至04集"}]
}
可以看到与 homeContent中的list类似,去掉了 class 和 filters。
categoryContent
categoryContent 主要负责处理的是分类、筛选、翻页等动作发生时,页面中所需要刷新的视频列表信息。
tid 入参是 type_id 的缩写,格式为字符串,当分类按钮被选中时, tid的值也就更新为 type_id 的值。除了这个场景外,当存在其的非分类动作产生的跳转时,tid的值会更新为跳转时由vod传递过来的 vod_id 值。
pg 入参是 page 的缩写,格式为字符串,视频列表是按页加载的,对应网站中的某一页内容,当用户滚动视频列表到底部时,会触发加载新的一页,pg自增,再次调用该接口,从而获得新的视频内容。这就类似于懒加载。
filter 入参为布尔型变量,表示是否支持筛选,内容来自 json 配置中的 filterable
参数,0 表示不可筛选,1 表示可筛选。
extend 入参是一个字典,用户点击某个筛选按钮,则这个这个按钮的 key 会被记录,value 则来自value列表中所选中的选项对应的 v 值。
通过以上参数,合理解析由用户操作所产生的包括跳转地址、分页、分类筛选等信息,构造目标网页地址,然后再自行编写网页内容爬取函数,最后返回视频列表信息。
函数最终返回的结果为 json,格式如下:
{"list": [{"vod_id": 69780,"vod_name": "绝世战魂","vod_pic": "https://img.ffzy888.com/upload/vod/20221114-1/4f2a3910e3f0ad0f1878eb9932ff6a33.jpg","vod_remarks": "更新至127集"},{"vod_id": 148464,"vod_name": "地狱旅馆","vod_pic": "https://img.lzzyimg.com/upload/vod/20220909-1/6a60270e5b91796482f1557d814b4fa0.jpg","vod_remarks": "更新至04集"}],"page": "1","pagecount": 9999,"limit": 90,"total": 999999
}
其中list为视频列表,剩下的是关于页码的信息,page 表示当前是第几页,pagecount 表示一共有多少页,limit 表示超时,total表示一共多少页。
这里值得一提的是,该接口实际上可以处理类似文件夹多层级打开的功能。视频信息完整的可供解析的参数包括:
{"vod_id": "","vod_name": "","type_name": "","vod_pic": "","vod_remarks": "","vod_year": "","vod_area": "","vod_director": "","vod_actor": "","vod_content": "","vod_play_from": "","vod_play_url": "","vod_wallpaper": "","vod_tag": "","action": "","cate": "","style": "","land": "","circle": "","ratio": ""
}
其中 vod_tag 有两种选项:file 、folder,如果是folder则表示点击该视频封面后,会将vod_id 作为新的 tid 继续调用 本接口,从而形成多层点击,直到返回的视频 vod_tag 为 file,再点击时才调用 detailContent 。
另外视频的封面尺寸实际上可以在本接口中直接调整,通过style参数控制,具体参数包括:
//直式
{"style": {"type": "rect"}
}//橫式
{"style": {"type": "rect","ratio": 1.33}
}//正方
{"style": {"type": "rect","ratio": 1}
}//正圓
{"style": {"type": "oval"}
}//橢圓
{"style": {"type": "oval","ratio": 1.1}
}
detailContent
detailContent 主要负责处理某个视频页网址的视频详细信息爬取。
ids 入参默认是一个列表,但是一般我们只取第一个元素作为视频页地址。
在这个接口中,需要获取视频的详细信息,最终接口返回 json,格式如下:
{"list": [{"vod_name": "爱的小麻烦","vod_pic": "https://api.codetabs.com/v1/proxy/?quest=https://img.cfwebname.top/i/2025/08/15/689e94507a6a5.png","vod_year": "2020","vod_director": "罗伯托·菲斯科","vod_actor": "阿方索·杜萨勒,瑞吉娜·布兰登,Francesca Mercadante","type_name": "喜剧","vod_area": "墨西哥","vod_content": " 他全心爱上的女子竟然讨厌小孩!这下如何是好?9 岁的女儿提议假装成他的妹妹,应该不会有什麽问题吧?","vod_play_from": "WEB-1080P$$$其他","vod_play_url": "磁力$magnet:?xt=urn:btih:69A166E5CFACB8C24B2280D96395F15556737024#磁力$magnet:?xt=urn:btih:74EE1CA8F44788A68895C3CDA07C9F3A68D3B66A#磁力$magnet:?xt=urn:btih:A866D12DC828C7C0DD9AB31A348186F2E4025ED0$$$磁力$magnet:?xt=urn:btih:42F4AF63FE801EEC9F9941BE13F1A743DC0A379A"}]
}
视频资源
这里要重点解释的是 vod_play_from
和 vod_play_url
这两个是绑定在一起的,其内容语法来自 苹果cms 。在苹果cms中,通过下面这种语法表示一个视频资源:
视频名称$视频链接
当有多个视频资源时(通常在电视剧资源时表示视频集数),通过#
串联。不同线路通过 $$$
串联。上述vod_play_from
表示路线,vod_play_url
表示该路线下对应的资源。这里的视频链接可以是直接播放的直链,也可以是某个可解析出视频直链的地址,这样在 playerContent 接口中需要写解析方法。
富文本
在 FongMi 影视中,允许在 vod_director、vod_actor、vod_content等内容中插入富文本链接,软件中带有富文本链接的内容会变黄色,带有下划线。富文本格式如下:
[a=cr:{{"id":"{href}","name":"{name}"}}/]{name}[/a]
其中href为跳转的链接,类似 vod_id 功能,name用于显示。
当点击该富文本链接时,会将href作为跳转tid,再次调用 categoryContent 。
playerContent
playerContent 主要负责处理播放视频时视频的资源地址解析。
id 入参即为detailContent 中传入的某个视频链接地址。
flag 和 vipFlags 入参目前尚未看到有开源的接口源有用到的。
接口返回的结果为json,格式如下:
{"jx":1,"parse": 0,"url": "https://tyyszywvod5.com/videos/202507/03/68669eb47ea4833d7f00048e/ae77de/index.m3u8","header": {"User-Agent": "okhttp/3.14.9"}
}
其中 jx 表示用第几个解析接口,parse表示是否需要解析。url为需要播放的地址。header 可有可无。
searchContent
searchContent 主要处理站点内容搜索返回视频列表。
key 入参即为搜索框输入的文本内容。
quick 为布尔型变量,表示是否启用快速搜索。
pg 表示页码,可能存在多页搜索结果。
该接口与前面的接口类似,只是从搜索页的网址中获取视频列表,返回结果也为json,具体如下:
{"list": [{"vod_name": "爱的小麻烦","vod_pic": "https://api.codetabs.com/v1/proxy/?quest=https://img.cfwebname.top/i/2025/08/15/689e94507a6a5.png","vod_year": "2020","vod_director": "罗伯托·菲斯科","vod_actor": "阿方索·杜萨勒,瑞吉娜·布兰登,Francesca Mercadante","type_name": "喜剧","vod_area": "墨西哥","vod_content": " 他全心爱上的女子竟然讨厌小孩!这下如何是好?9 岁的女儿提议假装成他的妹妹,应该不会有什麽问题吧?","vod_play_from": "WEB-1080P$$$其他","vod_play_url": "磁力$magnet:?xt=urn:btih:69A166E5CFACB8C24B2280D96395F15556737024#磁力$magnet:?xt=urn:btih:74EE1CA8F44788A68895C3CDA07C9F3A68D3B66A#磁力$magnet:?xt=urn:btih:A866D12DC828C7C0DD9AB31A348186F2E4025ED0$$$磁力$magnet:?xt=urn:btih:42F4AF63FE801EEC9F9941BE13F1A743DC0A379A"}],"page":"1"
}
其他
其他还有很多接口,用于辅助的,例如日志打印的log,结合Fongmi的调试功能可以打印一些关键信息用于脚本开发调试。
再比如缓存相关的,getCache、setCache、delCache。获取网页内容的fetch等等。
以上辅助接口功能单一比较好理解,在此不再赘述。