这次我们来看一个和 Telegram 搜索资源、搜索引擎搭建有关的实战教程。
核心不是把 Telegram 改成一个花哨的网页,而是解决一个很实际的问题:当你面对大量频道、群组和历史消息时,怎么快速找到想要的内容,怎么把自己有权访问的消息整理成本地索引,怎么做成可以重复调用的搜索接口。Telegram 本身有消息搜索能力,平时在某个聊天内搜关键词够用;但频道一多、消息一多、需要反复过滤的时候,直接搜就明显不够了。
更稳妥的做法是把它拆成三层。第一层用客户端和 Bot 的搜索能力做临时检索;第二层用 Telethon 把消息批量采集到本地 SQLite 数据库;第三层把数据库封装成 HTTP 搜索接口,供脚本、网站或者其他工具调用。这套方案不需要 GPU,对显存完全没有需求,普通服务器就能跑,适合做内容留档、信息聚合、群聊资料库和个人知识库。
本文会带读者完成完整链路:环境准备、账号凭证获取、Telethon 客户端搭建、消息关键词搜索测试、自定义 Bot 搜索指令、消息采集入库、批量任务调度、搜索接口封装,以及常见问题排查。使用边界先说明:本文不讨论任何网络访问配置,所有操作必须在当地法律法规、Telegram 服务条款以及内容授权允许的范围内进行。
1. 核心能力速览
这个教程不是下载某个现成软件,而是通过组合 Telegram 已有搜索能力和 Telethon 客户端库,搭建一套轻量级“Telegram 搜索资源 + 搜索引擎”方案。关键能力先用一张表快速过一遍:
| 能力项 | 说明 |
|---|---|
| 项目类型 | Telegram 搜索技巧 + 基于 Telethon 的轻量搜索引擎搭建教程 |
| 主要功能 | 关键词消息检索、频道/群组内容采集、自定义 Bot 搜索指令、HTTP 搜索接口、批量轮询 |
| 运行环境 | Python 3.9+,普通 CPU 即可,无需 GPU,无显存占用 |
| 依赖工具 | Telethon、SQLite 标准库,可选 Flask/FastAPI 做接口 |
| 启动方式 | 命令行启动 Python 脚本,可常驻运行 |
| 接口能力 | 可封装为本地 HTTP 搜索接口,支持 curl / Python 调用 |
| 批量任务 | 支持按频道列表逐个采集,配合定时任务做增量轮询 |
| 数据存储 | SQLite 本地数据库,适合十万级消息以内检索 |
| 适合场景 | 内容留档、群聊资料库、内部信息聚合、自定义搜索工具 |
| 合规要求 | 必须遵守当地法律法规、Telegram 服务条款与内容授权规则 |
从表里可以快速得到几个判断点:
- 不需要 GPU,不消耗显存,低成本服务器就能跑。
- 支持 API 封装,用 Flask 可以快速暴露搜索接口。
- 支持批量任务,把频道列表写进配置,循环采集即可。
- 启动方式不是 WebUI,而是命令行 Python 脚本,适合放在服务器后台运行。
- 使用前需要准备 Telegram 账号凭证和 Bot Token。
2. 适用场景与使用边界
先回答一个最关键的问题:这个方案到底适合谁,不适合谁。
适合的场景很明确。如果你需要定期把某个公开频道里的文字消息汇总留档,或者要给多个人维护一个内部检索入口,或者想把一段时间内某个群聊里的讨论内容保存下来做二次分析,这套“Telethon 采集 + SQLite 存储 + HTTP 接口”的思路都适用。它的核心价值是两点:第一,把分散在多个聊天的内容集中到一个本地库;第二,用本地 SQL 查询替代每次实时请求 Telegram 服务器,检索更快、更稳定。
不适合的场景也很清楚。这个方案不适合采集私密聊天内容,不适合把未授权媒体文件批量转发保存,也不适合把搜索结果公开到没有访问控制的站点上。Telethon 虽然能够以客户端身份读取账号有权访问的聊天,但这只是技术能力,不等于可以无视授权。本节说的“资源”,严格限定为已授权、可公开访问或你有权读取的频道/群组内的文本消息和文字内容。
合规边界必须划清楚:
- 不要采集和保存任何你没有权限访问的私密聊天记录。
- 不要将抓取到的消息公开传播,尤其是涉及个人信息、内部讨论和未授权内容。
- 不要批量下载和二次分发受版权保护的图片、视频、音频等媒体文件。
- 账号凭证和个人 session 文件不要提交到公开代码仓库,不要泄露给第三方。
- 使用个人主账号批量采集前要慎重,高频请求可能触发账号风控限制,后果由使用者自行承担。
3. 环境准备与前置条件
在开始写代码之前,先把环境确认好。
硬件方面,这个方案对性能要求很低。单个 Telethon 客户端进程主要消耗网络带宽和少量内存,普通 1 核 2G 的 Linux 服务器就能跑。磁盘空间需要根据采集量设计,如果只保存文字消息,几万条通常只占几 MB 到几十 MB;如果后续要扩展媒体文件,磁盘占用会快速上升,所以第一章建议先把范围控制在文本消息。
软件方面需要准备:
- Python 3.9 或更高版本。
- pip 包管理工具。
- 建议使用虚拟环境隔离依赖。
- 需要一个可以正常访问 Telegram API 的网络环境,访问配置不在本教程范围内。
凭证准备是很多人容易卡住的地方,需要准备两套东西。
第一套是 Telegram 账号的api_id和api_hash。在 Telegram 官方应用管理平台创建一个应用,创建完成后就能拿到这两个值。这个凭证本质上是你的客户端身份标识,Telethon 登录时需要用到。使用个人客户端模式搜索消息,就是通过这组凭证以你的账号身份去访问有权查看的聊天记录。
第二套是 Bot Token,用于 Bot 模式的搜索指令。在 Telegram 中向 @BotFather 发送命令创建机器人,会得到一个123456:ABC...格式的 Token。Bot 模式适合部署成群聊内的搜索机器人,但它的消息读取范围受权限限制,通常只能处理 Bot 所在聊天中它能访问到的消息,后面会具体讲。
创建虚拟环境并安装依赖:
python -m venv venv source venv/bin/activate # Windows # venv\Scripts\activate pip install telethon pip install flasktelethon是核心依赖,负责以 MTProto 协议连接 Telegram API;flask用于最后封装 HTTP 搜索接口,可以按需要选装。
4. 安装部署与启动方式
先用一个最小脚本验证账号凭证和 Telethon 客户端能否正常工作。新建search_client.py:
from telethon import TelegramClient api_id = 123456 # 替换为你在官方应用管理平台获取的 api_id api_hash = "0123456789abcdef0123456789abcdef" # 替换为 api_hash client = TelegramClient("search_session", api_id, api_hash) async def main(): await client.start() me = await client.get_me() print("登录账号:", me.username or me.first_name) if __name__ == "__main__": import asyncio asyncio.run(main())运行:
python search_client.py第一次运行会要求输入手机号,然后输入登录验证码。如果账号开启了双重验证,还要再输入密码。登录成功后,目录下会生成一个search_session.session文件,这个文件保存了登录状态,后续运行不需要重新输入验证码。
如果要用 Bot 模式启动,代码会稍有不同:
from telethon import TelegramClient api_id = 123456 api_hash = "0123456789abcdef0123456789abcdef" bot_token = "123456:ABC..." client = TelegramClient("search_bot_session", api_id, api_hash) async def main(): await client.start(bot_token=bot_token) me = await client.get_me() print("Bot 登录:", me.username) if __name__ == "__main__": import asyncio asyncio.run(main())这里要注意,Bot 模式下client.get_me()返回的是机器人账号,而不是你的个人账号。Bot 消息读取范围更小,但好处是更适合部署在群聊中给多个成员共用,不会把个人账号会话暴露出去。
启动脚本的方式很简单,确认屏幕上出现登录账号信息,就说明环境准备完成。这个阶段的常见问题是验证码输入错误、手机号不匹配、历史 session 被风控,排查思路放在第九章统一处理。
5. 功能测试与效果验证
5.1 在指定聊天中搜索关键词
最小客户端跑通后,先测最简单的关键词搜索。新建search_test.py:
from telethon import TelegramClient api_id = 123456 api_hash = "0123456789abcdef0123456789abcdef" client = TelegramClient("search_session", api_id, api_hash) async def main(): await client.start() chat = await client.get_entity("目标频道的username") count = 0 async for msg in client.iter_messages(chat, search="Python", limit=30): text = (msg.text or "").replace("\n", " ")[:60] print(msg.date, msg.sender_id, text) count += 1 print("命中条数:", count) if __name__ == "__main__": import asyncio asyncio.run(main())关键点有三个:
get_entity支持频道/群组的 username、链接、邀请链接中的 ID。如果目标聊天是私密群,账号必须已经加入。iter_messages的search参数指定关键词,Telethon 会把请求转换为服务端的消息搜索。limit限制返回条数,不传 limit 时会从头到尾遍历所有命中消息。
运行后输出每一条命中的消息时间和前 60 个字符,方便快速确认搜索是否生效。
测试成功的判断标准很简单:能打印出与关键词匹配的消息,并且消息内容确实来自目标聊天。如果打印为空,优先检查关键词是否真的存在于该聊天中,以及账号是否加入了目标聊天。
5.2 按发送人过滤与组合条件
搜索通常需要组合条件。Telethon 的iter_messages还支持from_user参数,用来限定发送人:
# 搜索某个用户发表的包含关键词的消息 async for msg in client.iter_messages( chat, search="Python", from_user="目标userId或username", limit=20 ): print(msg.date, msg.text[:80])这种过滤适合做定向内容监测,例如查看某一频道内某个作者发布的特定主题内容。Telethon 还支持时间范围过滤,但需要拼接offset_date或处理日期边界,实际使用中按需查阅官方方法签名即可。
5.3 自定义搜索 Bot 指令
客户端测试没问题后,可以做一个 Bot 模式搜索机器人。用户向 Bot 发送/search 关键词,Bot 返回当前聊天中最近命中的消息。先设置环境变量:
export TG_API_ID=123456 export TG_API_HASH=0123456789abcdef0123456789abcdef export TG_BOT_TOKEN=123456:ABC...然后新建search_bot.py:
import os from telethon import TelegramClient, events api_id = int(os.getenv("TG_API_ID", "0")) api_hash = os.getenv("TG_API_HASH", "") bot_token = os.getenv("TG_BOT_TOKEN", "") client = TelegramClient("search_bot_session", api_id, api_hash) @client.on(events.NewMessage(pattern="/search")) async def handler(event): parts = event.raw_text.split(maxsplit=1) if len(parts) < 2: await event.reply("用法:/search 关键词") return keyword = parts[1] chat = event.chat hits = [] async for msg in client.iter_messages(chat, search=keyword, limit=10): text = (msg.text or "").replace("\n", " ")[:100] hits.append(f"[{msg.date:%m-%d %H:%M}] {text}") result = "\n".join(hits) if hits else "当前聊天没有命中消息。" await event.reply(result) async def main(): await client.start(bot_token=bot_token) print("搜索 Bot 已启动") await client.run_until_disconnected() if __name__ == "__main__": import asyncio asyncio.run(main())启动:
python search_bot.py把 Bot 拉入目标群,然后在群里给 Bot 发送/search 某关键词。如果一切正常,Bot 会回复最近 10 条与关键词匹配的消息。
这里要说明 Bot 模式的限制:Telethon 以 Bot Token 启动后,只能读取当前聊天中 Bot 有权访问的消息。对于默认开启了隐私模式的群聊,Bot 未必能看到所有历史消息,所以搜索结果可能比个人客户端模式少。要做更完整的搜索,建议使用个人客户端模式,或者把 Bot 设置为允许读取全部消息。
6. 消息采集入库与基础搜索引擎
实时搜索的问题在于,每次都要请求 Telegram 服务器,消息一多速度就慢,而且容易碰到接口限流。更实用的方式是先采集、后搜索:把消息落到本地 SQLite,再用 SQL 查。
先建表:
CREATE TABLE IF NOT EXISTS messages ( id INTEGER PRIMARY KEY, chat_id INTEGER, msg_id INTEGER, sender_id INTEGER, date TEXT, text TEXT, UNIQUE(chat_id, msg_id) );UNIQUE(chat_id, msg_id)可以避免同一聊天内的同一条消息重复入库,这是后期增量采集的基础。
采集函数:
import sqlite3 from telethon import TelegramClient conn = sqlite3.connect("telegram.db") async def archive_chat(client, chat, keyword=None, limit=200): async for msg in client.iter_messages(chat, search=keyword, limit=limit): text = msg.text or "" if not text.strip(): continue conn.execute( "INSERT OR IGNORE INTO messages(chat_id, msg_id, sender_id, date, text) VALUES (?, ?, ?, ?, ?)", (chat.id, msg.id, msg.sender_id, msg.date.isoformat(), text) ) conn.commit()这里保存的是消息文本,媒体消息的说明文字一般也在msg.text里。
落库完成后,就可以用本地 SQLite 做搜索:
def local_search(keyword, chat_id=None, limit=50): if chat_id: rows = conn.execute( "SELECT date, sender_id, text FROM messages " "WHERE chat_id = ? AND text LIKE ? " "ORDER BY date DESC LIMIT ?", (chat_id, f"%{keyword}%", limit) ).fetchall() else: rows = conn.execute( "SELECT date, sender_id, text FROM messages " "WHERE text LIKE ? " "ORDER BY date DESC LIMIT ?", (f"%{keyword}%", limit) ).fetchall() return rows这个函数的优势是访问本地数据库,不需要请求 Telegram,速度明显更快,而且可以跨多个聊天统一检索。数据量在万级到十万级的时候,LIKE 查询的表现够用;再往上就需要考虑 SQLite FTS5 全文索引或外部搜索引擎。
7. 接口 API 与批量任务
7.1 封装 HTTP 搜索接口
本地搜索函数写好后,可以用 Flask 暴露成接口。新建api_app.py:
from flask import Flask, request, jsonify app = Flask(__name__) @app.route("/search") def search(): q = request.args.get("q", "") if not q: return jsonify({"error": "缺少 q 参数"}), 400 rows = local_search(q) return jsonify({ "count": len(rows), "items": [list(r) for r in rows] }) if __name__ == "__main__": app.run(host="127.0.0.1", port=8765, debug=False)启动:
python api_app.py测试接口:
curl "http://127.0.0.1:8765/search?q=Python"返回结果是一段 JSON,包含命中的数量和时间、发送人、消息文本。接口只绑定127.0.0.1,默认只允许本机访问,避免直接暴露到局域网。如果需要外部服务调用,建议在前面加网关或限制来源 IP。
7.2 批量采集与定时任务
批量任务的核心逻辑是循环频道列表,逐个调用采集函数:
CHANNELS = [ "channel_a", "channel_b", "channel_c", ] async def run_batch(): for name in CHANNELS: try: chat = await client.get_entity(name) await archive_chat(client, chat) except Exception as exc: print("采集失败:", name, exc)加上定时任务后,就能实现每天自动增量采集。最简单的方式是系统 crontab:
# crontab 示例:每天凌晨 2 点执行一次 0 2 * * * cd /path/to/project && python batch_collect.py >> collect.log 2>&1批量采集最容易遇到的问题就是接口限流。Telethon 在遇到限流时会抛出FloodWaitError,代码里需要捕获:
from telethon.errors import FloodWaitError async def safe_archive(client, chat): while True: try: await archive_chat(client, chat) break except FloodWaitError as e: print("触发限流,等待", e.seconds, "秒") await asyncio.sleep(e.seconds)等待时间以异常返回的秒数为主,不要为了赶进度频繁重试。更合理的做法是在任务里主动 sleep,降低请求频率,避免触发更长的限制。
8. 资源占用与性能观察
运行这套方案时,可以从几个角度观察资源占用。
进程内存方面,单个 Telethon 客户端常驻进程内存占用通常不大,具体取决于会话数量、缓存和并发任务数。之前说的“普通 1 核 2G 服务器能跑”,在实际部署中偏向保守估计,真实占用需要以本机观察为准。
显存和 GPU 完全用不到,这是这个方案对入门用户比较友好的地方。主要瓶颈在 Telegram 接口请求频率和 SQLite 查询速度。
影响性能的关键参数:
limit控制单次采集条数,设置过大会导致耗时长,容易触发限流。- 搜索范围越宽,耗时越长;限定
chat_id查询通常比全库查询快。 - SQLite 数据量越大,LIKE 全表扫描越慢。数据量明显增长后,建议切换 FTS5 全文索引。
- 频繁的
commit()可能影响写速度;大批量采集时可以采用批次提交。
如果是个人使用,建议在脚本里输出每批任务的耗时、入库数量和失败数量,方便判断任务是否正常运行。例如:
[2025-06-01 02:00:00] channel_a: 拉取 200 条,入库 180 条,耗时 12.3s [2025-06-01 02:00:15] channel_b: 拉取 200 条,入库 0 条,耗时 3.1s这种日志对批量任务排查很有用。
9. 常见问题与排查方法
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
| 登录时反复提示验证码错误 | 手机号输入错误或会话触发风控 | 检查手机号是否带国家区号,停止短时间频繁重试 | 等待一段时间后再尝试,不要连续轮询验证码 |
| 提示找不到目标实体 | 目标频道/群组 username 错误,或账号未加入 | 在 Telegram 客户端确认目标聊天真实存在 | 修正 username,先加入目标聊天 |
| 消息搜索没有命中结果 | 关键词不存在、目标聊天无权限读历史 | 在客户端手动搜索同一关键词 | 换成已知存在的关键词,加入目标聊天 |
| 请求频繁报限流 | 单次任务请求过多、频率过高 | 查看异常信息中的等待秒数 | 捕获 FloodWaitError,降低 limit,增加 sleep |
| 大量消息没有入库 | 消息为纯媒体消息,无文本 | 打印消息类型观察 | 使用 msg.text 或 msg.message 判断,必要时单独处理媒体文件 |
| Bot 收不到搜索命令 | Bot 未加入聊天或被群权限限制 | 检查群里 Bot 成员状态 | 将 Bot 加入目标群,调整群内 Bot 消息权限 |
| 搜索接口响应越来越慢 | SQLite 数据量增大,LIKE 扫描变慢 | 查看查询日志和表数据量 | 增加索引、限制结果集条数、调研 FTS5 全文索引 |
| session 文件损坏或登录态丢失 | session 被删除或账号触发风控 | 检查 session 文件是否存在 | 删除 session 后重新登录 |
这里强调一点:账号触发风控后,正确的做法是立即停止请求、等待限制自然解除。不要尝试任何绕过限制的方案,这既违反平台规则,也存在账号被封的风险。
10. 最佳实践与使用建议
把这套方案从“能跑”提升到“稳定跑”,下面几点值得做。
凭证管理:把api_id、api_hash、bot_token全部放到环境变量里,不要写死在代码里。代码仓库即使公开,也不应该带上凭证。
数据管理:消息表按聊天和时间周期性归档,避免单表无限增长。定期备份telegram.db,可以用 SQLite 的.backup命令或文件复制,备份文件放到独立目录。
任务设计:批量采集任务加入日志和失败重试,每次只处理一个频道,失败后跳过并记录错误。任务内部加锁,避免多个定时任务重复执行造成重复采集和限流。
接口访问控制:搜索接口默认只绑定本机,不要直接暴露公网。如果需要给团队使用,建议放在内网或加访问令牌。接口只做只读查询,不要在接口里暴露采集配置和凭证信息。
合规使用:只处理有权访问且授权允许的内容。涉及人脸、声音、个人信息时必须确认授权。不要采集私密聊天,不要传播未授权媒体文件,不要将抓取内容用于侵权或骚扰用途。
个人账号保护:如果使用个人主账号运行批量任务,控制任务频率和采集范围,避免触发风控。如果条件允许,单独使用 Bot 账号或只读账号执行采集,主账号保持可恢复的干净状态。
11. 总结与下一步
这一篇把 Telegram 搜索资源和搜索引擎搭建的完整链路串了一遍:先用 Telethon 做实时关键词搜索,再把消息批量采集到 SQLite,最后用 Flask 封装成 HTTP 搜索接口,配合定时任务实现了轻量级批量搜索引擎。
整个项目最值得优先验证的是基础关键词搜索,也就是 5.1 节的最小脚本。只要这一步能跑通,说明账号凭证、Telethon 环境和目标聊天权限都没有问题。最容易踩的坑是接口限流,几乎所有批量任务最终都会碰到 FloodWaitError,正确做法是捕获异常并等待自然解除,而不是提高请求频率。
后续可以继续扩展的方向也不少:把 SQLite 换成 FTS5 全文索引,搜索速度和准确度都会提升;增加时间范围和发送人过滤,让检索更精确;加一个简单的 Web 管理页面,方便查看采集状态;把采集任务接入告警系统,让新增消息能实时推送到自己的工具链里。
先从最小搜索脚本开始,跑通后再逐步加批量采集和接口,你的轻量 Telegram 搜索引擎就算是正式上线了。