# 前言

为什么突然想要去做一个 telegram bot 了呢?

这就要说到困扰我很久的一个小问题了,我在刷抖音的过程中,看到有意思的视频或者好看的图片,就很想要把它们给保存下来,作为壁纸或者和别人分享,但是有的时候 保存本地 这个选项是灰色的不让我去保存

image-20231231221356758

而且抖音在图片保存的过程中总是会打上水印,就像下面这个样子,倘若用作壁纸或者日常打开来看的时候就感觉十分的… 别扭

image-20231231221840810

这个时候,我就会把抖音的视频或图文分享链接复制下来,打开微信小程序,找到一个可以抖音无水印下载的小程序,忍受几十秒广告的煎熬之后,终于可以成功的把图片保存到本地,听起来相当的不便吧,然而我已经进行上面的操作不知多少次了,所以亟需一个更加方便的方式来帮助我减少无意义时间的消耗

而在抖音收藏夹图文批量获取这篇 blog 中,我已经利用 python 代码下载到了抖音上的无水印的视频和图片,那么现在要做的就是如何便捷的运行这段 python 代码并返回视频或图片,这个时候我想到了 telegram bot , 因为 tg 我日常也是在用的,打开速度快,界面简洁都是我选择它的原因,而 telegram bot 算是 telegram 的特色吧,之前总是觉得 bot 是个神秘的存在,但是这两天的 bot 做下来,发现其实是相当的简单的,阅读纯英文文档,自我探索的过程也同样充满的乐趣!而且我认为之后我还可以向这个 bot 中加入更多的有创造力的,提高生活效率的功能,敬请期待~

可以来玩玩这个 bot 噢~https://t.me/oacia_bot

bot 的源代码发布在 github 上面 https://github.com/oacia/oacia_bot

image-20231231230233851

# tg bot python 库选择

既然我们选定了核心代码是用 python 编写的,那么选择一个简单易上手的 telegram bot 集成库就显得非常有必要啦,他们封装了 telegram 官方的 bot api, 我们只需要调用 python 库作者集成的函数就可以方便的使用 bot api 的各种功能,现在主流的 tg bot python 库分别是

  • telethon
  • telebot
  • python-telegram-bot

我最终选择的库是 telethon, 原因很简单, 官方文档写的实在是太详细了!而 telebot 我也尝试了,然而 API 的变化实在是太大了,网上使用旧版本的 telebot 所展示的代码完全没有参考价值,python-telegram-bot 用法很复杂,官方文档写的也不是很详细导致我用起来相当痛苦…

# telegram bot

什么是 telegram bot? 这是官方文档中的介绍

Bots are small applications that run entirely within the Telegram app. Users interact with bots through flexible interfaces that can support any kind of task or service.

它其实本质上是基于 Telegram 客户端的第三方程序,我们给机器人发送消息,机器人通过代码处理我们发送的消息之后,再发送回消息给我们,类似于下面我和我的 bot 的简单交互

image-20231231223732245

# bot 实现简单的交互

大家可以看到上方我们刚刚实现了一个简单的交互,接下来我们用 telethon 来实现一下吧~

首先安装 telethon

pip install telethon

代码长这个样子的,一眼看上去是不是很简单呢~

from telethon import TelegramClient, events
api_id = 12345678,
api_hash = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
bot_token: "1234567890:aaaaaaaaaaaaaaaaa-bbbbbbbbbbbbbbbbbb",
session: "oacia_bot",
proxy = ("HTTP", "127.0.0.1", 7890)
client = TelegramClient(session, api_id, api_hash, proxy=proxy).start(bot_token=bot_token)
@client.on(events.NewMessage(pattern='(.*)'))
async def hello(event):
    user = await client.get_entity(event.peer_id.user_id)
    await event.reply("bot has received your message!")
    await client.send_message(user,f"wow!{user.username}, you say {event.text}")
    
client.run_until_disconnected()

这里的 api_id , api_hashbot_token 我将会介绍获取的方法

api_id , api_hashbot_token 千万不要泄漏给其他人,千万不要!!

# api_id api_hash

首先前往 https://my.telegram.org/, 输入手机号,在 telegram 上接收到 login code 后进入

image-20231231224259408

随后点击这里的 API development tools 去创建一个 app, 这里的数据随便填也是没问题的,如果网页一直报错 ERROR , 那么百分之九十是代理的问题,一直换代理直到成功创建 app

image-20231231224449272

App configuration 的位置就可以得到 api_id api_hash

image-20231231224749993

# bot_token

想要创建 telegram bot, 我们需要发送消息给 botfather, 通过 /newbot 命令,输入 bot 的 nameusername 之后,我们的 bot 就被创建好啦~红框框里面的 token 就是我们的 bot_token

image-20231231225759299

之后将上面获取到的三个参数填入代码,运行 python 脚本,访问 t.me/[username] , 就可以和我们创建的机器人交互啦

# bot 云端部署

因为本人从未拥有过一台属于自己的服务器 (二进制根本不需要服务器滴!😄), 所以就将目光转向了网上免费的云服务部署上,经过下面那么多云服务的尝试,我最终选择将服务部署在 render 上面了

