土豆不好吃

[Telegram bot系列]0:用Python写一个Telegram Bot 简单的回话bot

文章目录[显示]
这篇文章在 2020年12月25日13:47:40 更新了哦~
(我知道我还有一个SSH系列的坑没填完,别催,越催越不填,再催熄火

终于,又轮到了小土豆我开新系列的日子啦,这也可能是我的为数不多的讲编程的文章。这一系列中我们将详细说说怎么用Python写一个能玩的Telegram bot,顺便学习一下Python中的一些知识点。

前言

假定读者们都知道Telegram是什么,会翻墙并且掌握一定的Python基础。在本系列中我使用Python 2.7和PyCharm,如果要是用Python 3的话最好用Python 3.6

本系列可能会有部分内容翻译自Telegram官方网站,可是官网对于API的说明非常简明易懂,而且有的地方还很幽默。如果英语水平连这都看不懂、理解苦难的话,那说句实在话(不是打击大家),还是尽早转行吧

所以有的时候我也很纠结,我写这一系列干嘛啊,吃饱了没事干么?

目录

未完待定

什么是bot(机器人)

机器人是一种特殊的不额外需要手机号码的账号。用户可以通过给机器人发消息来进行交互。哎呀反正你们都知道啦。

机器人和普通用户有何不同呢?

机器人没有在线状态、没有上次在线时间;

机器人的存储空间是有限的;

机器人不能主动和用户开启会话,换句话说,要用户先跟它说(或者是添加到群里),他才能回消息;

机器人的用户名结尾永远是bot;

把机器人加到群里的时候,默认情况下(开启隐私模式),机器人是不会收到所有的消息的;

机器人不吃不喝,不睡觉也不抱怨(除非编码太垃圾分分钟抛异常?)。

如何创建一个机器人

很简单,跟BotFather说话,他会指引你创建一个机器人。真的是太简单了,大家去官网自己看吧。

在此系列中,我创建一个名为@benny_demo_bot的机器人,TOKEN为XXX我当然不会告诉你啦。

并且,我使用Edit commands添加了如下命令(start、help、settings是全局命令):

start - 自我介绍

help - 帮助

talk - 聊天

搭建开发环境

众所周知的是,Python可以使用pip来安装一些非常好用的第三方库。这里我们使用了pyTelegramBotAPI来和Telegram API进行交互。实际上你想用curl也没人拦着你。

为啥不用另一个star更多的库?我嫌弃那个库麻烦不好用。

准备virtual environment与pyTelegramBotAPI

Virtual environment就是一个虚拟出来的纯净的、不包含第三方库的Python环境(想包含本地已安装的,也不是不行)。

为什么要使用virtual environment呢?唔是这样的,pip默认会把库安装到系统里对应的site-packages里,这样无论你在哪打开Python,都是可以用这个库的。这样听起来好像挺好,但实际上还是有一些弊端的。比如说,在一些项目中,我们最后需要整理出来一个这个项目使用了哪些第三方库,然后指引用户去安装这些库。一个两个还好,多了的话,恐怕开发者也容易找不全、漏掉一些库吧。再加上一些库的依赖、版本等问题,所以如果有必要,那么一定要使用virtual Environment的。

所以我们先创建virtual environment吧。有好几种方式,这里我们就说两种:命令行方式和IDE方式

命令行方式

首先我们需要安装virtual environment,用pip就可以了,网上教程很多,这里我就简述一下。

pip install virtualenv

如果你使用某些Linux发行版,可能会提示pip: command not found,如果是Debian系的话,那么运行:

sudo apt install python-pip

之后我们创建一个目录,使之成为工程目录:

mkdir bot_demo
cd bot_demo
#创建virtualenv
virtualenv ENV
#激活virtualenv(Windows)
ENV\Scripts\activate
#激活virtualenv(Linux) 
source ENV/bin/activate

此时命令行前面会变成(ENV),代表着已经进入了。这个时候再运行pip就会安装到虚拟环境中

pip install pyTelegramBotAPI

IDE方式

使用IDE相比来说很方便。我们只需要新建一个项目,File - Settings - Project interpreter,右侧的齿轮里即可选择create VirtualEnv

我建议将VirtualEnv选择到工程目录下,这样方便我们判断哪个VirtualEnv对应哪个项目。当然,如果你打算把代码push到GitHub,记得把这个目录加到.gitignore里。

之后我们点击加号,安装pyTelegramBotAPI这个package,PyCharm就会自动为我们安装好这个包了。

开始你的项目

我该怎么处理我的TOKEN

为了方便项目的扩展,咱一般都会把配置信息放在一个Python文件中。但是,咱知道,像TOKEN这类东西都是比较敏感的,如果要打算把代码push到GitHub,那么很容易就会泄露这类敏感信息。也千万别以为删除这些信息了就万事大吉了。要知道时光机可是Git的能力之一。万一不幸发生了这种事情,推荐大家用BFG抹掉历史纪录,详细教程可以参考我

那从头开始预防这件事,咱该怎么做呢?一个非常愚蠢但是有效的办法是,新建一个名为config.py的文件,此文件用于保存你的配置信息,并将其加到.gitignore中,另外复制一个名为config-example.py,此文件内容与config.py一致,只是不包含TOKEN敏感信息。

为什么咱不直接把不包含敏感信息的config.py先push上去,然后加入自己的TOKEN,之后再加入到.gitignore中呢?其实这样要倍加小心,哦是这样的,gitignore管不到已经在历史记录中的文件的。

另外,如果你使用私有仓库(并且打算以后公开),那就更简单了。可以什么都不管直接push上去,再打算公开之前抹掉TOKEN再push,然后用BFG抹掉历史记录再force push就可以了。

另一个更好的办法是,创建一个config.py但是不在这里写入真实的配置信息,转而设置环境变量然后用os.environ加判断获取到对应的KEY,如果使用PyCharm的话,在Run/Debug configuration里就可以添加环境变量,当然直接在命令行里设置也可以(windows要用set xxx='123', Linux直接export xxx='123'设置可以考虑写入.bashrc里)

项目结构

这里由于只是一个演示,并不打算push到GitHub,所以就不处理TOKEN啦。

很显然,我们需要一个config.py用于保存配置文件,还需要一个"主程序",这里我就很无耻的叫它main.py啦。

一些解释:

第一行的#!/usr/bin/python用于指定当给文件加x权限并执行时(./main.py)该使用哪个解释器,用法和shell编程中的是一样的;

第二行用于指定编码格式,下面则是注释说明与doc啦。大家不好奇这些是怎么来的吗?实际上是IDE自动生成的啦。我才懒得自己打这些玩意。

在设置中的如下位置即可设定模板,更多信息可以参考JetBrains官网。

config.py

显然我们要在这里放入TOKEN,所以我们直接写一行TOKEN='XXX'即可。我一般习惯把这类变量全大写,给人“常量”的感觉嘛(实际上Python中是没有常量这个概念的)。如下所示

看这时间戳,我写一篇文章容易嘛我!几个小时了……

main.py

首先我们需要import库和我们的配置文件并创建telebot类的实例

import telebot
from config import TOKEN
bot = telebot.TeleBot(TOKEN)

定义接受/start和命令的消息处理函数,如果多个命令都用这一个函数处理,就这样['start','help']

@bot.message_handler(commands=['start'])
def send_welcome(message):
    bot.send_message(message.chat.id, '大家好,我是机器人')

定义接受所有消息的处理函数

@bot.message_handler()
def echo(message):
    bot.reply_to(message, message.text)

另一种reply_to

@bot.message_handler(commands=['help'])
def send_welcome(message):
    bot.send_message(reply_to_message_id=message.message_id, chat_id=message.chat.id, text='有什么可以帮您')

定义程序的入口:

if __name__ == '__main__':
    bot.polling()

我来解释一下:

装饰器

在每个函数前面,我们可以看到有一个@bot.message_handler,这其实是一个Python装饰器。装饰器其实是一个起初听起来觉得什么用都没有、但是用起来却很方便的高阶Python功能。简单说,装饰器可以在运行时改变或增加函数的功能。此话怎讲?

比如说,我们需要在函数开始运行、结束运行的时候输出消息到控制台,大家可能会想着在函数开始和结尾加两个print。没错这样是可以的,但是假如我们有10个函数呢?这代码都没能重用,删除的时候还要删除20次。由于函数在Python中是一等公民,我们可以定义一个嵌套函数(也就是装饰器),配合Python的语法糖@来实现这一功能。

在我们说的打印日志这个例子中,装饰器就可以这么写这么用:

当然在这个例子中,这个装饰器无法处理带参数的函数。要处理函数的参数,我们需要在内层的wrapper的参数中使用*args**kwargs来处理参数(和关键字参数),关于装饰器更多的内容,可以参考奔跑的蜗牛壳《Python 装饰器》

message

Telegram API会返回给我们一组JSON,但是控制台用print打印出来的JSON都是一行,看起来很不舒服,解决方法是使用pprint或者新建一个扩展名为json的文件,将一行json放入,Ctrl + Alt + L格式化。

在message这个参数中,有几个是比较重要的,我说几个个人比较常用的:

message.chat.id 类型为int,聊天ID,如果是和机器人私聊,那么这个ID也就是用户的user_id;如果是群组的话,那么就是群组的id

message.text 类型为unicode,用户发给机器人的聊天内容

message.message_id 类型为int,用户发给机器人的消息编号,再使用"回复"功能时会用到这个编号。

send_message与reply_to_message

send_message用于给用户发送消息,必须要有至少两个参数,一个是chat_id,一个是text;

reply_to则是回复某条消息,是send_message(message.chat.id, text, reply_to_message_id=message.message_id, **kwargs)的方便用法,需要两个参数,一个是message,一个是回复的内容;

如果我们要用send_message来实现relpy_to_message,那么就要手动用关键字参数指定回复哪条消息,如代码中的help命令所示。

if __name__ == '__main__':

这一行则定义了这个Python程序的入口,在他下面运行bot.polling()方法。这个方法可神奇了呢,他会帮你处理各种事件,自动帮你从API里取回消息,基本不用你干预。

如果我们不用__name__控制的话,那么当在其他文件中import时,也就顺便运行这个文件啦。这很明显不是我们想要的结果。

运行与调试

如果一切顺利的话,当你点击运行时,跟机器人说话,它就会回复你啦。当然啦,运行(run)与调试(debug)其实还是有些区别的,关于这的一些技巧,我们可以以后再谈~

哦对了,我们还需要导出依赖,方便别人也能够用啊!

很简单,进入到virtual env,运行如下命令:

pip freeze > requirements.txt

别人用的时候,pip install -r requirements.txt就可以安装对应的依赖啦。

我该怎么长期运行我的机器人呢

这个问题问得好!首先你得有个在海外的服务器(或者让程序走代理),可以考虑用用nohup或者screen,这样当你关掉终端之后,程序还会继续运行。呃,那些用Windows做服务器的,当我什么都没说好了。

当然了正经的办法,是要用systemd或者supervisor的。具体可以参考这里

我想要任务计划机器人,怎么办

这个问题问得也很好。我们可能需要某种机器人,每十分钟给用户发送一条消息。

此时我的建议是,如果需求很简单,那么使用操作系统自带的任务计划功能来执行脚本(Linux为cron)。

可能有人会有反对意见了。Python里有很多优秀的任务调度、任务计划库,比如说apscheduler。这样也是可以的,只不过需要多写点代码!

当然了,有些时候我们的需求比较灵活,操作系统提供的任务计划用起来会很麻烦,此时就只能用一些任务调度的库啦。

下一篇打算讲点什么呢

如果我们的机器人只能以固定的模式讲话,那么显然是不行的!

那么下一篇,我们就要尝试着接入其他服务(使用pycurl发送POST或者GET请求),操作数据库,给机器人加入"正在输入"的特效,更加深入的理解Telegram Bot API。当然了,我下一篇说不定等到啥时候,所以,别太期待。


文章版权归原作者所有丨本站默认采用CC-BY-NC-SA 4.0协议进行授权|
转载必须包含本声明,并以超链接形式注明原作者和本文原始地址:
https://dmesg.app/tgbot0.html
退出移动版