Utilizaremos o módulo node-telegram-bot-api para essa tarefa.
Primeira coisa que precisamos fazer é instalar esse módulo:
npm i -S node-telegram-bot-api
E depois iniciar um arquivo index.js
com as seguintes linhas:
const TelegramBot = require( `node-telegram-bot-api` )
const TOKEN = `SEU TOKEN`
const bot = new TelegramBot( TOKEN, { polling: true } )
Mas onde pego esse
TOKEN
?
Click nesse manolo -> @BotFather <- para incicar o chat com o Bot gerenciador de Bots. <3
Bom como você deve ter percebido ele é auto-explicativo, entao vamos criar nosso bot.
Após executar o comando /newbot
siga suas instruções:
Depois coloque o TOKEN no nosso código:
const TelegramBot = require( `node-telegram-bot-api` )
const TOKEN = `275399831:AAHvjSOiGLxgXmff9wgdECdrZXfMtvnKURw
`
const bot = new TelegramBot( TOKEN, { polling: true } )
ps: ñ precisa se preocupar pois jah revoguei o TOKEN antes de publicar
Depois disso precisamos entender o conceito de como esse BOT funcionara', para isso vamos ver o código mais simples possível que interaja com o BOT.
bot.on( 'message', ( msg ) => console.log( 'msg', msg ) )
Enviando essa mensagem para o BOT iremos ter o seguinte retorno no console:
{ message_id: 2,
from:
{ id: 77586615,
first_name: 'Suissa Refatoreitor',
last_name: 'Tabajara',
username: 'osuissa' },
chat:
{ id: 77586615,
first_name: 'Suissa Refatoreitor',
last_name: 'Tabajara',
username: 'osuissa',
type: 'private' },
date: 1492093704,
text: 'oi' }
}
Logo percebemos que além dos dados basicos:
- message_id: identificador dessa mensagem
- date: data no formato timestamp
- text: texto recebido pelo BOT
Também possuimos 2 outros objetos:
- from: dados de quem enviou a mensagem
- chat: dados do chat aberto entre você e o BOT
Facilmente podemos inferir que o chat.id
é igual ao from.id
, logo o Telegram
cria essa ligação entre você e chat que você abriu.
Guarde bem essa informação pois sera muito útil no futuro.
Analisando esse retorno podemos montar o seguinte Schema para esse resultado:
const from = {
id: Number,
first_name: String,
last_name: String,
username: String
}
const chat = {
id: Number,
first_name: String,
last_name: String,
username: String,
type: String
}
const Schema = {
message_id: Number,
from,
chat,
date: Number,
text: String
}
Logo mais voltaremos nesse assunto dos Schemas.
Para dar continuidade ao nosso BOT iremos utilizar eventos específicos para que ele não pegue TUDO que vier, mas sim apenas o que desejemos.
Vejamos quais sao esses eventos:
message
text
audio
document
photo
sticker
video
voice
contact
location
Esses serão os eventos que utilizaremos por hora, existem muitos outros como você pode conferir na documentação, o link esta abaixo.
fonte: Node.js Telegram Bot API - Usage - Events
Como você viu acima, possuímos o evento text
e como sabemos a função on
sempre
é utilizada para ouvir um evento, por isso o nome da função ja é onText
.
O melhor dela é que possamos passar, como primeiro parametro, uma RegEx para que o BOT execute o callback apenas se o texto enviado pelo usuario "caiba" nessa RegEx.
Utilizaremos o exemplo mais simples que encontramos por aí:
bot.onText( /\/echo (.*)/, ( msg, match ) => {
console.log( `echo msg: `, msg )
console.log( `echo match: `, match )
})
/**
echo msg: { message_id: 7,
from:
{ id: 77586615,
first_name: 'Suissa Refatoreitor',
last_name: 'Tabajara',
username: 'osuissa' },
chat:
{ id: 77586615,
first_name: 'Suissa Refatoreitor',
last_name: 'Tabajara',
username: 'osuissa',
type: 'private' },
date: 1492101864,
text: '/echo blz mein?',
entities: [ { type: 'bot_command', offset: 0, length: 5 } ] }
echo match: [ '/echo blz mein?',
'blz mein?',
index: 0,
input: '/echo blz mein?' ]
*/
O retorno da msg
jah conhecemos, porém ele possui uma propriedade nova: entities
.
Não entrarei nesse escopo agora, entao vamos continuar com o echo
.
O que nos interessa nesse retorno é o seguinte objeto: match
.
[ '/echo blz mein?',
'blz mein?',
index: 0,
input: '/echo blz mein?' ]
Como podemos ver ele é um array que contém o resultado do match testando a mensagem que o BOT recebeu com a RegEx que você definiu no onText
.
Caso você não conheça essa funcao veja como ela funciona executando o seguinte código no Terminal, executando node
antes.
> '/echo blz mein?'.match(/\/echo (.*)/)
[ '/echo blz mein?',
'blz mein?',
index: 0,
input: '/echo blz mein?' ]
Logo conseguimos entender que:
- na posiçao 0: temos o valor total do texto
- na posiçao 1: o texto sem a RegEx
- na posiçao 2: o índice onde foi encontrada a RegEx
- na posiçao 3: a entrada
Agora vamos fazer o BOT enviar como mensagem o mesmo texto recebido no chat,
para isso iremos utilizar a função bot.sendMessage
.
Sua assinatura é bem simples:
- primeiro: o ID do chat onde foi recebido o texto
- segundo: o texto a ser enviado pelo BOT
bot.sendMessage( id, text )
E essa função irah retornar uma Promise, entao sabemos o que fazer né?
const logErrorEcho = ( msg ) => ( err ) =>
console.log( msg, err )
const logSuccessEcho = ( msg, match ) => ( data ) =>
console.log( `Success: `, data )
const sendEcho = ( msg, match ) =>
bot.sendMessage( msg.chat.id, match[ 1 ] )
.then( logSuccessEcho( msg, match ) )
.catch( logErrorEcho( `Error: ` ) )
bot.onText( /\/echo (.*)/, sendEcho )
Para criarmos um comando para fazer uma busca usaremos o axios, primeira vez que usarei ele, sempre usei request/request-promise; com ele iremos fazer uma requisição GET
em https://www.google.com.br/search?q=nomadev e parsear seu HTML, com cheerio para retirarmos as informaçoes necessarias.
Sim isso é um crawler!
Porém quando requisitamos nomadev
ao Google e pegamos o atributo href
:
http.get( URL_BASE + match[ 1 ] )
.then( (response) => {
const $ = cheerio.load( response.data )
$( `.r a` ).each( ( i, elem ) => {
if ( i === 1 ) return false
const url = $( elem ).attr( `href` )
console.log(`url`, url)
})
.catch(function (error) {
console.log(error);
});
Recebemos o seguinte valor: /url?q=http://nomadev.com.br/&sa=U&ved=0ahUKEwiC96G_xKbTAhVFhZAKHQKoALwQFggVMAA&usg=AFQjCNFAoCxThw2mWS4Xvg-PlvnwG0EWdQ
Depois de analisar outras buscas percebi que a url desejada sempre vem adicionada de /url?q=
e &sa=U&ved=0ahUKEwiC96G_xKbTAhVFhZAKHQKoALwQFggVMAA&usg=AFQjCNFAoCxThw2mWS4Xvg-PlvnwG0EWdQ
logo preciso executar um replace
em cada parte para retirar o indesejado:
http.get( URL_BASE + match[ 1 ] )
.then( (response) => {
const $ = cheerio.load( response.data )
$( `.r a` ).each( ( i, elem ) => {
if ( i === 1 ) return false
const url = $( elem ).attr( `href` )
.replace( `/url?q=`, `` )
.replace( /\&sa(.*)/, `` )
console.log(`url`, url)
})
.catch(function (error) {
console.log(error);
});
Prontinho! A possuimos a url desejada e podemos enviar ela como mensagem pelo BOT.
const TelegramBot = require( `node-telegram-bot-api` )
const http = require( `axios` )
const cheerio = require( `cheerio` )
const TOKENS = require( `./token` )
const bot = new TelegramBot( TOKENS.TELEGRAM, { polling: true } )
const URL_BASE = `https://www.google.com.br/search?q=`
const log = ( msg ) => ( result ) =>
console.log( msg, result )
const sendGoogle = ( msg, match ) => {
http.get( `${URL_BASE}${match[ 1 ]}` )
.then( (response) => {
const $ = cheerio.load( response.data )
$( `.r a` ).each( ( i, elem ) => {
if ( i === 1 ) return false
const url = $( elem ).attr( `href` )
.replace( `/url?q=`, `` )
.replace( /\&sa(.*)/, `` )
bot.sendMessage( msg.chat.id, url, { parse_mode: 'Markdown' } )
.then( log( `${url} delivered!` ) )
.catch( log( `Error: ` ) )
});
})
.catch(function (error) {
console.log(error);
});
}
bot.onText( /\/google (.*)/, sendGoogle )
Resultado:
http://nomadev.com.br/ delivered! { message_id: 52,
from:
{ id: 275399831,
first_name: 'meu_exemplo_de_bot',
username: 'meu_exemplo_de_bot' },
chat:
{ id: 77586615,
first_name: 'Suissa Refatoreitor',
last_name: 'Tabajara',
username: 'osuissa',
type: 'private' },
date: 1492262538,
text: 'http://nomadev.com.br/',
entities: [ { type: 'url', offset: 0, length: 22 } ] }
Vamos refatorar para funções puras!
const TelegramBot = require( `node-telegram-bot-api` )
const http = require( `axios` )
const cheerio = require( `cheerio` )
const TOKENS = require( `./token` )
const bot = new TelegramBot( TOKENS.TELEGRAM, { polling: true } )
const URL_BASE = `https://www.google.com.br/search?q=`
const log = ( msg ) => ( result ) =>
console.log( msg, result )
const getURLFrom = ( elem, $ ) =>
$( elem ).attr( `href` )
.replace( `/url?q=`, `` )
.replace( /\&sa(.*)/, `` )
const sendLinkFromGoogle = ( $, msg ) => ( i, a ) =>
( !i )
? bot.sendMessage( msg.chat.id, getURLFrom( a, $ ), { parse_mode: 'Markdown' } )
.then( log( `${getURLFrom( a, $ )} delivered!` ) )
.catch( log( `Error: ` ) )
: false
const sendLink = ( msg ) => ( response ) => {
const $ = cheerio.load( response.data )
return $( `.r a` ).each( sendLinkFromGoogle( $, msg ) )
}
const sendGoogle = ( msg, match ) =>
http.get( `${URL_BASE}${match[ 1 ]}` )
.then( sendLink( msg ) )
.catch( log( `Error: `) )
bot.onText( /\/google (.*)/, sendGoogle )
Bora testar o comando: /google github suissa
Caso você queira treinar e contribuir com esse projeto crie um bot para alguma das seguintes buscas:
- Wikipedia
- mdn.io
- DuckDuckGo
- redtube
- npm
- caniuse
- http.cat
E envie para a pasta src/
o arquivo com o nome: desafioBusca.${seu_github_user}.js
Depois irei ensinar a mordularizar e utilizaremos todas as buscas no mesmo BOT!
TERMINA AQUI POR HORA!!!!
// Logo + falar sobre os parse_mode MD e HTML { parse_mode: 'Markdown' }
Esse erro acontece qnd outro BOT com o mesmo TOKEN esta rodando.
body:
{ ok: false,
error_code: 409,
description: 'Conflict: terminated by other long poll or webhook' }