TG机器人从0到1搭建(Node.js/Java)

3,504 阅读5分钟

必备的开发文档

Bots: An introduction for developers (telegram.org)

Telegram Bot 使用文档 - KainHuck - 博客园 (cnblogs.com)

创建机器人

这个步骤网上有很多方案,直接采用即可(通过botfather创建)

开发机器人

github上有很多专门用于开发机器人的库,如grammY、telegramsjs、node-telegram-bot-api等,在尝试了多个库之后我最终采用node-telegram-bot-api进行开发,其他库像grammY由于版本更新,目前的开发文档有很多部分是过时的(因为这个情况我被卡了很久)

如果你想使用其他语言的库,请移步 core.telegram.org/bots/sample…

选择部署方式(长轮询和设置webhook)

你的 bot 可以主动拉取信息(长轮询),或者是由 Telegram 服务器主动推送过来(webhook)。

长轮询:主动的给 Telegram 服务器发送了一个请求,来询问是否有新的 update。不需要域名不需要配置,添加telegram的jar包,继承TelegramLongPollingBot重写它的onUpdateReceived方法,在项目启动是开启telegram机器监听,即可接收到你的Telegram bot接收到的消息,让机器人主动向聊天框发送消息用内置的execute方法即可。

webhook:为 Telegram 提供一个可以从公共互联网上访问的 URL(需要有域名的接口)。 无论何时,只要有新的信息发送到你的 bot,Telegram服务器将主动把消息内容封装成Update对象请求到你的url地址,发送消息需要使用官方文档的sendMessage方法。

详细的区别请查看:长轮询 vs. Webhook | grammY

下面采用长轮询的方式部署机器人

使用node-telegram-bot-api实现自动回复(Node.js)

github搜索node-telegram-bot-api,查看README文档使用快速入门方案

npm i node-telegram-bot-api
# 使用TypeScript开发时需要用到的类型声明
npm install --save-dev @types/node-telegram-bot-api
# 快速入门(创建index.ts编写以下代码)
const TelegramBot = require('node-telegram-bot-api');

// replace the value below with the Telegram token you receive from @BotFather
const token = 'YOUR_TELEGRAM_BOT_TOKEN';

// Create a bot that uses 'polling' to fetch new updates
const bot = new TelegramBot(token, {polling: true});

// Matches "/echo [whatever]"
bot.onText(/\/echo (.+)/, (msg, match) => {
  // 'msg' is the received Message from Telegram
  // 'match' is the result of executing the regexp above on the text content
  // of the message

  const chatId = msg.chat.id;
  const resp = match[1]; // the captured "whatever"

  // send back the matched "whatever" to the chat
  bot.sendMessage(chatId, resp);
});

// Listen for any kind of message. There are different kinds of
// messages.
bot.on('message', (msg) => {
  const chatId = msg.chat.id;

  // send a message to the chat acknowledging receipt of their message
  bot.sendMessage(chatId, 'Received your message');
});

注意需要把token换成自己机器人的token

原本以为这部分可以顺利完成,结果运行node .\index.ts后卡住,控制台与tg聊天框均没有反应,通过查找与询问发现tg被国内墙了,虽然已经使用🪜可以使用tg,但是程序并没法发送请求到api.telegram.org服务器,所以需要在程序中使用代理服务,这里以使用V2rayN为例,首先在V2rayN的参数设置中设定好本地socks监听端口(一般默认为10808),然后修改程序添加代理服务

const { SocksProxyAgent } = require('socks-proxy-agent');

// 使用 socks 代理
const agent = new SocksProxyAgent('socks://127.0.0.1:10808');
const token = 'YOUR_TELEGRAM_BOT_TOKEN'; // 检查你的 token 是否正确

const bot = new TelegramBot(token, {
  polling: true,  // 启用 polling
  request: {
    agent,  // 使用代理进行请求
  },
});

bot.onText(/\/ping/, (msg) => {
  const chatId = msg.chat.id;
  bot.sendMessage(chatId, 'pong');
});

// 启动 bot
bot.on('polling_error', (error) => console.log('Polling error:', error));  // 打印错误

注意,在使用代理服务时我原先在bot配置里加入了testEnvironment: true参数,导致运行时程序以为我在模拟环境中测试,并没有与实际的telegarm API服务器通信,从而报错error: [polling_error] {"code":"ETELEGRAM","message":"ETELEGRAM: 401 Unauthorized"}