# google colab

一开始我是在 google 的 colab 上面执行 bot 代码的,直接在 google 云端硬盘里面创建一个 ipynb 文件并点击就可以进入 colab 了,但是 colab 只能连续运行 12 个小时,pass

image-20231231230811161

# github codespace

后来我把 bot 代码放到 github 的 codespace 里面运行,没想到只能运行几十分钟就断开了 qaq

image-20231231230904330

# vercel

之后我又想到了 vercel, 毕竟之前就有过 vercel 部署静态网站的经验,并且去看了 vercel 的官方文档,是可以支持 python 的运行时的,Using the Python Runtime with Serverless Functions

但是它只能通过访问相应的 api 路由来触发函数的执行,而 telethon 使用的是 MTProto 协议直接和 telegram 服务器建立连接,并不需要对外开放一个路由,这就意味着 telethon 在 vercel 上将无法使用

MTProto is Telegram’s own protocol to communicate with their API when you connect to their servers.

Telethon is an alternative MTProto-based backend written entirely in Python and much easier to setup and use.

因此我又去阅读了 telebot 的官方文档,照着 Flask-ChatGPT-TelegramBot-Vercel 里面的代码重构了原本的脚本

这里我们就需要使用 telegram 的 webhook 功能

什么是 webhook?

简单的说就是将 telegram 服务器发送给 bot 的 message 同时也转发到设定的一个 url 上,消息的 json 格式如下方所示,我们可以处理这个消息并返回给发送消息方相应的消息

{
ok: true,
result: [
        {
             update_id: 11223344,
             message: {
                  message_id: 2,
             from: {
                  id: 123456789,
                  is_bot: false,
                  first_name: "",
                  username: "",
                  language_code: "en"
             },
             chat: {
                  id: 123456789,
                  first_name: "",
                  username: "",
                  type: "private"
             },
             date: 1558784616,
             text: "My first message to this bot"
             }
        }
        ]
}

设置 webhook 方法很简单,浏览器访问这个网站就可以了 https://api.telegram.org/bot{$token}/setWebhook?url={$webhook_url}

这样做了之后确实是可以进行简单的交互的,但是当我让 bot 执行下载抖音图片这种耗时任务的时候,vercel 免费版的弊端就体现出来了, 一个函数最长只能执行 10 秒,10 秒后这个函数将会被强制停止,太艰难了,只能重新找找其他方法咯

# render

最终我的 bot 代码是部署在 render 上面的,免费版每个月 750 小时完全够用了 (要知道一个月最长也就 744 小时呢)

首先我们去 render 上注册一个账号

然后在右上角点击 New , 并创建一个 Web Service

image-20231231234329521

选择 Build and deploy from a Git repository 并点击 Next

image-20231231234639194

你可以将 oacia_bot fork 到你的仓库里面,或者直接用 bot 仓库的 git 链接来创建 https://github.com/oacia/oacia_bot

image-20231231234712486

之后就是设定运行的环境了,名称不重复就可以了,region 表示服务器,哪个服务器离你近就选哪个

image-20231231234819187

接下来这个 Start Command 需要填入 python main.py , 服务器示例选择免费就够用了

image-20231231234859286

再往下看,我们要设定这四个环境变量,前面三个我们之前就获取过了,填入即可,这个 RENDER_NAME 是我们刚刚创建的 Web Service 的名称

image-20231231235238966

这个 RENDER_NAME 的作用是给 bot 设置 webhook 用的,为什么要这样做呢?

因为 render 的免费云服务同样有一个限制,就是如果 15 分钟内没有流量访问我们创建的 web 服务,那么这个服务将会被暂停,直到有流量经过 web 服务时,这个服务才会被重新启动,而我所使用的是 telethon, 要直到服务关了可就是真关了,telethon 创建的 client 也因此无法和 telegram 服务器通信了

所以我的做法是给 bot 设置了一个 webhook

render_name = os.getenv("RENDER_NAME")
if render_name:
    requests.post(f"https://api.telegram.org/bot{bot_token}/setWebhook?url=https://{render_name}.onrender.com/webhook")
    if requests.status_codes == 200:
        print("set webhook successful")

并用 flask 开放了一个 webhook 的路由

# render 必须得起一个 http 服务,否则就会断开连接....
from flask import Flask
app = Flask(__name__)
@app.route('/')
def home():
    return "hello world"
@app.route('/webhook')
def webhook():
    return 'ok'
if __name__ == "__main__":
    app.run(host='0.0.0.0', port=10000)

当有人给 bot 发消息时,telegram 服务器同时也会给我们设置的 webhook 网址发送一个 post 的 http 请求,这样我们的 render 服务即使因为 15 分钟没有流量经过而被暂停了,也会因为 telegram 服务器的流量经过而被重启,telethon 就可以再次成功的和 telegram 服务器通讯啦,这也就意味着 bot 可以一直在 render 上面运行 ~♪(^∇^*)

更新于 阅读次数