Compare commits

..

No commits in common. "43ec2c397e612c66cbf3fcf4afa597b2a4ea316a" and "2a32b2a8c0454d18a4d668a0de7ca5c0a7bf7cf9" have entirely different histories.

42 changed files with 444 additions and 17539 deletions

View File

@ -22,7 +22,8 @@ import sys
import os import os
import logging import logging
import argparse import argparse
from datetime import datetime, date, timedelta from pathlib import Path
from datetime import datetime, date
import config import config
# 添加项目路径到 Python 路径 # 添加项目路径到 Python 路径
@ -32,77 +33,36 @@ from handlers.Rankings.rank_data_scraper import DouyinPlayVVScraper
# 配置日志的函数 # 配置日志的函数
def setup_logging(quiet_mode=False): def setup_logging():
"""设置日志配置""" """设置日志配置"""
# 确保logs目录存在 # 确保logs目录存在
import os
script_dir = os.path.dirname(os.path.abspath(__file__)) script_dir = os.path.dirname(os.path.abspath(__file__))
logs_dir = os.path.join(script_dir, 'handlers', 'Rankings', 'logs') logs_dir = os.path.join(script_dir, 'handlers', 'Rankings', 'logs')
os.makedirs(logs_dir, exist_ok=True) os.makedirs(logs_dir, exist_ok=True)
# 在安静模式下只记录WARNING及以上级别的日志到控制台
console_level = logging.WARNING if quiet_mode else logging.INFO
logging.basicConfig( logging.basicConfig(
level=logging.INFO, # 文件日志仍然记录所有INFO级别 level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s', format='%(asctime)s - %(levelname)s - %(message)s',
handlers=[ handlers=[
logging.FileHandler(os.path.join(logs_dir, 'scheduler.log'), encoding='utf-8'), logging.FileHandler(os.path.join(logs_dir, 'scheduler.log'), encoding='utf-8'),
logging.StreamHandler() logging.StreamHandler()
] ]
) )
# 如果是安静模式,调整控制台处理器的级别
if quiet_mode:
for handler in logging.getLogger().handlers:
if isinstance(handler, logging.StreamHandler) and not isinstance(handler, logging.FileHandler):
handler.setLevel(console_level)
class DouyinAutoScheduler: class DouyinAutoScheduler:
def __init__(self): def __init__(self):
self.is_running = False self.is_running = False
def _normalize_play_vv(self, play_vv):
"""标准化播放量数据类型,将字符串转换为数字"""
if isinstance(play_vv, str):
try:
return int(play_vv.replace(',', '').replace('', '0000').replace('亿', '00000000'))
except:
return 0
elif not isinstance(play_vv, (int, float)):
return 0
return play_vv
def _deduplicate_videos_by_mix_name(self, videos, include_rank=False):
"""按短剧名称去重,保留播放量最高的记录"""
unique_data = {}
for video in videos:
mix_name = video.get("mix_name", "")
if mix_name:
# 标准化播放量数据类型
play_vv = self._normalize_play_vv(video.get("play_vv", 0))
if mix_name not in unique_data or play_vv > unique_data[mix_name].get("play_vv", 0):
if include_rank:
# 用于昨天数据的格式
unique_data[mix_name] = {
"play_vv": play_vv,
"video_id": str(video.get("_id", "")),
"rank": 0 # 稍后计算排名
}
else:
# 用于今天数据的格式,直接更新原视频对象
video["play_vv"] = play_vv
unique_data[mix_name] = video
return unique_data
def run_douyin_scraper(self): def run_douyin_scraper(self):
"""执行抖音播放量抓取任务""" """执行抖音播放量抓取任务"""
try: try:
logging.warning("🚀 开始执行抖音播放量抓取任务...") logging.info("🚀 开始执行抖音播放量抓取任务...")
# 设置环境变量,确保自动模式 # 设置环境变量,确保自动模式
os.environ['AUTO_CONTINUE'] = '1' os.environ['AUTO_CONTINUE'] = '1'
# 设置定时器模式环境变量,跳过评论抓取等函数
os.environ['TIMER_MODE'] = '1'
# 直接创建并运行 DouyinPlayVVScraper 实例 # 直接创建并运行 DouyinPlayVVScraper 实例
scraper = DouyinPlayVVScraper( scraper = DouyinPlayVVScraper(
@ -110,10 +70,10 @@ class DouyinAutoScheduler:
auto_continue=True, auto_continue=True,
duration_s=60 duration_s=60
) )
logging.info("📁 开始执行抓取任务...") logging.info("📁 开始执行抓取任务...")
scraper.run() scraper.run()
logging.info("✅ 抖音播放量抓取任务执行成功") logging.info("✅ 抖音播放量抓取任务执行成功")
# 数据抓取完成后,自动生成当日榜单 # 数据抓取完成后,自动生成当日榜单
@ -162,7 +122,7 @@ class DouyinAutoScheduler:
today_videos_raw = list(douyin_collection.find({"batch_time": latest_batch_time}).sort("play_vv", -1)) today_videos_raw = list(douyin_collection.find({"batch_time": latest_batch_time}).sort("play_vv", -1))
logging.info(f"📊 最新批次数据数量: {len(today_videos_raw)}") logging.info(f"📊 最新批次数据数量: {len(today_videos_raw)}")
# 按短剧名称去重,每个短剧只保留播放量最高的一条 # 按短剧名称去重(虽然同一批次应该不会有重复,但为了代码健壮性保留此逻辑)
unique_videos = {} unique_videos = {}
for video in today_videos_raw: for video in today_videos_raw:
mix_name = video.get("mix_name", "") mix_name = video.get("mix_name", "")
@ -173,24 +133,34 @@ class DouyinAutoScheduler:
logging.info(f"📊 今日数据去重后:{len(today_videos)} 个独特短剧(原始数据:{len(today_videos_raw)} 条)") logging.info(f"📊 今日数据去重后:{len(today_videos)} 个独特短剧(原始数据:{len(today_videos_raw)} 条)")
# 获取昨天的榜单数据(如果存在),取最新的计算结果 # 获取昨天最后一批次的数据
yesterday_ranking = rankings_collection.find_one({ yesterday_batch = douyin_collection.find_one({
"date": yesterday_str, "batch_time": {"$regex": f"^{yesterday_str}"}
"type": "comprehensive" }, sort=[("batch_time", -1)])
}, sort=[("calculation_sequence", -1)])
yesterday_data = {} yesterday_data = {}
if yesterday_ranking and "data" in yesterday_ranking: if yesterday_batch:
# 将昨天的数据转换为字典,以短剧名称为键 # 获取昨天最后一批次的所有数据
for item in yesterday_ranking["data"]: yesterday_videos = list(douyin_collection.find({
title = item.get("title", "") "batch_time": yesterday_batch["batch_time"]
if title: }).sort("play_vv", -1))
yesterday_data[title] = {
"rank": item.get("rank", 0), # 按短剧名称去重,保留播放量最高的记录
"play_vv": item.get("play_vv", 0), for video in yesterday_videos:
"video_id": item.get("video_id", "") mix_name = video.get("mix_name", "")
if mix_name and (mix_name not in yesterday_data or video.get("play_vv", 0) > yesterday_data[mix_name].get("play_vv", 0)):
yesterday_data[mix_name] = {
"play_vv": video.get("play_vv", 0),
"video_id": str(video.get("_id", "")),
"rank": 0 # 稍后计算排名
} }
logging.info(f"📊 找到昨天的榜单数据,共 {len(yesterday_data)} 个短剧")
# 计算排名
sorted_videos = sorted(yesterday_data.items(), key=lambda x: x[1]["play_vv"], reverse=True)
for rank, (mix_name, data) in enumerate(sorted_videos, 1):
yesterday_data[mix_name]["rank"] = rank
logging.info(f"📊 找到昨天的原始数据,共 {len(yesterday_data)} 个短剧")
else: else:
logging.info("📊 未找到昨天的原始数据,将作为首次生成") logging.info("📊 未找到昨天的原始数据,将作为首次生成")
@ -367,6 +337,8 @@ class DouyinAutoScheduler:
def main(): def main():
"""主函数""" """主函数"""
import argparse
try: try:
parser = argparse.ArgumentParser(description='抖音播放量自动抓取定时器') parser = argparse.ArgumentParser(description='抖音播放量自动抓取定时器')
parser.add_argument('--test', action='store_true', help='测试模式 - 立即执行一次') parser.add_argument('--test', action='store_true', help='测试模式 - 立即执行一次')
@ -375,51 +347,23 @@ def main():
args = parser.parse_args() args = parser.parse_args()
# 设置日志配置 - 只在定时器模式下启用静默模式 # 设置日志配置
quiet_mode = not (args.test or args.once or args.ranking_only) setup_logging()
setup_logging(quiet_mode=quiet_mode)
print("正在初始化定时器...") print("正在初始化定时器...")
scheduler = DouyinAutoScheduler() scheduler = DouyinAutoScheduler()
if args.test: if args.test:
scheduler._is_timer_mode = False
print("执行测试模式...") print("执行测试模式...")
scheduler.run_test() scheduler.run_test()
elif args.once: elif args.once:
scheduler._is_timer_mode = False
print("执行单次模式...") print("执行单次模式...")
scheduler.run_once() scheduler.run_once()
elif args.ranking_only: elif args.ranking_only:
scheduler._is_timer_mode = False
print("执行榜单生成模式...") print("执行榜单生成模式...")
scheduler.run_ranking_only() scheduler.run_ranking_only()
else: else:
scheduler._is_timer_mode = True
print("启动定时器模式...") print("启动定时器模式...")
# 显示定时器信息使用print确保能看到
from datetime import datetime
current_time = datetime.now()
print(f"🕐 当前时间:{current_time.strftime('%Y-%m-%d %H:%M:%S')}")
print(f"⏰ 执行规则:每小时整点执行抖音播放量抓取")
# 计算下次执行时间
next_hour = current_time.replace(minute=0, second=0, microsecond=0)
if current_time.minute > 0 or current_time.second > 0:
next_hour = next_hour.replace(hour=next_hour.hour + 1)
if next_hour.hour >= 24:
from datetime import timedelta
next_hour = next_hour.replace(hour=0) + timedelta(days=1)
wait_seconds = (next_hour - current_time).total_seconds()
wait_minutes = int(wait_seconds // 60)
print(f"⏰ 下次执行时间:{next_hour.strftime('%Y-%m-%d %H:%M:%S')}")
print(f"⏳ 距离下次执行:{wait_minutes} 分钟 ({int(wait_seconds)} 秒)")
print("💡 定时器正在等待中,将在整点自动执行任务...")
print("⏹️ 按 Ctrl+C 停止定时器")
scheduler.setup_schedule() scheduler.setup_schedule()
scheduler.start_scheduler() scheduler.start_scheduler()

View File

@ -1,43 +0,0 @@
{
"episodes": [
{
"video_id": "7389531100718107954",
"episode_num": 0
},
{
"video_id": "7393209049208130851",
"episode_num": 0
},
{
"video_id": "7398121035452763432",
"episode_num": 0
},
{
"video_id": "7404808266888252698",
"episode_num": 0
},
{
"video_id": "7410761253204905235",
"episode_num": 0
},
{
"video_id": "7416596680776158515",
"episode_num": 0
},
{
"video_id": "7426956763892665654",
"episode_num": 0
},
{
"video_id": "7429208304389328180",
"episode_num": 0
},
{
"video_id": "7429519648518966555",
"episode_num": 0
}
],
"total_count": 9,
"last_update": "2025-10-22T09:55:41.380145",
"mix_name": "觉醒"
}

View File

@ -1,123 +0,0 @@
{
"episodes": [
{
"video_id": "7421044063190699303",
"episode_num": 0
},
{
"video_id": "7425556502057897270",
"episode_num": 0
},
{
"video_id": "7428086785537821963",
"episode_num": 0
},
{
"video_id": "7438273827555134774",
"episode_num": 0
},
{
"video_id": "7431047488955632907",
"episode_num": 0
},
{
"video_id": "7434029345796066623",
"episode_num": 0
},
{
"video_id": "7438157166382550313",
"episode_num": 0
},
{
"video_id": "7445146231225077003",
"episode_num": 0
},
{
"video_id": "7448086473322106152",
"episode_num": 0
},
{
"video_id": "7451825341225585954",
"episode_num": 0
},
{
"video_id": "7463783714389085476",
"episode_num": 0
},
{
"video_id": "7461502376516586752",
"episode_num": 0
},
{
"video_id": "7471109492738952483",
"episode_num": 0
},
{
"video_id": "7473376886383512884",
"episode_num": 0
},
{
"video_id": "7476035323416415542",
"episode_num": 0
},
{
"video_id": "7477826100815514889",
"episode_num": 0
},
{
"video_id": "7480121799733202186",
"episode_num": 0
},
{
"video_id": "7482669047008611610",
"episode_num": 0
},
{
"video_id": "7483737890845920549",
"episode_num": 0
},
{
"video_id": "7486742756103130394",
"episode_num": 0
},
{
"video_id": "7487446983901269274",
"episode_num": 0
},
{
"video_id": "7488238211139996978",
"episode_num": 0
},
{
"video_id": "7489006391865216265",
"episode_num": 0
},
{
"video_id": "7493926858061352202",
"episode_num": 0
},
{
"video_id": "7498645852182203700",
"episode_num": 0
},
{
"video_id": "7502686428054244660",
"episode_num": 0
},
{
"video_id": "7504263612656078116",
"episode_num": 0
},
{
"video_id": "7509429118845340982",
"episode_num": 0
},
{
"video_id": "7509743276300291340",
"episode_num": 0
}
],
"total_count": 29,
"last_update": "2025-10-22T09:56:01.930652",
"mix_name": "《田螺姑娘》系列短剧"
}

View File

@ -1,51 +0,0 @@
{
"episodes": [
{
"video_id": "7472763101620751626",
"episode_num": 0
},
{
"video_id": "7472763403182886156",
"episode_num": 0
},
{
"video_id": "7472763009627065619",
"episode_num": 0
},
{
"video_id": "7472764867905195327",
"episode_num": 0
},
{
"video_id": "7472763523450293516",
"episode_num": 0
},
{
"video_id": "7472763290104450315",
"episode_num": 0
},
{
"video_id": "7472762896833908031",
"episode_num": 0
},
{
"video_id": "7472763068376780071",
"episode_num": 0
},
{
"video_id": "7472763556648193334",
"episode_num": 0
},
{
"video_id": "7472763183409777939",
"episode_num": 0
},
{
"video_id": "7472763426813529380",
"episode_num": 0
}
],
"total_count": 11,
"last_update": "2025-10-22T09:56:08.613429",
"mix_name": "兴安岭诡事"
}

View File

@ -1,27 +0,0 @@
{
"episodes": [
{
"video_id": "7462779038784933158",
"episode_num": 0
},
{
"video_id": "7469001162868444443",
"episode_num": 0
},
{
"video_id": "7469998771519130889",
"episode_num": 0
},
{
"video_id": "7470709002284862720",
"episode_num": 0
},
{
"video_id": "7471924777410645283",
"episode_num": 0
}
],
"total_count": 5,
"last_update": "2025-10-22T09:55:36.943794",
"mix_name": "《青蛇传》"
}

View File

@ -1,123 +0,0 @@
{
"episodes": [
{
"video_id": "7438832661914717475",
"episode_num": 0
},
{
"video_id": "7441055420505918760",
"episode_num": 0
},
{
"video_id": "7441797752599711010",
"episode_num": 0
},
{
"video_id": "7444025334355201314",
"episode_num": 0
},
{
"video_id": "7444767906782514432",
"episode_num": 0
},
{
"video_id": "7445511144686587170",
"episode_num": 0
},
{
"video_id": "7448480282623216934",
"episode_num": 0
},
{
"video_id": "7449224455496256777",
"episode_num": 0
},
{
"video_id": "7449966534602018074",
"episode_num": 0
},
{
"video_id": "7452190854900370715",
"episode_num": 0
},
{
"video_id": "7452932931934342437",
"episode_num": 0
},
{
"video_id": "7453673782092303666",
"episode_num": 0
},
{
"video_id": "7454416566910864650",
"episode_num": 0
},
{
"video_id": "7458870546697080101",
"episode_num": 0
},
{
"video_id": "7459612621348572443",
"episode_num": 0
},
{
"video_id": "7460354830322699571",
"episode_num": 0
},
{
"video_id": "7461097063850249499",
"episode_num": 0
},
{
"video_id": "7461840320993463590",
"episode_num": 0
},
{
"video_id": "7462583778557349147",
"episode_num": 0
},
{
"video_id": "7463322906186091813",
"episode_num": 0
},
{
"video_id": "7467405224320322854",
"episode_num": 0
},
{
"video_id": "7468147493620960549",
"episode_num": 0
},
{
"video_id": "7468887846011653402",
"episode_num": 0
},
{
"video_id": "7469630119456361779",
"episode_num": 0
},
{
"video_id": "7471114379258318106",
"episode_num": 0
},
{
"video_id": "7471856794772491547",
"episode_num": 0
},
{
"video_id": "7472598861073157403",
"episode_num": 0
},
{
"video_id": "7473341167099186441",
"episode_num": 0
},
{
"video_id": "7474085833558052159",
"episode_num": 0
}
],
"total_count": 29,
"last_update": "2025-10-22T09:55:53.324636",
"mix_name": "我在地府开当铺"
}

View File

@ -1,87 +0,0 @@
{
"episodes": [
{
"video_id": "7472623062152695074",
"episode_num": 0
},
{
"video_id": "7457112388907666727",
"episode_num": 0
},
{
"video_id": "7457505550188743973",
"episode_num": 0
},
{
"video_id": "7457874864729345318",
"episode_num": 0
},
{
"video_id": "7458965679874542858",
"episode_num": 0
},
{
"video_id": "7459348765586001178",
"episode_num": 0
},
{
"video_id": "7459760717202345254",
"episode_num": 0
},
{
"video_id": "7460119944940883227",
"episode_num": 0
},
{
"video_id": "7460847335602490675",
"episode_num": 0
},
{
"video_id": "7461235696414559514",
"episode_num": 0
},
{
"video_id": "7461939199000825151",
"episode_num": 0
},
{
"video_id": "7462718793974910271",
"episode_num": 0
},
{
"video_id": "7463090318058081555",
"episode_num": 0
},
{
"video_id": "7463442602558246207",
"episode_num": 0
},
{
"video_id": "7464950323786861874",
"episode_num": 0
},
{
"video_id": "7466027689028193574",
"episode_num": 0
},
{
"video_id": "7467918209505676585",
"episode_num": 0
},
{
"video_id": "7469002478999096610",
"episode_num": 0
},
{
"video_id": "7471609858727447808",
"episode_num": 0
},
{
"video_id": "7472348174464650536",
"episode_num": 0
}
],
"total_count": 20,
"last_update": "2025-10-22T09:56:14.396524",
"mix_name": "《鲛人珠》"
}

View File

@ -1,47 +0,0 @@
{
"episodes": [
{
"video_id": "7445594903796518201",
"episode_num": 0
},
{
"video_id": "7446432501297384763",
"episode_num": 0
},
{
"video_id": "7454551962659376443",
"episode_num": 0
},
{
"video_id": "7461234093703875898",
"episode_num": 0
},
{
"video_id": "7466059018256026940",
"episode_num": 0
},
{
"video_id": "7471994773054819641",
"episode_num": 0
},
{
"video_id": "7474591461695147324",
"episode_num": 0
},
{
"video_id": "7477189231987772729",
"episode_num": 0
},
{
"video_id": "7478673086884187449",
"episode_num": 0
},
{
"video_id": "7482757832807386426",
"episode_num": 0
}
],
"total_count": 10,
"last_update": "2025-10-22T09:55:40.776573",
"mix_name": "中式百妖集·白骨夫人"
}

View File

@ -1,79 +0,0 @@
{
"episodes": [
{
"video_id": "7484932173439536421",
"episode_num": 0
},
{
"video_id": "7485664110688898343",
"episode_num": 0
},
{
"video_id": "7486419411969068314",
"episode_num": 0
},
{
"video_id": "7487121293100305718",
"episode_num": 0
},
{
"video_id": "7487526141658467620",
"episode_num": 0
},
{
"video_id": "7488271435824123173",
"episode_num": 0
},
{
"video_id": "7488650316636917044",
"episode_num": 0
},
{
"video_id": "7489021106041392418",
"episode_num": 0
},
{
"video_id": "7489378816629001510",
"episode_num": 0
},
{
"video_id": "7489762229294730530",
"episode_num": 0
},
{
"video_id": "7490506362162580771",
"episode_num": 0
},
{
"video_id": "7491612455748128063",
"episode_num": 0
},
{
"video_id": "7492356791385214249",
"episode_num": 0
},
{
"video_id": "7493098513320938764",
"episode_num": 0
},
{
"video_id": "7493470039182445843",
"episode_num": 0
},
{
"video_id": "7494213861059579170",
"episode_num": 0
},
{
"video_id": "7494607366281809179",
"episode_num": 0
},
{
"video_id": "7496444061780299017",
"episode_num": 0
}
],
"total_count": 18,
"last_update": "2025-10-22T09:56:10.891927",
"mix_name": "忘川引"
}

View File

@ -1,151 +0,0 @@
{
"episodes": [
{
"video_id": "7508787409220308287",
"episode_num": 0
},
{
"video_id": "7510681348156214582",
"episode_num": 0
},
{
"video_id": "7511991741650701607",
"episode_num": 0
},
{
"video_id": "7513617213908159783",
"episode_num": 0
},
{
"video_id": "7514504440183885067",
"episode_num": 0
},
{
"video_id": "7515713983450451211",
"episode_num": 0
},
{
"video_id": "7516611820073930020",
"episode_num": 0
},
{
"video_id": "7517661121336184127",
"episode_num": 0
},
{
"video_id": "7518746065160424743",
"episode_num": 0
},
{
"video_id": "7519749002439429417",
"episode_num": 0
},
{
"video_id": "7520472849899932964",
"episode_num": 0
},
{
"video_id": "7521204206330547497",
"episode_num": 0
},
{
"video_id": "7524573752886054196",
"episode_num": 0
},
{
"video_id": "7530578815811128603",
"episode_num": 0
},
{
"video_id": "7531758004685901065",
"episode_num": 0
},
{
"video_id": "7532765269714816306",
"episode_num": 0
},
{
"video_id": "7535386089935129871",
"episode_num": 0
},
{
"video_id": "7537427761216998708",
"episode_num": 0
},
{
"video_id": "7538524602385878324",
"episode_num": 0
},
{
"video_id": "7540051891523177737",
"episode_num": 0
},
{
"video_id": "7541107806611475752",
"episode_num": 0
},
{
"video_id": "7541853195853712640",
"episode_num": 0
},
{
"video_id": "7542682704836332835",
"episode_num": 0
},
{
"video_id": "7543822135823830287",
"episode_num": 0
},
{
"video_id": "7544261185663798555",
"episode_num": 0
},
{
"video_id": "7544908029926313225",
"episode_num": 0
},
{
"video_id": "7545999867550747914",
"episode_num": 0
},
{
"video_id": "7548507331529657626",
"episode_num": 0
},
{
"video_id": "7550700558206635274",
"episode_num": 0
},
{
"video_id": "7551695429147086126",
"episode_num": 0
},
{
"video_id": "7552568123484900646",
"episode_num": 0
},
{
"video_id": "7552961927568313609",
"episode_num": 0
},
{
"video_id": "7553727704906943771",
"episode_num": 0
},
{
"video_id": "7555956738030177562",
"episode_num": 0
},
{
"video_id": "7557016037955325194",
"episode_num": 0
},
{
"video_id": "7558378239337467174",
"episode_num": 0
}
],
"total_count": 36,
"last_update": "2025-10-22T09:55:32.073567",
"mix_name": "末世系列"
}

View File

@ -1,47 +0,0 @@
{
"episodes": [
{
"video_id": "7488147760089287973",
"episode_num": 0
},
{
"video_id": "7488147616237096219",
"episode_num": 0
},
{
"video_id": "7488146990686014757",
"episode_num": 0
},
{
"video_id": "7488146612695485706",
"episode_num": 0
},
{
"video_id": "7488145907737775369",
"episode_num": 0
},
{
"video_id": "7488510699275029810",
"episode_num": 0
},
{
"video_id": "7488511105959071013",
"episode_num": 0
},
{
"video_id": "7488511733053607177",
"episode_num": 0
},
{
"video_id": "7488885747047468315",
"episode_num": 0
},
{
"video_id": "7488885905084714249",
"episode_num": 0
}
],
"total_count": 10,
"last_update": "2025-10-22T09:56:06.856199",
"mix_name": "全国首部奇幻探秘Al微短剧"
}

View File

@ -1,143 +0,0 @@
{
"episodes": [
{
"video_id": "7486805231804681530",
"episode_num": 0
},
{
"video_id": "7487578743611985210",
"episode_num": 0
},
{
"video_id": "7488320388464774460",
"episode_num": 0
},
{
"video_id": "7489343145566555449",
"episode_num": 0
},
{
"video_id": "7490919031881469241",
"episode_num": 0
},
{
"video_id": "7491659592909327675",
"episode_num": 0
},
{
"video_id": "7492774825606483258",
"episode_num": 0
},
{
"video_id": "7495283384688594233",
"episode_num": 0
},
{
"video_id": "7496485765267754300",
"episode_num": 0
},
{
"video_id": "7497545408492014905",
"episode_num": 0
},
{
"video_id": "7499453865651014971",
"episode_num": 0
},
{
"video_id": "7500569260890099004",
"episode_num": 0
},
{
"video_id": "7502050015763189050",
"episode_num": 0
},
{
"video_id": "7502796678514642233",
"episode_num": 0
},
{
"video_id": "7505018729597963577",
"episode_num": 0
},
{
"video_id": "7505763063816670521",
"episode_num": 0
},
{
"video_id": "7507631537329458490",
"episode_num": 0
},
{
"video_id": "7508730844816280890",
"episode_num": 0
},
{
"video_id": "7513187407958150460",
"episode_num": 0
},
{
"video_id": "7516524242646125884",
"episode_num": 0
},
{
"video_id": "7518011787930520889",
"episode_num": 0
},
{
"video_id": "7520976901600447801",
"episode_num": 0
},
{
"video_id": "7537305227914546490",
"episode_num": 0
},
{
"video_id": "7546210488913595705",
"episode_num": 0
},
{
"video_id": "7546922516716539196",
"episode_num": 0
},
{
"video_id": "7547625203083185468",
"episode_num": 0
},
{
"video_id": "7549924545768295739",
"episode_num": 0
},
{
"video_id": "7553215200825134394",
"episode_num": 0
},
{
"video_id": "7554737168394374459",
"episode_num": 0
},
{
"video_id": "7555479694759284027",
"episode_num": 0
},
{
"video_id": "7556555317988724026",
"episode_num": 0
},
{
"video_id": "7562121519012285755",
"episode_num": 0
},
{
"video_id": "7563238756892757307",
"episode_num": 0
},
{
"video_id": "7564756828878753061",
"episode_num": 0
}
],
"total_count": 34,
"last_update": "2025-10-26T14:48:56.017802",
"mix_name": "【中式百妖集·阴医】"
}

View File

@ -1,67 +0,0 @@
{
"episodes": [
{
"video_id": "7498696558876331318",
"episode_num": 0
},
{
"video_id": "7498696627905940747",
"episode_num": 0
},
{
"video_id": "7498696682746514751",
"episode_num": 0
},
{
"video_id": "7498696464852471051",
"episode_num": 0
},
{
"video_id": "7498991164272479551",
"episode_num": 0
},
{
"video_id": "7499073383687114024",
"episode_num": 0
},
{
"video_id": "7499073497541528867",
"episode_num": 0
},
{
"video_id": "7499073601295944975",
"episode_num": 0
},
{
"video_id": "7499073974123498804",
"episode_num": 0
},
{
"video_id": "7499074026569059599",
"episode_num": 0
},
{
"video_id": "7499074347429006626",
"episode_num": 0
},
{
"video_id": "7499074195519802658",
"episode_num": 0
},
{
"video_id": "7501976370621287718",
"episode_num": 0
},
{
"video_id": "7502295085464227082",
"episode_num": 0
},
{
"video_id": "7502419858789911846",
"episode_num": 0
}
],
"total_count": 15,
"last_update": "2025-10-22T09:55:36.327209",
"mix_name": "盲盒千岁"
}

View File

@ -1,47 +0,0 @@
{
"episodes": [
{
"video_id": "7504244447165615360",
"episode_num": 0
},
{
"video_id": "7504244610508524834",
"episode_num": 0
},
{
"video_id": "7504244482838138147",
"episode_num": 0
},
{
"video_id": "7504244233549761844",
"episode_num": 0
},
{
"video_id": "7504244628758007040",
"episode_num": 0
},
{
"video_id": "7504244597929889076",
"episode_num": 0
},
{
"video_id": "7504244625457024296",
"episode_num": 0
},
{
"video_id": "7504244460637654307",
"episode_num": 0
},
{
"video_id": "7504244631295528227",
"episode_num": 0
},
{
"video_id": "7504244436004654371",
"episode_num": 0
}
],
"total_count": 10,
"last_update": "2025-10-22T09:55:42.069016",
"mix_name": "白骨精传奇"
}

View File

@ -1,155 +0,0 @@
{
"episodes": [
{
"video_id": "7506067244128963892",
"episode_num": 0
},
{
"video_id": "7506450698897296692",
"episode_num": 0
},
{
"video_id": "7506711648292375846",
"episode_num": 0
},
{
"video_id": "7508950346337815817",
"episode_num": 0
},
{
"video_id": "7509774388443499803",
"episode_num": 0
},
{
"video_id": "7510136494552550697",
"episode_num": 0
},
{
"video_id": "7511916836351511862",
"episode_num": 0
},
{
"video_id": "7514267874987363618",
"episode_num": 0
},
{
"video_id": "7514880725972225319",
"episode_num": 0
},
{
"video_id": "7516734442199682339",
"episode_num": 0
},
{
"video_id": "7517445470608690447",
"episode_num": 0
},
{
"video_id": "7517854243118730536",
"episode_num": 0
},
{
"video_id": "7519774016958172443",
"episode_num": 0
},
{
"video_id": "7520504060600929571",
"episode_num": 0
},
{
"video_id": "7521579659352395062",
"episode_num": 0
},
{
"video_id": "7522327810527055143",
"episode_num": 0
},
{
"video_id": "7524266961459481891",
"episode_num": 0
},
{
"video_id": "7524619540563512616",
"episode_num": 0
},
{
"video_id": "7525332357025402151",
"episode_num": 0
},
{
"video_id": "7527197348515171584",
"episode_num": 0
},
{
"video_id": "7527580712619363618",
"episode_num": 0
},
{
"video_id": "7527875102319316258",
"episode_num": 0
},
{
"video_id": "7529722113029147944",
"episode_num": 0
},
{
"video_id": "7529741695441833268",
"episode_num": 0
},
{
"video_id": "7530556459571039507",
"episode_num": 0
},
{
"video_id": "7532003677117091107",
"episode_num": 0
},
{
"video_id": "7533520661294239012",
"episode_num": 0
},
{
"video_id": "7534591926373190912",
"episode_num": 0
},
{
"video_id": "7535986779401325843",
"episode_num": 0
},
{
"video_id": "7538632635627703606",
"episode_num": 0
},
{
"video_id": "7538634729889877290",
"episode_num": 0
},
{
"video_id": "7540121743873035555",
"episode_num": 0
},
{
"video_id": "7540870569168784655",
"episode_num": 0
},
{
"video_id": "7542402995653283112",
"episode_num": 0
},
{
"video_id": "7546532809460976948",
"episode_num": 0
},
{
"video_id": "7547533101929467151",
"episode_num": 0
},
{
"video_id": "7547910476743609652",
"episode_num": 0
}
],
"total_count": 37,
"last_update": "2025-10-22T09:56:06.222702",
"mix_name": "九尾狐男妖爱上我"
}

View File

@ -1,235 +0,0 @@
{
"episodes": [
{
"video_id": "7506725945898847515",
"episode_num": 0
},
{
"video_id": "7506726188392402186",
"episode_num": 0
},
{
"video_id": "7506726062122929417",
"episode_num": 0
},
{
"video_id": "7506725983026777354",
"episode_num": 0
},
{
"video_id": "7506726108860124443",
"episode_num": 0
},
{
"video_id": "7506726665033223433",
"episode_num": 0
},
{
"video_id": "7506726346563800370",
"episode_num": 0
},
{
"video_id": "7506726016790940965",
"episode_num": 0
},
{
"video_id": "7506726671379221787",
"episode_num": 0
},
{
"video_id": "7506726090564586761",
"episode_num": 0
},
{
"video_id": "7506726187318725898",
"episode_num": 0
},
{
"video_id": "7506726296039230730",
"episode_num": 0
},
{
"video_id": "7506726309150592294",
"episode_num": 0
},
{
"video_id": "7506726284358094107",
"episode_num": 0
},
{
"video_id": "7506726237205777714",
"episode_num": 0
},
{
"video_id": "7506726182524685605",
"episode_num": 0
},
{
"video_id": "7506726228850674954",
"episode_num": 0
},
{
"video_id": "7506726166506605862",
"episode_num": 0
},
{
"video_id": "7506726208801901851",
"episode_num": 0
},
{
"video_id": "7506726298337758501",
"episode_num": 0
},
{
"video_id": "7506726295435218213",
"episode_num": 0
},
{
"video_id": "7506726377392016650",
"episode_num": 0
},
{
"video_id": "7506726273427754278",
"episode_num": 0
},
{
"video_id": "7506726355774524682",
"episode_num": 0
},
{
"video_id": "7506726266536594726",
"episode_num": 0
},
{
"video_id": "7506726314951462181",
"episode_num": 0
},
{
"video_id": "7506726196588203290",
"episode_num": 0
},
{
"video_id": "7506726170638028070",
"episode_num": 0
},
{
"video_id": "7506726491531660594",
"episode_num": 0
},
{
"video_id": "7506726608372239643",
"episode_num": 0
},
{
"video_id": "7506726485236141362",
"episode_num": 0
},
{
"video_id": "7506726498439564553",
"episode_num": 0
},
{
"video_id": "7506726478663486758",
"episode_num": 0
},
{
"video_id": "7506726546317659419",
"episode_num": 0
},
{
"video_id": "7506726541062130982",
"episode_num": 0
},
{
"video_id": "7506726526709157147",
"episode_num": 0
},
{
"video_id": "7506726570220883251",
"episode_num": 0
},
{
"video_id": "7506726627510897958",
"episode_num": 0
},
{
"video_id": "7506726589883747622",
"episode_num": 0
},
{
"video_id": "7506726632447593765",
"episode_num": 0
},
{
"video_id": "7506726607525039369",
"episode_num": 0
},
{
"video_id": "7506726659584822565",
"episode_num": 0
},
{
"video_id": "7506726454617525541",
"episode_num": 0
},
{
"video_id": "7506726418294869285",
"episode_num": 0
},
{
"video_id": "7506726571374333210",
"episode_num": 0
},
{
"video_id": "7506726517443956019",
"episode_num": 0
},
{
"video_id": "7506726555305905418",
"episode_num": 0
},
{
"video_id": "7506726472007109914",
"episode_num": 0
},
{
"video_id": "7506726648675323173",
"episode_num": 0
},
{
"video_id": "7506726475693919515",
"episode_num": 0
},
{
"video_id": "7506726506924739850",
"episode_num": 0
},
{
"video_id": "7506726523471220019",
"episode_num": 0
},
{
"video_id": "7506726476633476379",
"episode_num": 0
},
{
"video_id": "7506726532715433226",
"episode_num": 0
},
{
"video_id": "7506726554542640394",
"episode_num": 0
},
{
"video_id": "7506726533835410698",
"episode_num": 0
},
{
"video_id": "7506726608326118683",
"episode_num": 0
}
],
"total_count": 57,
"last_update": "2025-10-22T09:55:59.359473",
"mix_name": "如意坊"
}

View File

@ -1,55 +0,0 @@
{
"episodes": [
{
"video_id": "7549025803313384746",
"episode_num": 0
},
{
"video_id": "7549025817850826003",
"episode_num": 0
},
{
"video_id": "7549025811861409043",
"episode_num": 0
},
{
"video_id": "7549025819251756342",
"episode_num": 0
},
{
"video_id": "7549025818131893547",
"episode_num": 0
},
{
"video_id": "7549025828185705767",
"episode_num": 0
},
{
"video_id": "7549025818874252563",
"episode_num": 0
},
{
"video_id": "7549025854819405097",
"episode_num": 0
},
{
"video_id": "7549025851971521828",
"episode_num": 0
},
{
"video_id": "7549025854999891239",
"episode_num": 0
},
{
"video_id": "7549025873840590134",
"episode_num": 0
},
{
"video_id": "7549025884955577643",
"episode_num": 0
}
],
"total_count": 12,
"last_update": "2025-10-22T09:55:37.752763",
"mix_name": "新平妖传"
}

View File

@ -1,83 +0,0 @@
{
"episodes": [
{
"video_id": "7517472781332696332",
"episode_num": 0
},
{
"video_id": "7517971761476979980",
"episode_num": 0
},
{
"video_id": "7518395078306483510",
"episode_num": 0
},
{
"video_id": "7518867709761686803",
"episode_num": 0
},
{
"video_id": "7519654070961949988",
"episode_num": 0
},
{
"video_id": "7520748725438811446",
"episode_num": 0
},
{
"video_id": "7521798836566641983",
"episode_num": 0
},
{
"video_id": "7529928581993041215",
"episode_num": 0
},
{
"video_id": "7530321831966805284",
"episode_num": 0
},
{
"video_id": "7531079565049941289",
"episode_num": 0
},
{
"video_id": "7532255656586399017",
"episode_num": 0
},
{
"video_id": "7533366600439762195",
"episode_num": 0
},
{
"video_id": "7534435304296516918",
"episode_num": 0
},
{
"video_id": "7535534271813979431",
"episode_num": 0
},
{
"video_id": "7536713189078175016",
"episode_num": 0
},
{
"video_id": "7538565796382002467",
"episode_num": 0
},
{
"video_id": "7538868180136037647",
"episode_num": 0
},
{
"video_id": "7540042632618167592",
"episode_num": 0
},
{
"video_id": "7543715550619241743",
"episode_num": 0
}
],
"total_count": 19,
"last_update": "2025-10-22T09:55:49.993319",
"mix_name": "苏祥云"
}

View File

@ -1,19 +0,0 @@
{
"episodes": [
{
"video_id": "7527336931760295168",
"episode_num": 0
},
{
"video_id": "7529100313467325711",
"episode_num": 0
},
{
"video_id": "7539690162612079872",
"episode_num": 0
}
],
"total_count": 3,
"last_update": "2025-10-22T09:55:17.087205",
"mix_name": "《小宝穿越|课本古诗文》"
}

View File

@ -1,19 +0,0 @@
{
"episodes": [
{
"video_id": "7476841679304051968",
"episode_num": 0
},
{
"video_id": "7519893460598541609",
"episode_num": 0
},
{
"video_id": "7548075831491415359",
"episode_num": 0
}
],
"total_count": 3,
"last_update": "2025-10-22T09:56:11.433105",
"mix_name": "僵尸师姐"
}

View File

@ -1,55 +0,0 @@
{
"episodes": [
{
"video_id": "7529542793484815642",
"episode_num": 0
},
{
"video_id": "7529837310423190825",
"episode_num": 0
},
{
"video_id": "7530392006963498279",
"episode_num": 0
},
{
"video_id": "7531919686112529716",
"episode_num": 0
},
{
"video_id": "7533566057529740559",
"episode_num": 0
},
{
"video_id": "7536843946534669631",
"episode_num": 0
},
{
"video_id": "7538371048060898600",
"episode_num": 0
},
{
"video_id": "7540606531264433418",
"episode_num": 0
},
{
"video_id": "7542079999621319986",
"episode_num": 0
},
{
"video_id": "7543609660469824822",
"episode_num": 0
},
{
"video_id": "7546200368829484339",
"episode_num": 0
},
{
"video_id": "7548447317729234239",
"episode_num": 0
}
],
"total_count": 12,
"last_update": "2025-10-22T09:55:50.726907",
"mix_name": "青云修仙传"
}

View File

@ -1,195 +0,0 @@
{
"episodes": [
{
"video_id": "7533908493456182538",
"episode_num": 0
},
{
"video_id": "7534294543475150118",
"episode_num": 0
},
{
"video_id": "7534686345395014950",
"episode_num": 0
},
{
"video_id": "7535429627486031144",
"episode_num": 0
},
{
"video_id": "7535787648519097634",
"episode_num": 0
},
{
"video_id": "7536148527018167604",
"episode_num": 0
},
{
"video_id": "7536756145902374159",
"episode_num": 0
},
{
"video_id": "7536916803734359296",
"episode_num": 0
},
{
"video_id": "7537291155520621858",
"episode_num": 0
},
{
"video_id": "7537711561570290998",
"episode_num": 0
},
{
"video_id": "7538026362255281447",
"episode_num": 0
},
{
"video_id": "7538291293873556778",
"episode_num": 0
},
{
"video_id": "7538394363068452115",
"episode_num": 0
},
{
"video_id": "7538755908755590463",
"episode_num": 0
},
{
"video_id": "7539159291803045159",
"episode_num": 0
},
{
"video_id": "7539494201172512063",
"episode_num": 0
},
{
"video_id": "7539497676841241898",
"episode_num": 0
},
{
"video_id": "7539878435678653750",
"episode_num": 0
},
{
"video_id": "7541743859181636910",
"episode_num": 0
},
{
"video_id": "7542114403907308810",
"episode_num": 0
},
{
"video_id": "7542826819817377070",
"episode_num": 0
},
{
"video_id": "7542829529639734574",
"episode_num": 0
},
{
"video_id": "7543242228785876275",
"episode_num": 0
},
{
"video_id": "7543611905496059174",
"episode_num": 0
},
{
"video_id": "7543976834791165210",
"episode_num": 0
},
{
"video_id": "7544364656991784219",
"episode_num": 0
},
{
"video_id": "7545110659919383859",
"episode_num": 0
},
{
"video_id": "7545458257129655567",
"episode_num": 0
},
{
"video_id": "7545864375643409704",
"episode_num": 0
},
{
"video_id": "7546225454894599464",
"episode_num": 0
},
{
"video_id": "7546575160715889966",
"episode_num": 0
},
{
"video_id": "7546934519836806409",
"episode_num": 0
},
{
"video_id": "7547336647730335027",
"episode_num": 0
},
{
"video_id": "7547711167158897958",
"episode_num": 0
},
{
"video_id": "7548073308894317875",
"episode_num": 0
},
{
"video_id": "7548371214998244658",
"episode_num": 0
},
{
"video_id": "7548819838773349670",
"episode_num": 0
},
{
"video_id": "7549193055358733606",
"episode_num": 0
},
{
"video_id": "7549574668735270190",
"episode_num": 0
},
{
"video_id": "7549952043016883502",
"episode_num": 0
},
{
"video_id": "7550323254922202378",
"episode_num": 0
},
{
"video_id": "7550694134588263720",
"episode_num": 0
},
{
"video_id": "7551058050275167540",
"episode_num": 0
},
{
"video_id": "7551425021642607906",
"episode_num": 0
},
{
"video_id": "7551790578816552226",
"episode_num": 0
},
{
"video_id": "7555439509588938024",
"episode_num": 0
},
{
"video_id": "7555845189366074662",
"episode_num": 0
}
],
"total_count": 47,
"last_update": "2025-10-22T09:55:27.641577",
"mix_name": "《风水之王》"
}

View File

@ -1,279 +0,0 @@
{
"episodes": [
{
"video_id": "7535701272712777002",
"episode_num": 0
},
{
"video_id": "7535701290232401194",
"episode_num": 0
},
{
"video_id": "7535701286658821430",
"episode_num": 0
},
{
"video_id": "7535701275858570532",
"episode_num": 0
},
{
"video_id": "7535701262310985003",
"episode_num": 0
},
{
"video_id": "7535701270364048682",
"episode_num": 0
},
{
"video_id": "7535701309303901481",
"episode_num": 0
},
{
"video_id": "7535701337573461289",
"episode_num": 0
},
{
"video_id": "7535701337984519460",
"episode_num": 0
},
{
"video_id": "7535701328048311571",
"episode_num": 0
},
{
"video_id": "7535701353595800874",
"episode_num": 0
},
{
"video_id": "7535701350357699903",
"episode_num": 0
},
{
"video_id": "7535701363007769898",
"episode_num": 0
},
{
"video_id": "7535701370368691492",
"episode_num": 0
},
{
"video_id": "7535701350932335911",
"episode_num": 0
},
{
"video_id": "7535701373900377385",
"episode_num": 0
},
{
"video_id": "7535701392267283775",
"episode_num": 0
},
{
"video_id": "7535701391872888106",
"episode_num": 0
},
{
"video_id": "7535701400672619795",
"episode_num": 0
},
{
"video_id": "7535701415142935827",
"episode_num": 0
},
{
"video_id": "7535701423242120484",
"episode_num": 0
},
{
"video_id": "7535701444511403305",
"episode_num": 0
},
{
"video_id": "7535701443542535465",
"episode_num": 0
},
{
"video_id": "7535701456305786153",
"episode_num": 0
},
{
"video_id": "7535701442590428455",
"episode_num": 0
},
{
"video_id": "7535701468439973162",
"episode_num": 0
},
{
"video_id": "7535701494906031399",
"episode_num": 0
},
{
"video_id": "7535701504049548580",
"episode_num": 0
},
{
"video_id": "7535701470788750635",
"episode_num": 0
},
{
"video_id": "7535701485867322687",
"episode_num": 0
},
{
"video_id": "7535701502833200403",
"episode_num": 0
},
{
"video_id": "7535701525734231359",
"episode_num": 0
},
{
"video_id": "7535701525520239914",
"episode_num": 0
},
{
"video_id": "7535701540334587190",
"episode_num": 0
},
{
"video_id": "7535701524362693930",
"episode_num": 0
},
{
"video_id": "7535701557594066217",
"episode_num": 0
},
{
"video_id": "7535701561180163367",
"episode_num": 0
},
{
"video_id": "7535701557178879268",
"episode_num": 0
},
{
"video_id": "7535701577760263463",
"episode_num": 0
},
{
"video_id": "7535701575201738026",
"episode_num": 0
},
{
"video_id": "7535701602775108905",
"episode_num": 0
},
{
"video_id": "7535701587893833014",
"episode_num": 0
},
{
"video_id": "7535701608986873127",
"episode_num": 0
},
{
"video_id": "7535701629786508580",
"episode_num": 0
},
{
"video_id": "7535701644424531239",
"episode_num": 0
},
{
"video_id": "7535701627827752211",
"episode_num": 0
},
{
"video_id": "7535701660933492009",
"episode_num": 0
},
{
"video_id": "7535701645422873897",
"episode_num": 0
},
{
"video_id": "7535701646941179179",
"episode_num": 0
},
{
"video_id": "7535701666885045540",
"episode_num": 0
},
{
"video_id": "7535701674799779135",
"episode_num": 0
},
{
"video_id": "7535701687755869476",
"episode_num": 0
},
{
"video_id": "7535701681867214099",
"episode_num": 0
},
{
"video_id": "7535701718235942180",
"episode_num": 0
},
{
"video_id": "7535701716738559295",
"episode_num": 0
},
{
"video_id": "7535701714779884841",
"episode_num": 0
},
{
"video_id": "7535701730080656679",
"episode_num": 0
},
{
"video_id": "7535701718118567211",
"episode_num": 0
},
{
"video_id": "7535701734463720743",
"episode_num": 0
},
{
"video_id": "7535701751924542756",
"episode_num": 0
},
{
"video_id": "7535701727887084842",
"episode_num": 0
},
{
"video_id": "7535701766235622710",
"episode_num": 0
},
{
"video_id": "7535701764960521508",
"episode_num": 0
},
{
"video_id": "7535701790038199606",
"episode_num": 0
},
{
"video_id": "7535701815388540223",
"episode_num": 0
},
{
"video_id": "7535701795494989098",
"episode_num": 0
},
{
"video_id": "7535701809969532214",
"episode_num": 0
},
{
"video_id": "7543884485494885666",
"episode_num": 0
}
],
"total_count": 68,
"last_update": "2025-10-22T09:56:42.812592",
"mix_name": "奶团太后宫心计"
}

View File

@ -1,55 +0,0 @@
{
"episodes": [
{
"video_id": "7538319264500010274",
"episode_num": 0
},
{
"video_id": "7538319253661895976",
"episode_num": 0
},
{
"video_id": "7538319258040667426",
"episode_num": 0
},
{
"video_id": "7538319250730142991",
"episode_num": 0
},
{
"video_id": "7538319251308956928",
"episode_num": 0
},
{
"video_id": "7538319255717088546",
"episode_num": 0
},
{
"video_id": "7538319260087635200",
"episode_num": 0
},
{
"video_id": "7538319313824943360",
"episode_num": 0
},
{
"video_id": "7538319304874282280",
"episode_num": 0
},
{
"video_id": "7538319315666357519",
"episode_num": 0
},
{
"video_id": "7538319302512921890",
"episode_num": 0
},
{
"video_id": "7538319312289926400",
"episode_num": 0
}
],
"total_count": 12,
"last_update": "2025-10-22T09:56:12.150347",
"mix_name": "燕赤伏妖"
}

View File

@ -1,87 +0,0 @@
{
"episodes": [
{
"video_id": "7540121867537894694",
"episode_num": 0
},
{
"video_id": "7540121873649093926",
"episode_num": 0
},
{
"video_id": "7540121890577272115",
"episode_num": 0
},
{
"video_id": "7540121898751986990",
"episode_num": 0
},
{
"video_id": "7540121893479664934",
"episode_num": 0
},
{
"video_id": "7540121902363233545",
"episode_num": 0
},
{
"video_id": "7540121896306707721",
"episode_num": 0
},
{
"video_id": "7540121918884547878",
"episode_num": 0
},
{
"video_id": "7540121908944162099",
"episode_num": 0
},
{
"video_id": "7540121914937822510",
"episode_num": 0
},
{
"video_id": "7540121923020246310",
"episode_num": 0
},
{
"video_id": "7540121952229330186",
"episode_num": 0
},
{
"video_id": "7540121960240434470",
"episode_num": 0
},
{
"video_id": "7540121958432689458",
"episode_num": 0
},
{
"video_id": "7540121974115241267",
"episode_num": 0
},
{
"video_id": "7540121980037582126",
"episode_num": 0
},
{
"video_id": "7540121986127727922",
"episode_num": 0
},
{
"video_id": "7540121993606171931",
"episode_num": 0
},
{
"video_id": "7540121997993397550",
"episode_num": 0
},
{
"video_id": "7540121998798671150",
"episode_num": 0
}
],
"total_count": 20,
"last_update": "2025-10-22T09:55:40.062057",
"mix_name": "废柴仙尊在凡间逆袭"
}

View File

@ -1,59 +0,0 @@
{
"episodes": [
{
"video_id": "7520060104645823780",
"episode_num": 0
},
{
"video_id": "7526440964852911360",
"episode_num": 0
},
{
"video_id": "7531224944424897807",
"episode_num": 0
},
{
"video_id": "7536966604467342634",
"episode_num": 0
},
{
"video_id": "7540495853090245898",
"episode_num": 0
},
{
"video_id": "7546582568850754825",
"episode_num": 0
},
{
"video_id": "7550653403244875044",
"episode_num": 0
},
{
"video_id": "7553221689224711466",
"episode_num": 0
},
{
"video_id": "7555476643674869028",
"episode_num": 0
},
{
"video_id": "7557563705563581723",
"episode_num": 0
},
{
"video_id": "7561372042944105770",
"episode_num": 0
},
{
"video_id": "7563638353325821203",
"episode_num": 0
},
{
"video_id": "7564982296051338534",
"episode_num": 0
}
],
"total_count": 13,
"last_update": "2025-10-25T12:53:08.640840",
"mix_name": "暗黑神话《葫芦兄弟》大电影"
}

View File

@ -1,335 +0,0 @@
{
"episodes": [
{
"video_id": "7542848851212848399",
"episode_num": 0
},
{
"video_id": "7542848809219509539",
"episode_num": 0
},
{
"video_id": "7542848845315607848",
"episode_num": 0
},
{
"video_id": "7542848836981640482",
"episode_num": 0
},
{
"video_id": "7542848861065301248",
"episode_num": 0
},
{
"video_id": "7542848884834323746",
"episode_num": 0
},
{
"video_id": "7542848870422711587",
"episode_num": 0
},
{
"video_id": "7542848880208022824",
"episode_num": 0
},
{
"video_id": "7542848850625662223",
"episode_num": 0
},
{
"video_id": "7542848915637357858",
"episode_num": 0
},
{
"video_id": "7542848899275443508",
"episode_num": 0
},
{
"video_id": "7542848861832793344",
"episode_num": 0
},
{
"video_id": "7542848917688405248",
"episode_num": 0
},
{
"video_id": "7542848921295539490",
"episode_num": 0
},
{
"video_id": "7542848955193822498",
"episode_num": 0
},
{
"video_id": "7542848980061785359",
"episode_num": 0
},
{
"video_id": "7542848967848004898",
"episode_num": 0
},
{
"video_id": "7542848965998415104",
"episode_num": 0
},
{
"video_id": "7542848979311070504",
"episode_num": 0
},
{
"video_id": "7542848967923584308",
"episode_num": 0
},
{
"video_id": "7542848984814062848",
"episode_num": 0
},
{
"video_id": "7542848924772470050",
"episode_num": 0
},
{
"video_id": "7542849015503768847",
"episode_num": 0
},
{
"video_id": "7542849044486343970",
"episode_num": 0
},
{
"video_id": "7542849026937408820",
"episode_num": 0
},
{
"video_id": "7542849016988536064",
"episode_num": 0
},
{
"video_id": "7542849050052152576",
"episode_num": 0
},
{
"video_id": "7542849050303827234",
"episode_num": 0
},
{
"video_id": "7542849070256098560",
"episode_num": 0
},
{
"video_id": "7542849073359883554",
"episode_num": 0
},
{
"video_id": "7542849080590978339",
"episode_num": 0
},
{
"video_id": "7542849054955277620",
"episode_num": 0
},
{
"video_id": "7542849095237422376",
"episode_num": 0
},
{
"video_id": "7542849079081012495",
"episode_num": 0
},
{
"video_id": "7542849104309751092",
"episode_num": 0
},
{
"video_id": "7542849117307915554",
"episode_num": 0
},
{
"video_id": "7542849134680739106",
"episode_num": 0
},
{
"video_id": "7542849125507779892",
"episode_num": 0
},
{
"video_id": "7542849118029286691",
"episode_num": 0
},
{
"video_id": "7542849137717349684",
"episode_num": 0
},
{
"video_id": "7542849160806927650",
"episode_num": 0
},
{
"video_id": "7542849105559604520",
"episode_num": 0
},
{
"video_id": "7542849158164565263",
"episode_num": 0
},
{
"video_id": "7542849186220297487",
"episode_num": 0
},
{
"video_id": "7542849155958394146",
"episode_num": 0
},
{
"video_id": "7542849176644717839",
"episode_num": 0
},
{
"video_id": "7542849167325039924",
"episode_num": 0
},
{
"video_id": "7542849189500226850",
"episode_num": 0
},
{
"video_id": "7542849227328621839",
"episode_num": 0
},
{
"video_id": "7542849207896395008",
"episode_num": 0
},
{
"video_id": "7542849211025444111",
"episode_num": 0
},
{
"video_id": "7542849162627386639",
"episode_num": 0
},
{
"video_id": "7542849207703555328",
"episode_num": 0
},
{
"video_id": "7542849259792502031",
"episode_num": 0
},
{
"video_id": "7542849258521644323",
"episode_num": 0
},
{
"video_id": "7542849225709735183",
"episode_num": 0
},
{
"video_id": "7542849302184365364",
"episode_num": 0
},
{
"video_id": "7542849280399232271",
"episode_num": 0
},
{
"video_id": "7542849289127464232",
"episode_num": 0
},
{
"video_id": "7542849295699987747",
"episode_num": 0
},
{
"video_id": "7542849251013954850",
"episode_num": 0
},
{
"video_id": "7542849316457565475",
"episode_num": 0
},
{
"video_id": "7542849309453077794",
"episode_num": 0
},
{
"video_id": "7542849330223287604",
"episode_num": 0
},
{
"video_id": "7542849366608973071",
"episode_num": 0
},
{
"video_id": "7542849356844649743",
"episode_num": 0
},
{
"video_id": "7542849376066997544",
"episode_num": 0
},
{
"video_id": "7542849360560737536",
"episode_num": 0
},
{
"video_id": "7542849368232086819",
"episode_num": 0
},
{
"video_id": "7542849392085110050",
"episode_num": 0
},
{
"video_id": "7542849341845720335",
"episode_num": 0
},
{
"video_id": "7542849423311637795",
"episode_num": 0
},
{
"video_id": "7542849409881558287",
"episode_num": 0
},
{
"video_id": "7542849389480529167",
"episode_num": 0
},
{
"video_id": "7542849421172657442",
"episode_num": 0
},
{
"video_id": "7542849419784359168",
"episode_num": 0
},
{
"video_id": "7542849444547415348",
"episode_num": 0
},
{
"video_id": "7542849467016383778",
"episode_num": 0
},
{
"video_id": "7542849454877986048",
"episode_num": 0
},
{
"video_id": "7542849456861973760",
"episode_num": 0
},
{
"video_id": "7542849403191594255",
"episode_num": 0
},
{
"video_id": "7543842316474207529",
"episode_num": 0
}
],
"total_count": 82,
"last_update": "2025-10-22T09:56:26.875722",
"mix_name": "200斤王妃天天想和离Q版"
}

View File

@ -1,59 +0,0 @@
{
"episodes": [
{
"video_id": "7546071652224765234",
"episode_num": 0
},
{
"video_id": "7546071610189548827",
"episode_num": 0
},
{
"video_id": "7546071665881500954",
"episode_num": 0
},
{
"video_id": "7546071681165495561",
"episode_num": 0
},
{
"video_id": "7546071674475515145",
"episode_num": 0
},
{
"video_id": "7546071695342243123",
"episode_num": 0
},
{
"video_id": "7546071699012193587",
"episode_num": 0
},
{
"video_id": "7546071697456254234",
"episode_num": 0
},
{
"video_id": "7546071708185283878",
"episode_num": 0
},
{
"video_id": "7546071712543165723",
"episode_num": 0
},
{
"video_id": "7546071720415857947",
"episode_num": 0
},
{
"video_id": "7546071728376565043",
"episode_num": 0
},
{
"video_id": "7546071716959685939",
"episode_num": 0
}
],
"total_count": 13,
"last_update": "2025-10-22T09:55:35.570013",
"mix_name": "末日来袭"
}

View File

@ -1,35 +0,0 @@
{
"episodes": [
{
"video_id": "7545715527935610150",
"episode_num": 0
},
{
"video_id": "7546851498567716123",
"episode_num": 0
},
{
"video_id": "7548440120316218662",
"episode_num": 0
},
{
"video_id": "7549782003667782954",
"episode_num": 0
},
{
"video_id": "7551038580261391616",
"episode_num": 0
},
{
"video_id": "7552606420504464650",
"episode_num": 0
},
{
"video_id": "7555059788590206234",
"episode_num": 0
}
],
"total_count": 7,
"last_update": "2025-10-22T09:56:07.724877",
"mix_name": "《南城诡事》"
}

View File

@ -1,283 +0,0 @@
{
"episodes": [
{
"video_id": "7553983620604579118",
"episode_num": 0
},
{
"video_id": "7553983636282953011",
"episode_num": 0
},
{
"video_id": "7553983647192288563",
"episode_num": 0
},
{
"video_id": "7553983646374448411",
"episode_num": 0
},
{
"video_id": "7553983671213133107",
"episode_num": 0
},
{
"video_id": "7553983656532937994",
"episode_num": 0
},
{
"video_id": "7553983683934326067",
"episode_num": 0
},
{
"video_id": "7553983686446697737",
"episode_num": 0
},
{
"video_id": "7553983694885752110",
"episode_num": 0
},
{
"video_id": "7553983711918755122",
"episode_num": 0
},
{
"video_id": "7553983719787285770",
"episode_num": 0
},
{
"video_id": "7553983712300403978",
"episode_num": 0
},
{
"video_id": "7553983719380487450",
"episode_num": 0
},
{
"video_id": "7553983734438038830",
"episode_num": 0
},
{
"video_id": "7553983745687178546",
"episode_num": 0
},
{
"video_id": "7553983751466831150",
"episode_num": 0
},
{
"video_id": "7553983762921524530",
"episode_num": 0
},
{
"video_id": "7553983765584923914",
"episode_num": 0
},
{
"video_id": "7553983782336957723",
"episode_num": 0
},
{
"video_id": "7553983772199275785",
"episode_num": 0
},
{
"video_id": "7553983806231891209",
"episode_num": 0
},
{
"video_id": "7553983819997547803",
"episode_num": 0
},
{
"video_id": "7553983816046595366",
"episode_num": 0
},
{
"video_id": "7553983829485112627",
"episode_num": 0
},
{
"video_id": "7553983842286161178",
"episode_num": 0
},
{
"video_id": "7553983841656950042",
"episode_num": 0
},
{
"video_id": "7553983832865737993",
"episode_num": 0
},
{
"video_id": "7553983844874013978",
"episode_num": 0
},
{
"video_id": "7553983845054352678",
"episode_num": 0
},
{
"video_id": "7553983863744187699",
"episode_num": 0
},
{
"video_id": "7553983873361677618",
"episode_num": 0
},
{
"video_id": "7553983883587423514",
"episode_num": 0
},
{
"video_id": "7553983889304194330",
"episode_num": 0
},
{
"video_id": "7553983897294359818",
"episode_num": 0
},
{
"video_id": "7553983891145575707",
"episode_num": 0
},
{
"video_id": "7553983921776512266",
"episode_num": 0
},
{
"video_id": "7553983915900374299",
"episode_num": 0
},
{
"video_id": "7553983931104693542",
"episode_num": 0
},
{
"video_id": "7553983944425737523",
"episode_num": 0
},
{
"video_id": "7553983937924680998",
"episode_num": 0
},
{
"video_id": "7553983956136381705",
"episode_num": 0
},
{
"video_id": "7553983954274077961",
"episode_num": 0
},
{
"video_id": "7553983968228494602",
"episode_num": 0
},
{
"video_id": "7553983980819713326",
"episode_num": 0
},
{
"video_id": "7553983971994995995",
"episode_num": 0
},
{
"video_id": "7553983994157632814",
"episode_num": 0
},
{
"video_id": "7553983997076966706",
"episode_num": 0
},
{
"video_id": "7553984007311019315",
"episode_num": 0
},
{
"video_id": "7553984019042422026",
"episode_num": 0
},
{
"video_id": "7553984009651408137",
"episode_num": 0
},
{
"video_id": "7553984031956798770",
"episode_num": 0
},
{
"video_id": "7553984033814859054",
"episode_num": 0
},
{
"video_id": "7553984062147431690",
"episode_num": 0
},
{
"video_id": "7553984067348352266",
"episode_num": 0
},
{
"video_id": "7553984082489658675",
"episode_num": 0
},
{
"video_id": "7553984074881256714",
"episode_num": 0
},
{
"video_id": "7553984094493773094",
"episode_num": 0
},
{
"video_id": "7553984092258241830",
"episode_num": 0
},
{
"video_id": "7553984101271850267",
"episode_num": 0
},
{
"video_id": "7553984113179462950",
"episode_num": 0
},
{
"video_id": "7553984119844228379",
"episode_num": 0
},
{
"video_id": "7553984134859722035",
"episode_num": 0
},
{
"video_id": "7553984126999711022",
"episode_num": 0
},
{
"video_id": "7553984154476514587",
"episode_num": 0
},
{
"video_id": "7553984147111415049",
"episode_num": 0
},
{
"video_id": "7553984154166168870",
"episode_num": 0
},
{
"video_id": "7553984160797363502",
"episode_num": 0
},
{
"video_id": "7553984182108572955",
"episode_num": 0
},
{
"video_id": "7553984168468811046",
"episode_num": 0
}
],
"total_count": 69,
"last_update": "2025-10-22T09:56:34.803954",
"mix_name": "我在荒年当女帝"
}

View File

@ -1,59 +0,0 @@
{
"episodes": [
{
"video_id": "7554009575922355482",
"episode_num": 0
},
{
"video_id": "7554009571266809139",
"episode_num": 0
},
{
"video_id": "7554009591776840970",
"episode_num": 0
},
{
"video_id": "7554009593425218866",
"episode_num": 0
},
{
"video_id": "7554009609409662217",
"episode_num": 0
},
{
"video_id": "7554312903608913195",
"episode_num": 0
},
{
"video_id": "7554312915164187940",
"episode_num": 0
},
{
"video_id": "7554312925851176234",
"episode_num": 0
},
{
"video_id": "7554312927336041791",
"episode_num": 0
},
{
"video_id": "7554312932851617078",
"episode_num": 0
},
{
"video_id": "7555847841084706111",
"episode_num": 0
},
{
"video_id": "7555847841931955510",
"episode_num": 0
},
{
"video_id": "7559429054969957684",
"episode_num": 0
}
],
"total_count": 13,
"last_update": "2025-10-22T09:56:17.655969",
"mix_name": "传武"
}

View File

@ -1,87 +0,0 @@
{
"episodes": [
{
"video_id": "7554750058999188776",
"episode_num": 0
},
{
"video_id": "7554750089743355151",
"episode_num": 0
},
{
"video_id": "7554750101374143784",
"episode_num": 0
},
{
"video_id": "7554750092658429199",
"episode_num": 0
},
{
"video_id": "7554750091874045224",
"episode_num": 0
},
{
"video_id": "7554750074610339107",
"episode_num": 0
},
{
"video_id": "7554750093157600512",
"episode_num": 0
},
{
"video_id": "7554750110882729251",
"episode_num": 0
},
{
"video_id": "7554751305978268963",
"episode_num": 0
},
{
"video_id": "7554750135679356195",
"episode_num": 0
},
{
"video_id": "7554750126988872995",
"episode_num": 0
},
{
"video_id": "7554750136304422144",
"episode_num": 0
},
{
"video_id": "7554750151248694568",
"episode_num": 0
},
{
"video_id": "7554750138007276835",
"episode_num": 0
},
{
"video_id": "7554750160660679970",
"episode_num": 0
},
{
"video_id": "7554750166654356770",
"episode_num": 0
},
{
"video_id": "7554750176326454562",
"episode_num": 0
},
{
"video_id": "7554750194152197416",
"episode_num": 0
},
{
"video_id": "7554750204159773967",
"episode_num": 0
},
{
"video_id": "7554750213030776064",
"episode_num": 0
}
],
"total_count": 20,
"last_update": "2025-10-22T09:55:34.882918",
"mix_name": "我的治愈系游戏"
}

View File

@ -1,23 +0,0 @@
{
"episodes": [
{
"video_id": "7555012459468295464",
"episode_num": 0
},
{
"video_id": "7555402801766092086",
"episode_num": 0
},
{
"video_id": "7555406069112130856",
"episode_num": 0
},
{
"video_id": "7559152702782049576",
"episode_num": 0
}
],
"total_count": 4,
"last_update": "2025-10-22T09:55:32.571577",
"mix_name": "我在山海世界当神仙奶奶"
}

View File

@ -1,215 +0,0 @@
{
"episodes": [
{
"video_id": "7555848626619043087",
"episode_num": 0
},
{
"video_id": "7555848620394745103",
"episode_num": 0
},
{
"video_id": "7555848626723884288",
"episode_num": 0
},
{
"video_id": "7555848639554374947",
"episode_num": 0
},
{
"video_id": "7555848651201908020",
"episode_num": 0
},
{
"video_id": "7555848646504303872",
"episode_num": 0
},
{
"video_id": "7555848634936479016",
"episode_num": 0
},
{
"video_id": "7555848658214833443",
"episode_num": 0
},
{
"video_id": "7555848701277670656",
"episode_num": 0
},
{
"video_id": "7555848676313206050",
"episode_num": 0
},
{
"video_id": "7555848687017151759",
"episode_num": 0
},
{
"video_id": "7555848690846551330",
"episode_num": 0
},
{
"video_id": "7555848704461196544",
"episode_num": 0
},
{
"video_id": "7555848729824152832",
"episode_num": 0
},
{
"video_id": "7555848716045847842",
"episode_num": 0
},
{
"video_id": "7555848730759531828",
"episode_num": 0
},
{
"video_id": "7555848731841662242",
"episode_num": 0
},
{
"video_id": "7555848757745618228",
"episode_num": 0
},
{
"video_id": "7555848764313947426",
"episode_num": 0
},
{
"video_id": "7555848763940572456",
"episode_num": 0
},
{
"video_id": "7555848769703644468",
"episode_num": 0
},
{
"video_id": "7555848788842171663",
"episode_num": 0
},
{
"video_id": "7555848805493558562",
"episode_num": 0
},
{
"video_id": "7555848796584938787",
"episode_num": 0
},
{
"video_id": "7555848822841232655",
"episode_num": 0
},
{
"video_id": "7555848807460752675",
"episode_num": 0
},
{
"video_id": "7555848826909625634",
"episode_num": 0
},
{
"video_id": "7555848831548525859",
"episode_num": 0
},
{
"video_id": "7555848844282449204",
"episode_num": 0
},
{
"video_id": "7555848849298820367",
"episode_num": 0
},
{
"video_id": "7555848861130951970",
"episode_num": 0
},
{
"video_id": "7555848854726348072",
"episode_num": 0
},
{
"video_id": "7555848849340910882",
"episode_num": 0
},
{
"video_id": "7555848876754849064",
"episode_num": 0
},
{
"video_id": "7555848903296371968",
"episode_num": 0
},
{
"video_id": "7555848872417971471",
"episode_num": 0
},
{
"video_id": "7555848898049363234",
"episode_num": 0
},
{
"video_id": "7555848895910235426",
"episode_num": 0
},
{
"video_id": "7555848919880699136",
"episode_num": 0
},
{
"video_id": "7555848946078207267",
"episode_num": 0
},
{
"video_id": "7555848941703613711",
"episode_num": 0
},
{
"video_id": "7555848946078305571",
"episode_num": 0
},
{
"video_id": "7555848977900375336",
"episode_num": 0
},
{
"video_id": "7555848968379419939",
"episode_num": 0
},
{
"video_id": "7555848963484683572",
"episode_num": 0
},
{
"video_id": "7559890467404434724",
"episode_num": 0
},
{
"video_id": "7555848989376089359",
"episode_num": 0
},
{
"video_id": "7555848987807386880",
"episode_num": 0
},
{
"video_id": "7555848993603898664",
"episode_num": 0
},
{
"video_id": "7555849016483777827",
"episode_num": 0
},
{
"video_id": "7555849024037801216",
"episode_num": 0
},
{
"video_id": "7555849027057667368",
"episode_num": 0
}
],
"total_count": 52,
"last_update": "2025-10-22T09:55:47.709471",
"mix_name": "婉心计"
}

View File

@ -1,251 +0,0 @@
{
"episodes": [
{
"video_id": "7556193043586600201",
"episode_num": 0
},
{
"video_id": "7556193049286675762",
"episode_num": 0
},
{
"video_id": "7556193069050105139",
"episode_num": 0
},
{
"video_id": "7556193070857899302",
"episode_num": 0
},
{
"video_id": "7556193075085741350",
"episode_num": 0
},
{
"video_id": "7556193078072134962",
"episode_num": 0
},
{
"video_id": "7556193079070379310",
"episode_num": 0
},
{
"video_id": "7556193078973975818",
"episode_num": 0
},
{
"video_id": "7556193108963118382",
"episode_num": 0
},
{
"video_id": "7556193112775822638",
"episode_num": 0
},
{
"video_id": "7556193121483115802",
"episode_num": 0
},
{
"video_id": "7556193118438067494",
"episode_num": 0
},
{
"video_id": "7556193118383623462",
"episode_num": 0
},
{
"video_id": "7556193123634908462",
"episode_num": 0
},
{
"video_id": "7556193146061868338",
"episode_num": 0
},
{
"video_id": "7556193153837960458",
"episode_num": 0
},
{
"video_id": "7556193142836448521",
"episode_num": 0
},
{
"video_id": "7556193162352512282",
"episode_num": 0
},
{
"video_id": "7556193174033616138",
"episode_num": 0
},
{
"video_id": "7556193192723402034",
"episode_num": 0
},
{
"video_id": "7556193187744845107",
"episode_num": 0
},
{
"video_id": "7556193208854646025",
"episode_num": 0
},
{
"video_id": "7556193223312510254",
"episode_num": 0
},
{
"video_id": "7556193225766112550",
"episode_num": 0
},
{
"video_id": "7556193223954287922",
"episode_num": 0
},
{
"video_id": "7556193234033069338",
"episode_num": 0
},
{
"video_id": "7556193250365771054",
"episode_num": 0
},
{
"video_id": "7556193252056059182",
"episode_num": 0
},
{
"video_id": "7556193259912006963",
"episode_num": 0
},
{
"video_id": "7556193260188847369",
"episode_num": 0
},
{
"video_id": "7556193250890075418",
"episode_num": 0
},
{
"video_id": "7556193288026361114",
"episode_num": 0
},
{
"video_id": "7556193288236190985",
"episode_num": 0
},
{
"video_id": "7556193301905345802",
"episode_num": 0
},
{
"video_id": "7556193302542961970",
"episode_num": 0
},
{
"video_id": "7556193321299823881",
"episode_num": 0
},
{
"video_id": "7556193328434269450",
"episode_num": 0
},
{
"video_id": "7556193321668922633",
"episode_num": 0
},
{
"video_id": "7556193341751266569",
"episode_num": 0
},
{
"video_id": "7556193355420405019",
"episode_num": 0
},
{
"video_id": "7556193355697458482",
"episode_num": 0
},
{
"video_id": "7556193360436841737",
"episode_num": 0
},
{
"video_id": "7556193361883974921",
"episode_num": 0
},
{
"video_id": "7556193358012534025",
"episode_num": 0
},
{
"video_id": "7556193378002668846",
"episode_num": 0
},
{
"video_id": "7556193386659728691",
"episode_num": 0
},
{
"video_id": "7556193404892253478",
"episode_num": 0
},
{
"video_id": "7556193406922312970",
"episode_num": 0
},
{
"video_id": "7556193422680329498",
"episode_num": 0
},
{
"video_id": "7556193423468842266",
"episode_num": 0
},
{
"video_id": "7556193432524410158",
"episode_num": 0
},
{
"video_id": "7556193450471804187",
"episode_num": 0
},
{
"video_id": "7556193451281222939",
"episode_num": 0
},
{
"video_id": "7556193461007928586",
"episode_num": 0
},
{
"video_id": "7556193466187861294",
"episode_num": 0
},
{
"video_id": "7556193487763328265",
"episode_num": 0
},
{
"video_id": "7556193490787421467",
"episode_num": 0
},
{
"video_id": "7556193478774918410",
"episode_num": 0
},
{
"video_id": "7556193479311887625",
"episode_num": 0
},
{
"video_id": "7556193503307484425",
"episode_num": 0
},
{
"video_id": "7556193515902995721",
"episode_num": 0
}
],
"total_count": 61,
"last_update": "2025-10-22T09:56:50.400526",
"mix_name": "我靠唱歌打脸全团"
}

View File

@ -1,115 +0,0 @@
{
"episodes": [
{
"video_id": "7497105467341147428",
"episode_num": 0
},
{
"video_id": "7501492304370601250",
"episode_num": 0
},
{
"video_id": "7502772081621273894",
"episode_num": 0
},
{
"video_id": "7503839169832062259",
"episode_num": 0
},
{
"video_id": "7504986016153062656",
"episode_num": 0
},
{
"video_id": "7506112308838403343",
"episode_num": 0
},
{
"video_id": "7506782177625394432",
"episode_num": 0
},
{
"video_id": "7507204856379378959",
"episode_num": 0
},
{
"video_id": "7507541015005744424",
"episode_num": 0
},
{
"video_id": "7507946206644210959",
"episode_num": 0
},
{
"video_id": "7508945450654141731",
"episode_num": 0
},
{
"video_id": "7514129646461078799",
"episode_num": 0
},
{
"video_id": "7519344535044066560",
"episode_num": 0
},
{
"video_id": "7521994647779970338",
"episode_num": 0
},
{
"video_id": "7524264312450698536",
"episode_num": 0
},
{
"video_id": "7527207390493723938",
"episode_num": 0
},
{
"video_id": "7531374405576248591",
"episode_num": 0
},
{
"video_id": "7532778856979451136",
"episode_num": 0
},
{
"video_id": "7535583078481136911",
"episode_num": 0
},
{
"video_id": "7536884524291263759",
"episode_num": 0
},
{
"video_id": "7538866617654365480",
"episode_num": 0
},
{
"video_id": "7539751142214438144",
"episode_num": 0
},
{
"video_id": "7549904246364376335",
"episode_num": 0
},
{
"video_id": "7554992404740214016",
"episode_num": 0
},
{
"video_id": "7555715283915312384",
"episode_num": 0
},
{
"video_id": "7558050978226982179",
"episode_num": 0
},
{
"video_id": "7560551213957500195",
"episode_num": 0
}
],
"total_count": 27,
"last_update": "2025-10-22T09:56:16.947762",
"mix_name": "绝境逆袭"
}

View File

@ -24,24 +24,16 @@ import os
import shutil import shutil
from datetime import datetime from datetime import datetime
import requests import requests
import base64
import uuid
import sys
import psutil
import random
import threading
import argparse
from concurrent.futures import ThreadPoolExecutor
from selenium import webdriver from selenium import webdriver
import os
from selenium.webdriver.chrome.service import Service from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options from selenium.webdriver.chrome.options import Options
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains
# 保留导入但默认不使用webdriver_manager避免网络下载卡顿 # 保留导入但默认不使用webdriver_manager避免网络下载卡顿
from webdriver_manager.chrome import ChromeDriverManager # noqa: F401 from webdriver_manager.chrome import ChromeDriverManager # noqa: F401
import chromedriver_autoinstaller
import sys
import os
# 添加项目根目录到 Python 路径 # 添加项目根目录到 Python 路径
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..')) sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..'))
# 确保能找到backend目录下的模块 # 确保能找到backend目录下的模块
@ -49,10 +41,13 @@ backend_dir = os.path.join(os.path.dirname(__file__), '..', '..')
sys.path.insert(0, backend_dir) sys.path.insert(0, backend_dir)
from database import db from database import db
from tos_client import oss_client from tos_client import oss_client
import uuid
import re
# 配置日志 # 配置日志
# 确保logs目录存在 # 确保logs目录存在
import os
script_dir = os.path.dirname(os.path.abspath(__file__)) script_dir = os.path.dirname(os.path.abspath(__file__))
logs_dir = os.path.join(script_dir, 'logs') logs_dir = os.path.join(script_dir, 'logs')
os.makedirs(logs_dir, exist_ok=True) os.makedirs(logs_dir, exist_ok=True)
@ -78,7 +73,6 @@ class DouyinPlayVVScraper:
self.db = None self.db = None
self.collection = None self.collection = None
self.image_cache = {} # 图片ID到TOS链接的缓存映射 {image_id: tos_url} self.image_cache = {} # 图片ID到TOS链接的缓存映射 {image_id: tos_url}
self.all_collected_comments = [] # 存储所有收集到的评论数据
self._cleanup_old_profiles() self._cleanup_old_profiles()
self._setup_mongodb() self._setup_mongodb()
self._load_image_cache() self._load_image_cache()
@ -164,6 +158,8 @@ class DouyinPlayVVScraper:
def _cleanup_chrome_processes(self): def _cleanup_chrome_processes(self):
"""清理可能占用配置文件的Chrome进程""" """清理可能占用配置文件的Chrome进程"""
try: try:
import subprocess
import psutil
# 获取当前配置文件路径 # 获取当前配置文件路径
script_dir = os.path.dirname(os.path.abspath(__file__)) script_dir = os.path.dirname(os.path.abspath(__file__))
@ -453,6 +449,28 @@ class DouyinPlayVVScraper:
if n >= 10_000: if n >= 10_000:
return f"{n/10_000:.1f}" return f"{n/10_000:.1f}"
return str(n) return str(n)
def format_interaction_count(self, n: int) -> str:
"""格式化互动数据数量,返回带单位的字符串
Args:
n: 数量
Returns:
str: 格式化后的字符串 27898 -> 2.8W, 1234 -> 1234
"""
if n >= 100_000_000:
result = n / 100_000_000
if result == int(result):
return f"{int(result)}亿"
else:
return f"{result:.1f}亿"
elif n >= 10_000:
result = n / 10_000
if result == int(result):
return f"{int(result)}W"
else:
return f"{result:.1f}W"
else:
return str(n)
@ -1156,7 +1174,9 @@ class DouyinPlayVVScraper:
# 等待页面加载完成 # 等待页面加载完成
try: try:
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
WebDriverWait(self.driver, 10).until( WebDriverWait(self.driver, 10).until(
EC.presence_of_element_located((By.TAG_NAME, "video")) EC.presence_of_element_located((By.TAG_NAME, "video"))
@ -1358,6 +1378,374 @@ class DouyinPlayVVScraper:
return [video['video_id'] for video in cached_videos] return [video['video_id'] for video in cached_videos]
return [] return []
def get_video_details(self, video_id: str, max_comments: int = 20) -> dict:
"""获取单个视频的详细互动数据
Args:
video_id: 视频ID
max_comments: 最大评论数量默认20条
Returns:
dict: 包含点赞数收藏数转发数评论内容的字典
"""
video_details = {
'video_id': video_id,
'likes': 0,
'shares': 0,
'favorites': 0,
'likes_formatted': '0',
'shares_formatted': '0',
'favorites_formatted': '0',
'comments': [],
'success': False,
'error': None
}
try:
# 确保driver已初始化
if self.driver is None:
logging.info('Driver未初始化正在设置...')
self.setup_driver()
if self.driver is None:
raise Exception("无法初始化WebDriver")
video_url = f'https://www.douyin.com/video/{video_id}'
logging.info(f'获取视频详细数据: {video_url}')
# 导航到视频页面
self.driver.get(video_url)
time.sleep(3)
# 等待页面加载完成
try:
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
WebDriverWait(self.driver, 10).until(
EC.presence_of_element_located((By.TAG_NAME, "video"))
)
except Exception as e:
logging.warning(f'等待视频元素超时: {e}')
# 获取网络请求日志
logs = self.driver.get_log('performance')
# 解析网络日志获取视频详细数据
for entry in logs:
try:
log = json.loads(entry['message'])['message']
if (
'Network.responseReceived' in log['method']
and 'response' in log['params']
and log['params']['response']
and log['params']['response'].get('url')
):
url = log['params']['response']['url']
# 检查是否是视频详情API
if '/aweme/v1/web/aweme/detail/' in url and video_id in url:
try:
# 获取响应体
response_body = self.driver.execute_cdp_cmd(
'Network.getResponseBody',
{'requestId': log['params']['requestId']}
)
if response_body and 'body' in response_body:
data = json.loads(response_body['body'])
aweme_detail = data.get('aweme_detail', {})
if aweme_detail:
# 获取统计数据
statistics = aweme_detail.get('statistics', {})
video_details['likes'] = int(statistics.get('digg_count', 0))
video_details['shares'] = int(statistics.get('share_count', 0))
video_details['favorites'] = int(statistics.get('collect_count', 0))
# 添加格式化字段
video_details['likes_formatted'] = self.format_interaction_count(video_details['likes'])
video_details['shares_formatted'] = self.format_interaction_count(video_details['shares'])
video_details['favorites_formatted'] = self.format_interaction_count(video_details['favorites'])
logging.info(f'视频 {video_id} 互动数据: 点赞={video_details["likes_formatted"]}, 分享={video_details["shares_formatted"]}, 收藏={video_details["favorites_formatted"]}')
except Exception as e:
logging.warning(f'解析视频详情API响应失败: {e}')
continue
# 检查是否是评论API
elif '/aweme/v1/web/comment/list/' in url and video_id in url:
try:
# 获取响应体
response_body = self.driver.execute_cdp_cmd(
'Network.getResponseBody',
{'requestId': log['params']['requestId']}
)
if response_body and 'body' in response_body:
data = json.loads(response_body['body'])
comments = data.get('comments', [])
for comment in comments[:max_comments]:
comment_info = {
'text': comment.get('text', ''),
'user_name': comment.get('user', {}).get('nickname', ''),
'digg_count': int(comment.get('digg_count', 0)),
'create_time': comment.get('create_time', 0)
}
video_details['comments'].append(comment_info)
logging.info(f'视频 {video_id} 获取到 {len(video_details["comments"])} 条评论')
except Exception as e:
logging.warning(f'解析评论API响应失败: {e}')
continue
except Exception as e:
continue
# 如果网络日志没有获取到数据,尝试页面解析
if video_details['likes'] == 0 and video_details['shares'] == 0 and video_details['favorites'] == 0:
video_details = self._parse_video_details_from_page(video_id, video_details, max_comments)
video_details['success'] = True
return video_details
except Exception as e:
error_msg = f'获取视频 {video_id} 详细数据失败: {e}'
logging.error(error_msg)
video_details['error'] = error_msg
return video_details
def _parse_video_details_from_page(self, video_id: str, video_details: dict, max_comments: int = 20) -> dict:
"""从页面元素解析视频详细数据(备用方案)
Args:
video_id: 视频ID
video_details: 现有的视频详细数据字典
max_comments: 最大评论数量
Returns:
dict: 更新后的视频详细数据字典
"""
try:
logging.info(f'尝试从页面元素解析视频 {video_id} 的详细数据')
# 尝试解析页面中的SSR数据
try:
# 查找包含视频数据的script标签
scripts = self.driver.find_elements("tag name", "script")
for script in scripts:
script_content = script.get_attribute('innerHTML')
if script_content and ('window._SSR_HYDRATED_DATA' in script_content or 'RENDER_DATA' in script_content):
# 提取JSON数据
if 'window._SSR_HYDRATED_DATA' in script_content:
match = re.search(r'window\._SSR_HYDRATED_DATA\s*=\s*({.*?});', script_content, re.DOTALL)
else:
match = re.search(r'window\.RENDER_DATA\s*=\s*({.*?});', script_content, re.DOTALL)
if match:
data = json.loads(match.group(1))
# 查找视频详情数据
def find_video_data(obj, target_id):
if isinstance(obj, dict):
for key, value in obj.items():
if key == 'aweme_id' and str(value) == str(target_id):
return obj
elif isinstance(value, (dict, list)):
result = find_video_data(value, target_id)
if result:
return result
elif isinstance(obj, list):
for item in obj:
result = find_video_data(item, target_id)
if result:
return result
return None
video_data = find_video_data(data, video_id)
if video_data:
statistics = video_data.get('statistics', {})
video_details['likes'] = int(statistics.get('digg_count', 0))
video_details['shares'] = int(statistics.get('share_count', 0))
video_details['favorites'] = int(statistics.get('collect_count', 0))
# 添加格式化字段
video_details['likes_formatted'] = self.format_interaction_count(video_details['likes'])
video_details['shares_formatted'] = self.format_interaction_count(video_details['shares'])
video_details['favorites_formatted'] = self.format_interaction_count(video_details['favorites'])
logging.info(f'从SSR数据解析到视频 {video_id} 互动数据: 点赞={video_details["likes_formatted"]}, 分享={video_details["shares_formatted"]}, 收藏={video_details["favorites_formatted"]}')
break
except Exception as e:
logging.warning(f'解析SSR数据失败: {e}')
# 如果SSR数据解析失败尝试CSS选择器
if video_details['likes'] == 0 and video_details['shares'] == 0 and video_details['favorites'] == 0:
try:
# 尝试常见的点赞、分享、收藏按钮选择器
selectors = {
'likes': [
'[data-e2e="video-like-count"]',
'[class*="like"] [class*="count"]',
'[class*="digg"] [class*="count"]'
],
'shares': [
'[data-e2e="video-share-count"]',
'[class*="share"] [class*="count"]'
],
'favorites': [
'[data-e2e="video-collect-count"]',
'[class*="collect"] [class*="count"]',
'[class*="favorite"] [class*="count"]'
]
}
for data_type, selector_list in selectors.items():
for selector in selector_list:
try:
elements = self.driver.find_elements("css selector", selector)
if elements:
text = elements[0].text.strip()
if text and text.replace('.', '').replace('', '').replace('亿', '').isdigit():
# 转换数字格式
if '亿' in text:
video_details[data_type] = int(float(text.replace('亿', '')) * 100000000)
elif '' in text:
video_details[data_type] = int(float(text.replace('', '')) * 10000)
else:
video_details[data_type] = int(text)
break
except Exception:
continue
if video_details['likes'] > 0 or video_details['shares'] > 0 or video_details['favorites'] > 0:
# 添加格式化字段
video_details['likes_formatted'] = self.format_interaction_count(video_details['likes'])
video_details['shares_formatted'] = self.format_interaction_count(video_details['shares'])
video_details['favorites_formatted'] = self.format_interaction_count(video_details['favorites'])
logging.info(f'从页面元素解析到视频 {video_id} 互动数据: 点赞={video_details["likes_formatted"]}, 分享={video_details["shares_formatted"]}, 收藏={video_details["favorites_formatted"]}')
except Exception as e:
logging.warning(f'CSS选择器解析失败: {e}')
# 尝试获取评论(如果还没有获取到)
if not video_details['comments']:
try:
# 滚动到评论区域
self.driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
time.sleep(2)
# 尝试常见的评论选择器
comment_selectors = [
'[data-e2e="comment-item"]',
'[class*="comment-item"]',
'[class*="comment"] [class*="content"]'
]
for selector in comment_selectors:
try:
comment_elements = self.driver.find_elements("css selector", selector)[:max_comments]
if comment_elements:
for element in comment_elements:
try:
comment_text = element.text.strip()
if comment_text:
comment_info = {
'text': comment_text,
'user_name': '',
'digg_count': 0,
'create_time': 0
}
video_details['comments'].append(comment_info)
except Exception:
continue
if video_details['comments']:
logging.info(f'从页面元素获取到视频 {video_id}{len(video_details["comments"])} 条评论')
break
except Exception:
continue
except Exception as e:
logging.warning(f'获取评论失败: {e}')
except Exception as e:
logging.warning(f'页面解析视频详细数据失败: {e}')
return video_details
def get_collection_video_details(self, episode_video_ids: list, mix_name: str = '', max_comments_per_video: int = 10) -> list:
"""获取合集中所有视频的详细互动数据
Args:
episode_video_ids: 视频ID列表
mix_name: 合集名称用于日志
max_comments_per_video: 每个视频最大评论数量默认10条
Returns:
list: 包含每个视频详细数据的列表
"""
# 定时器模式下跳过此函数
if os.environ.get('TIMER_MODE') == '1':
logging.info(f'定时器模式:跳过 get_collection_video_details 函数')
return []
if not episode_video_ids:
logging.info(f'合集 {mix_name} 没有视频ID跳过详细数据获取')
return []
logging.info(f'开始获取合集 {mix_name}{len(episode_video_ids)} 个视频的详细数据')
video_details_list = []
for i, video_id in enumerate(episode_video_ids, 1):
if not video_id:
logging.warning(f'合集 {mix_name}{i} 集视频ID为空跳过')
video_details_list.append({
'episode_number': i,
'video_id': '',
'likes': 0,
'shares': 0,
'favorites': 0,
'comments': [],
'success': False,
'error': '视频ID为空'
})
continue
logging.info(f'获取合集 {mix_name}{i}/{len(episode_video_ids)} 集视频详细数据: {video_id}')
try:
# 获取单个视频的详细数据
video_details = self.get_video_details(video_id, max_comments_per_video)
video_details['episode_number'] = i
video_details_list.append(video_details)
# 添加延迟避免请求过快
time.sleep(2)
except Exception as e:
error_msg = f'获取视频 {video_id} 详细数据时出错: {e}'
logging.error(error_msg)
video_details_list.append({
'episode_number': i,
'video_id': video_id,
'likes': 0,
'shares': 0,
'favorites': 0,
'comments': [],
'success': False,
'error': error_msg
})
# 统计获取结果
success_count = sum(1 for detail in video_details_list if detail.get('success', False))
total_likes = sum(detail.get('likes', 0) for detail in video_details_list)
total_comments = sum(len(detail.get('comments', [])) for detail in video_details_list)
logging.info(f'合集 {mix_name} 视频详细数据获取完成: {success_count}/{len(episode_video_ids)} 成功, 总点赞数={total_likes:,}, 总评论数={total_comments}')
return video_details_list
def get_cookies_dict(self): def get_cookies_dict(self):
"""获取当前页面的cookies""" """获取当前页面的cookies"""
if not hasattr(self, 'cookies') or not self.cookies: if not hasattr(self, 'cookies') or not self.cookies:
@ -1384,6 +1772,7 @@ class DouyinPlayVVScraper:
if __name__ == '__main__': if __name__ == '__main__':
import argparse
parser = argparse.ArgumentParser(description='Selenium+CDP 抖音play_vv抓取器') parser = argparse.ArgumentParser(description='Selenium+CDP 抖音play_vv抓取器')
parser.add_argument('--url', default='https://www.douyin.com/user/self?showTab=favorite_collection&showSubTab=compilation', help='收藏合集列表页面URL') parser.add_argument('--url', default='https://www.douyin.com/user/self?showTab=favorite_collection&showSubTab=compilation', help='收藏合集列表页面URL')
parser.add_argument('--auto', action='store_true', help='自动继续,跳过回车等待') parser.add_argument('--auto', action='store_true', help='自动继续,跳过回车等待')

View File

@ -343,7 +343,7 @@ class TOSChunkUploader:
self.bucket_name = tos_client.bucket_name self.bucket_name = tos_client.bucket_name
self.self_domain = tos_client.self_domain self.self_domain = tos_client.self_domain
def init_multipart_upload(self, object_key: str, content_type: Optional[str] = None) -> Optional[str]: def init_multipart_upload(self, object_key: str, content_type: Optional[str] = None) -> str | None:
""" """
初始化分片上传 初始化分片上传