You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

RuntimeError事件循环已运行:Telegram TikTok下载Bot报错求助

问题解决:Telegram Bot下载TikTok视频触发事件循环错误

错误原因

aiogram是异步框架,运行时已启动一个事件循环,但你使用的TikTokApi同步版本内部又调用了asyncio.get_event_loop().run_until_complete(),导致同一个事件循环被重复启动,触发RuntimeError: This event loop is already running。

修复当前TikTokApi的方案

方案1:改用TikTokApi的异步版本

TikTokApi支持异步操作,直接在aiogram的异步处理器中使用异步方法,避免循环冲突。修改后的代码如下:

# -*- coding: utf-8 -*-
from aiogram import Bot, Dispatcher, executor, types
import logging
import config
from TikTokApi import TikTokApi

logging.basicConfig(level=logging.INFO)
bot = Bot(token=config.token)
dp = Dispatcher(bot)


@dp.message_handler(commands=['start'])
async def send_welcome(message: types.Message):
    await bot.send_message(message.from_user.id,
                           f'hello',
                           parse_mode="Markdown")


@dp.message_handler(content_types=['text'])
async def text(message: types.Message):
    if message.text.startswith('https://vt.tiktok.com'):
        video_url = message.text
        # 异步初始化TikTokApi
        async with TikTokApi() as api:
            video = await api.video(url=video_url)
            # 异步获取视频字节数据
            video_data = await video.bytes()
            
            file_name = f"{message.from_user.id}.mp4"
            with open(file_name, "wb") as out_file:
                out_file.write(video_data)
            
            # 可选:将下载好的视频发回给用户
            await bot.send_video(message.chat.id, open(file_name, "rb"))


if __name__ == "__main__":
    executor.start_polling(dp, skip_updates=True)

方案2:用线程池隔离同步操作

如果不想修改异步代码结构,可以把TikTokApi的同步调用放到线程池中执行,避免阻塞当前事件循环:

# -*- coding: utf-8 -*-
from aiogram import Bot, Dispatcher, executor, types
import logging
import config
from TikTokApi import TikTokApi
import asyncio

logging.basicConfig(level=logging.INFO)
bot = Bot(token=config.token)
dp = Dispatcher(bot)


@dp.message_handler(commands=['start'])
async def send_welcome(message: types.Message):
    await bot.send_message(message.from_user.id,
                           f'hello',
                           parse_mode="Markdown")


@dp.message_handler(content_types=['text'])
async def text(message: types.Message):
    if message.text.startswith('https://vt.tiktok.com'):
        video_url = message.text
        
        # 定义同步下载函数
        def download_tiktok():
            with TikTokApi() as api:
                video = api.video(url=video_url)
                return video.bytes()
        
        # 在线程池中执行同步操作
        loop = asyncio.get_event_loop()
        video_data = await loop.run_in_executor(None, download_tiktok)
        
        file_name = f"{message.from_user.id}.mp4"
        with open(file_name, "wb") as out_file:
            out_file.write(video_data)
        
        await bot.send_video(message.chat.id, open(file_name, "rb"))


if __name__ == "__main__":
    executor.start_polling(dp, skip_updates=True)

其他TikTok视频下载方案

1. 直接解析视频真实地址

通过异步请求TikTok短链接,从页面内容中提取真实视频地址,无需依赖第三方库:

# -*- coding: utf-8 -*-
from aiogram import Bot, Dispatcher, executor, types
import logging
import config
import httpx
import re

logging.basicConfig(level=logging.INFO)
bot = Bot(token=config.token)
dp = Dispatcher(bot)


async def get_tiktok_real_url(short_url):
    async with httpx.AsyncClient(follow_redirects=True) as client:
        response = await client.get(short_url)
        # 从页面源码中匹配真实视频地址(逻辑可能随TikTok页面更新失效)
        video_match = re.search(r'"playAddr":"(.*?)"', response.text)
        if video_match:
            return video_match.group(1).replace('\\u002F', '/')
    return None


@dp.message_handler(commands=['start'])
async def send_welcome(message: types.Message):
    await bot.send_message(message.from_user.id,
                           f'hello',
                           parse_mode="Markdown")


@dp.message_handler(content_types=['text'])
async def text(message: types.Message):
    if message.text.startswith('https://vt.tiktok.com'):
        real_url = await get_tiktok_real_url(message.text)
        if real_url:
            async with httpx.AsyncClient() as client:
                video_data = await client.get(real_url)
                file_name = f"{message.from_user.id}.mp4"
                with open(file_name, "wb") as f:
                    f.write(video_data.content)
                await bot.send_video(message.chat.id, open(file_name, "rb"))


if __name__ == "__main__":
    executor.start_polling(dp, skip_updates=True)

2. 使用轻量异步下载库

比如TikTokDownloader(需先安装:pip install TikTokDownloader),适配异步框架的同时简化下载逻辑:

# -*- coding: utf-8 -*-
from aiogram import Bot, Dispatcher, executor, types
import logging
import config
from TikTokDownloader import download_video

logging.basicConfig(level=logging.INFO)
bot = Bot(token=config.token)
dp = Dispatcher(bot)


@dp.message_handler(commands=['start'])
async def send_welcome(message: types.Message):
    await bot.send_message(message.from_user.id,
                           f'hello',
                           parse_mode="Markdown")


@dp.message_handler(content_types=['text'])
async def text(message: types.Message):
    if message.text.startswith('https://vt.tiktok.com'):
        # 异步下载视频
        result = await download_video(message.text, output_path="./")
        if result:
            await bot.send_video(message.chat.id, open(result["filename"], "rb"))


if __name__ == "__main__":
    executor.start_polling(dp, skip_updates=True)

内容的提问来源于stack exchange,提问作者sokol

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 10:20:15