踩过各种坑之后运行node .\index.ts终于成功了

image.png

使用telegrambots实现自动回复(Java)

考虑到java更适合本人的技术栈,下面介绍如何使用java来开发机器人

首先在core.telegram.org/bots/sample…选一个合适的库,这里使用TelegramBots

新建项目导入依赖(可以去maven repository选一个适合的版本)

<dependency>
    <groupId>org.telegram</groupId>
    <artifactId>telegrambots</artifactId>
    <version>6.9.0</version>
</dependency>

在启动类中配置代理服务并注册

package com.example.telegram_bot;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.telegram.telegrambots.bots.DefaultBotOptions;
import org.telegram.telegrambots.meta.TelegramBotsApi;
import org.telegram.telegrambots.meta.exceptions.TelegramApiException;
import org.telegram.telegrambots.updatesreceivers.DefaultBotSession;

@SpringBootApplication
public class TelegramBotApplication {

    public static void main(String[] args) {
//        SpringApplication.run(TelegramBotApplication.class, args);

        /*
         * 配置代理服务,同Node.js的配置,开启telegram机器监听
         */
        DefaultBotOptions botOptions = new DefaultBotOptions();
        botOptions.setProxyHost("127.0.0.1");
        botOptions.setProxyPort(10808);
        botOptions.setProxyType(DefaultBotOptions.ProxyType.SOCKS5);

        DefaultBotSession defaultBotSession = new DefaultBotSession();
        defaultBotSession.setOptions(botOptions);

        try {
            TelegramBotsApi telegramBotsApi = new TelegramBotsApi(defaultBotSession.getClass());
            ExecBot bot = new ExecBot(botOptions);
            telegramBotsApi.registerBot(bot);
        } catch (TelegramApiException e) {
            e.printStackTrace();
        }

    }
}

创建机器人类

package com.example.telegram_bot;

import org.springframework.stereotype.Component;
import org.telegram.telegrambots.bots.DefaultBotOptions;
import org.telegram.telegrambots.bots.TelegramLongPollingBot;
import org.telegram.telegrambots.meta.api.methods.send.SendMessage;
import org.telegram.telegrambots.meta.api.objects.Message;
import org.telegram.telegrambots.meta.api.objects.Update;
import org.telegram.telegrambots.meta.exceptions.TelegramApiException;
/**
 * 长轮询方式部署机器人
 */
@Component
public class ExecBot extends TelegramLongPollingBot {

    // 填你自己的token和username
    private String botToken = "YOUR_TOKEN";
    private String botName = "YOUR_BOT_NAME";// newbot时你的第二个名字

    public ExecBot() {
        this(new DefaultBotOptions());
    }
    
    // 通过 DefaultBotOptions 允许你指定代理服务器等配置。super(options) 将这个配置传给父类 TelegramLongPollingBot 进行处理
    public ExecBot(DefaultBotOptions options) {
        super(options);
    }

    @Override
    public String getBotToken() {
        return botToken;
    }

    @Override
    public String getBotUsername() {
        return botName;
    }


    // 当 Telegram 服务器发送一个更新(如用户消息)时,这个方法会被触发  update 是包含更新信息的对象
    @Override
    public void onUpdateReceived(Update update) {
        // 检查更新是否包含消息(update.hasMessage()),如果有消息,则提取消息内容和发送者的 chatId
        if (update.hasMessage()) {
            Message message = update.getMessage();
            Long chatId = message.getChatId();
            
            // 拿到用户输入的消息 text
            String text = message.getText().trim();
            String firstName = message.getChat().getFirstName();
            String type = message.getChat().getType();
            String title = message.getChat().getTitle();
            // todo 拿到text 也就是用户输入的内容,进行自己的逻辑判断回复各种消息
            sendMsg("你好", chatId);
        }
    }

    // 回复消息
    public void sendMsg(String text, Long chatId) {
        // 使用 SendMessage 对象构建回复消息
        SendMessage response = new SendMessage();
        // 设置要发送消息的聊天对象、发送内容、消息内容支持 HTML 格式的解析
        response.setChatId(String.valueOf(chatId));
        response.setText(text);
        response.setParseMode("html");
        try {
            // 执行发送消息
            execute(response);
        } catch (TelegramApiException e) {
            e.getMessage();
        }
    }
}

运行成功

image.png