使用Telethon与asyncio的Python脚本无法终止,无法生成CSV文件
问题排查与修复方案
核心原因
你的脚本持续运行无法生成CSV,是因为client.iter_messages默认会从最新消息开始,无限制遍历所有历史消息——哪怕已经处理完start_date之前的内容,它还会继续请求更早的消息,导致循环永远无法结束,自然执行不到生成CSV的代码段。
具体修复步骤
1. 添加遍历终止条件
由于iter_messages返回的消息是倒序排列(最新的在前),一旦遇到早于start_date的消息,直接跳出循环即可,后续消息肯定都不符合时间范围:
async for message in client.iter_messages("https://t.me/" + channel_username): msg_date = pd.Timestamp(message.date) # 一旦消息早于起始时间,直接终止遍历 if msg_date < start_date: break if start_date <= msg_date <= end_date: # 剩余逻辑不变
2. 优化日期比较逻辑
不用转成timestamp,直接用pd.Timestamp对象比较,代码更简洁高效:
msg_date = pd.Timestamp(message.date) if start_date <= msg_date <= end_date: # 处理符合条件的消息
3. 优化关键词匹配效率
原代码的嵌套循环顺序会导致重复检查,提前把关键词转成集合,匹配速度更快:
# 提前转成集合 keywords_set = set(keywords) # 匹配逻辑优化 any(word in keywords_set for word in words_in_msg)
4. 规范TelegramClient导入
异步场景下建议使用异步版导入,替代from telethon.sync import TelegramClient:
from telethon import TelegramClient
修复后的完整代码
import asyncio import nest_asyncio from telethon import TelegramClient import pandas as pd username = "MY-USERNAME" # 你的Telegram用户名 api_id = MY-API-ID # 你的API ID api_hash = "MY-API-HASH" # 你的API Hash phone = "MY-PHONE-NO" # 带区号的手机号 channel_username = "clickhouse_en" # 目标频道用户名 start_date_value = "2023-07-01 00:00:00" # UTC起始时间 end_date_value = "2023-07-25 23:59:59" # UTC结束时间 keywords_value = [] # 关键词列表,如["data", "report"] # 应用nest_asyncio适配Jupyter环境 nest_asyncio.apply() async def main(start_date=None, end_date=None, keywords=None): # 转换时间格式 start_date = pd.Timestamp(start_date) end_date = pd.Timestamp(end_date) # 处理关键词,转小写并转为集合提升匹配效率 keywords = [kw.lower() for kw in keywords] keywords_set = set(keywords) data = [] async with TelegramClient(username, api_id, api_hash) as client: async for message in client.iter_messages("https://t.me/" + channel_username): msg_date = pd.Timestamp(message.date) # 超出起始时间范围,直接终止遍历 if msg_date < start_date: break # 检查是否在目标时间范围内 if start_date <= msg_date <= end_date: msg_text_lower = str(message.text).lower() words_in_msg = msg_text_lower.split() # 无关键词时直接保留,或关键词匹配成功时保留 if not keywords or any(word in keywords_set for word in words_in_msg): print(msg_date, message.text, message.sender_id) data.append([msg_date, message.text, message.sender_id]) # 生成DataFrame并导出CSV df = pd.DataFrame(data, columns=["message_date", "message_text", "sender_id"]) df.to_csv('telegram_messages.csv', encoding='utf-8', index=False) # 运行异步函数 loop = asyncio.get_event_loop() loop.run_until_complete(main(start_date=start_date_value, end_date=end_date_value, keywords=keywords_value))
额外说明
- 导出CSV时添加
index=False可以避免生成多余的索引列 - 如果频道消息量极大,可考虑给
iter_messages添加limit参数限制单次请求的消息数量,避免内存占用过高
内容的提问来源于stack exchange,提问作者Leockl
相关产品推荐
相关产品推荐

