Linux Kamarada

Como programar um robô que tuíta toda manhã com Node.js

Esse é mais um da série: resolvendo problemas do dia a dia de forma criativa com scripts.

Provavelmente você já conhece a rede social Twitter. Se acompanha as notícias, talvez já tenha ouvido falar em robôs do Twitter. Mas o que são esses robôs do Twitter?

Um robô (bot) do Twitter é um programa de computador que controla uma conta do Twitter. Ele consegue fazer praticamente todas as ações que um usuário humano pode fazer no Twitter: tuitar, retuitar, curtir, seguir ou deixar de seguir outras contas, enviar ou responder mensagens diretas, monitorar tuítes contendo determinada palavra ou hashtag.

Robôs podem ser usados para as mais diversas finalidades: eu já vi robôs que compartilham a previsão do tempo de cidades, tem um robô que retuíta postagens sobre Linux que é o @LlnuxBot (sic) — quase sempre ele retuíta as postagens do @LinuxKamarada. Há também robôs mais polêmicos, que disparam mensagens em crítica ou apoio a políticos.

Nesse tutorial, você verá como programar um robô do Twitter. Aqui, vou usar como referência o sistema operacional Linux, mais especificamente a distribuição Linux Kamarada. Usuários do openSUSE ou derivados também podem seguir à risca esse tutorial.

As tecnologias que vou usar não são exclusivas do Linux ou do Linux Kamarada, de modo que usuários de outros sistemas, como, por exemplo, Windows ou macOS, com alguma pesquisa adicional também podem reproduzir esse tutorial.

Na verdade, o objetivo desse texto não é ser uma aula completa de programação nos mínimos detalhes, mas um estudo de caso de como programação pode ser usada de forma simples para resolver problemas simples do dia a dia, e quem sabe te motivar a aprender a programar. Ao longo do texto, deixarei links onde você pode ler mais sobre os componentes.

Todo estudo de caso começa com a análise do problema a ser resolvido. Então, vamos lá.

Por que eu decidi criar um robô do Twitter?

O problema

Nessa seção, vou tirar um pouco o chapéu de “eu técnico” e ser apenas o “eu pessoa”. Você pode imaginar como se o “eu pessoa” estivesse demandando um serviço para o “eu técnico.”

Nesse ano de 2020, é desnecessária uma longa introdução sobre o tema Covid-19. A pandemia, seu avanço e medidas de prevenção são constantemente abordadas pelos jornais e discutidas pelas pessoas. Inclusive eu já fiz um texto aqui sobre como seu computador com Linux pode ajudar nas pesquisas científicas sobre a Covid-19:

No entanto, pessoalmente, me incomoda a percepção de que alguns veículos de mídia trazem com muita ênfase os dados total acumulado de casos confirmados e total acumulado de mortes, mas não trazem o dado total acumulado de casos recuperados. Veja bem, não é que eles trazem esse dado com pouca ênfase: eles simplesmente não trazem.

Exemplo de [notícia do G1](https://g1.globo.com/bemestar/coronavirus/noticia/2020/12/10/casos-e-mortes-por-coronavirus-no-brasil-em-10-de-dezembro-segundo-consorcio-de-veiculos-de-imprensa.ghtml) que enumera os casos confirmados e as mortes, mas não os casos recuperados.

Exemplo de notícia do G1 que enumera os casos confirmados e as mortes, mas não os casos recuperados.

Experimente abrir qualquer uma das notícias a seguir, teclar Ctrl + F e procurar na página por recupera (não precisa digitar a palavra toda, na verdade essa pesquisa poderia trazer várias palavras parecidas, como recuperar, recuperados, recuperaram, recuperação, etc.):

O navegador vai informar que não encontrou nada parecido com recupera nessas páginas.

Uma estatística mais completa — que inclui o total acumulado de casos recuperados — pode ser obtida no site do Ministério da Saúde sobre a Covid-19 (covid.saude.gov.br):

Repare que os números desse site não são exatamente iguais aos daquela notícia, mas são bem próximos. Isso pode ser devido aos diferentes horários em que foram atualizados.

Minha opinião é que as pessoas deveriam ser informadas das estatísticas completas. Se, por um lado, o número de mortes pode trazer medo, por outro lado, o número de recuperados (muito maior, aliás) pode trazer esperança, que nesse momento muita gente precisa. E foi pensando em balancear essa divulgação de informações que eu decidi criar um robô do Twitter para divulgar todo dia o número de recuperados até o momento.

Certo, vestindo de novo o chapéu do “eu técnico” a partir de agora…

Resumo: o objetivo é desenvolver um robô que todo dia vai obter do site do governo o número de pessoas que se recuperaram da Covid-19 até o momento e compartilhar esse número no Twitter.

Lista de “ingredientes”

Para desenvolver esse robô, que será em formato de um script, vamos precisar de:

  1. Uma linguagem de programação;
  2. Uma conta no Twitter (uma conta normal e uma conta de desenvolvedor);
  3. Uma forma de tuitar a partir do script;
  4. Uma forma rodar o script de tempos em tempos; e
  5. Uma forma de o script obter os números do site do governo.

1) Linguagem: JavaScript

Como vamos obter informações a partir de uma página da Internet, pensei que não haveria linguagem de programação melhor para implementar nosso robô que aquela já presente nos navegadores e já usada em muitos sites: JavaScript.

Vejamos como extrair da página o número de recuperados usando JavaScript.

Clique com o botão direito do mouse em cima do número de casos recuperados e clique em Inspecionar Elemento:

Aqui estou usando o navegador Mozilla Firefox, mas isso pode ser feito de forma semelhante em qualquer navegador.

Identifique no código-fonte onde está o número de recuperados:

Perceba que ele é um texto dentro da primeira <div> de classe lb-total da página.

Alterne para a aba Console e execute o seguinte comando em JavaScript:

1
document.getElementsByClassName('lb-total')[0].lastChild.data.trim()

Ele retorna direitinho o número de recuperados como está na página:

Confesso que “descobrir” esse comando foi uma combinação de pesquisa e tentativa e erro.

Mas aí pode surgir a pergunta: normalmente o JavaScript é usado dentro de sites e navegadores. Podemos usá-lo também para escrever programas de computador desktop?

Desde 2009, a resposta a essa pergunta é sim, graças ao Node.js, que é um ambiente de execução (runtime) do JavaScript que permite desenvolver tanto sistemas web quanto programas desktop usando essa linguagem de programação.

Para instalar o Node.js no openSUSE, abra uma janela do Terminal e execute como root:

1
# zypper in nodejs14

Para referência futura, hoje esse comando instala no openSUSE Leap 15.2 (assim como no Linux Kamarada 15.2) a versão 14.15.0 do Node.js, e no openSUSE Tumbleweed a versão 14.15.1. Você pode pesquisar pelos pacotes do Node.js em software.opensuse.org.

O site do Node.js oferece as versões 14.15.1 LTS (suporte por mais tempo) ou 15.3.0 Atual.

O comando acima também instala, além do Node.js, o NPM, que é o Node Package Manager (gerenciador de pacotes do Node.js). Vamos usá-lo para instalar as bibliotecas de terceiros que vamos precisar para desenvolver nosso robô.

Dando prosseguimento, execute o comando a seguir para se certificar de que o Node.js está funcionando, ele deve informar a versão do Node.js que foi instalada:

1
2
$ node -v
v14.15.0

Façamos um rápido “olá, mundo” em JavaScript com Node.js.

Para isso, crie uma pasta para o projeto. Vou chamá-la de twitter-bot.

Abra o aplicativo Editor de texto, copie o seguinte conteúdo e cole dentro do editor:

1
console.log ('Olá, mundo!');

Salve esse arquivo dentro da pasta do projeto com o nome robo.js.

No terminal, na pasta do projeto, execute o script com o comando a seguir:

1
2
$ node robo.js
Olá, mundo!

Como prometido, não entrarei em detalhes. Se quiser mais informações, consulte:

Linguagem escolhida, ambiente instalado e testado, vamos para o próximo passo.

2) Criando as contas no Twitter

Vamos precisar de uma conta (normal) no Twitter e uma conta de desenvolvedor do Twitter.

Não vou mostrar aqui como criar uma conta no Twitter porque é trivial: você acessa twitter.com, clica no botão Inscrever-se e segue as instruções na tela. Se você já tem uma conta pessoal no Twitter, pode usá-la para o robô, se quiser.

Eu preferi criar uma conta só para o robô: @RecuperaCovidBR.

Para criar uma conta de desenvolvedor do Twitter, acesse o Twitter Developer (Twitter para desenvolvedores) em developer.twitter.com e clique em Apply (candidatar). Não vou entrar em detalhes de como criar essa conta, mas resumidamente o Twitter vai te pedir informações sobre você e o que pretende fazer com o robô. Todas as telas são em inglês.

Com a conta de desenvolvedor já criada, vamos precisar cadastrar o robô (bot) como um aplicativo (app) e obter as chaves de acesso. Vejamos como fazer isso.

Na página inicial do Twitter Developer, clique em Developer Portal (portal do desenvolvedor):

À esquerda, expanda Projects & Apps (projetos e aplicativos), clique em Overview (visão geral). À direita, em Standalone Apps (aplicativos “soltos”, que não pertencem a um projeto), clique em Create App (criar aplicativo):

Dê um nome para o seu aplicativo e clique em Complete (completar):

Na tela seguinte, copie as informações desses campos e salve-as em algum lugar seguro:

À esquerda, clique no aplicativo recém-criado. À direita, em App permissions (permissões do aplicativo), clique em Edit (editar):

Mude do padrão Read Only (somente leitura) para Read and Write (leitura e escrita), para que o robô possa tuitar usando a conta.

De volta à tela anterior, mude da aba Settings (configurações) para a aba Keys and tokens (chaves e tokens). Em Access token & secret (token de acesso e segredo), clique em Generate (gerar):

Também nessa tela, copie as informações desses campos para algum lugar seguro:

3) Twit: cliente do Twitter para Node.js

Agora a brincadeira vai começar a ficar realmente interessante. Vamos fazer nosso script tuitar “Olá, Twitter!” Para isso, vamos usar a biblioteca twit do Node.js. Vamos usar também a biblioteca dotenv para armazenar aquelas chaves do aplicativo separadas do código.

Como vamos começar a usar bibliotecas de terceiros, vamos inicializar um projeto do NPM para gerenciar as dependências. Na pasta do robô, execute o comando:

1
$ npm init -y

Então, instale as bibliotecas necessárias:

1
$ npm install dotenv twit

Crie um arquivo com o nome .env com o seguinte conteúdo:

1
2
3
4
CONSUMER_KEY=........................................
CONSUMER_SECRET=.....................................
ACCESS_TOKEN_KEY=....................................
ACCESS_TOKEN_SECRET=.................................

E cole as chaves obtidas na etapa anterior, na mesma sequência, pulando o Bearer token.

Agora substitua o conteúdo do script robo.js pelo seguinte:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
const Twit = require('twit');

require('dotenv').config();

function tuitar(mensagem) {
    var twitter = new Twit({
        consumer_key:         process.env.CONSUMER_KEY,
        consumer_secret:      process.env.CONSUMER_SECRET,
        access_token:         process.env.ACCESS_TOKEN,
        access_token_secret:  process.env.ACCESS_TOKEN_SECRET,
        timeout_ms:           60*1000,
        strictSSL:            true
    });
    twitter.post('statuses/update',
    {
        status: mensagem
    },
    function(err, data, response) {
        console.log(data)
    });
}

async function main() {
    tuitar('Olá, Twitter!');
}

main();

Salve o script e execute-o:

1
$ node robo.js

Parabéns, seu robô acabou de dizer “olá” para o Twitter:

Se quiser mais informações sobre o que acabamos de fazer nessa etapa, consulte:

4) Agendando tarefas com o node-cron

No Linux, podemos agendar que o sistema execute programas ou scripts em determinada data e hora ou de tempos em tempos. Para isso, configuramos o serviço cron usando o comando crontab. Existe um equivalente no Node.js que é a biblioteca node-cron.

Lembremos que o script deve ser executado uma vez ao dia, de manhã. Eu poderia deixar o script como está e fazer esse agendamento a nível de sistema usando o cron. Mas vou preferir usar a biblioteca node-cron e modificar o script para ele mesmo se repetir.

Comece instalando a biblioteca node-cron:

1
$ npm install node-cron

Adicione ao início do script a importação dessa biblioteca:

1
const Cron = require('node-cron');

No final do script, comente a chamada à função main() e adicione o agendamento:

1
2
3
4
5
// main();

Cron.schedule('*/2 * * * * *', () => {
    console.log('Esse agendamento roda segundo sim, segundo não');
});

A expressão */2 * * * * * é um jargão próprio do cron e quer dizer que o agendamento deve ser executado em metade de todos os segundos, ou seja, segundo sim, segundo não. Existem ferramentas online que podem te ajudar a escrever essas expressões, como crontab.guru ou cronjob.xyz. Note que o cron do Linux permite agendar só até minutos, enquanto a biblioteca node-cron permite agendar até segundos, mas a sintaxe é semelhante.

Salve e execute o script e veja que ele escreve no terminal segundo sim, segundo não:

1
2
3
4
$ node robo.js
Esse agendamento roda segundo sim, segundo não
Esse agendamento roda segundo sim, segundo não
Esse agendamento roda segundo sim, segundo não

O script não vai parar sozinho. Para interrompê-lo, tecle Ctrl + C.

Você pode modificar o trecho do agendamento para:

1
2
3
Cron.schedule('30 6 * * *', () => {
    console.log('Bom dia!');
});

Nesse caso, se você iniciar o script e deixar o computador ligado, verá que todo dia às 6:30 da manhã ele te dará bom dia. Simpático ele, não?

Se quiser mais informações sobre o que acabamos de fazer nessa etapa, consulte:

5) Obtendo números do site do governo

Para obter o número de pessoas recuperadas do site do governo, vamos usar uma técnica conhecida como web scraping (coleta de dados web), que consiste em baixar automaticamente uma página da Internet e depois extrair informações específicas dela.

Para isso, vamos usar a biblioteca Puppeteer do Node.js, que inicia uma instância do navegador Chromium nos bastidores e permite controlá-la via programação. A maioria das coisas que você pode fazer manualmente no navegador podem ser feitas via programação com o Puppeteer, inclusive usar as ferramentas do desenvolvedor, como fizemos antes.

Comece instalando a biblioteca Puppeteer:

1
$ npm install puppeteer

Adicione ao início do script a importação dessa biblioteca:

1
const puppeteer = require('puppeteer');

Adicione ao script também a função obterNumeroDeRecuperados():

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
async function obterNumeroDeRecuperados() {
    const browser = await puppeteer.launch();
    const page = await browser.newPage();
    await page.setViewport({
        width: 1024,
        height: 768,
    });
    await page.goto('https://covid.saude.gov.br/', {
        timeout: 60*1000,
        waitUntil: 'networkidle2'
    });
    var recuperados = await page.evaluate(() => {
        var numeroNaPagina = document.getElementsByClassName('lb-total')[0].lastChild.data.trim();
        return numeroNaPagina
    });
    await browser.close();
    return recuperados;
}

No final do script, remova o agendamento, descomente a chamada à função main() e também mude a implementação dessa função:

1
2
3
4
5
6
async function main() {
    var recuperados = await obterNumeroDeRecuperados();
    console.log(recuperados);
}

main();

Salve e execute o script. Aguarde alguns segundos e você terá o número obtido do site:

1
2
$ node robo.js
5.931.777

Se quiser mais informações sobre o que acabamos de fazer nessa etapa, consulte:

Unindo tudo

Pois bem, já temos tudo de que precisamos, chegou a hora de unir todos os “ingredientes” e fazer o robô funcionar. Ao final, o script deve apresentar: as importações das bibliotecas e as funções obterNumeroDeRecuperados() e tuitar(). Remova a implementação da função main() e sua chamada e adicione o código a seguir:

1
2
3
4
5
6
7
8
9
10
11
12
13
async function main() {
    var recuperados = await obterNumeroDeRecuperados();
    var tuite = 'Bom dia!\n';
    tuite += '\n';
    tuite += recuperados + ' brasileiros se recuperaram da #Covid19 até o momento\n';
    tuite += '\n';
    tuite += 'Fonte: https://covid.saude.gov.br';
    tuitar(tuite);
}

Cron.schedule('30 6 * * *', () => {
    main();
});

Agora é só iniciar o script e deixá-lo rodando com o computador ligado:

1
$ node robo.js

No dia seguinte, passada 6:30 da manhã, o robô terá tuitado o número de recuperados:

Se não quiser esperar o dia seguinte para testar o robô, mude a expressão do agendamento. Por exemplo, se agora são 19:28, você pode agenda-lo para as 19:30 com: 30 19 * * *.

Você deve interromper o robô sempre antes de fazer qualquer alteração no seu código-fonte, ou quando não precisar mais dele. Para interromper o robô, tecle Ctrl + C.

Conclusão

Publiquei o código-fonte do robô como está agora e demais arquivos que usei no GitHub:

Se quiser saber diariamente quantas pessoas já se recuperaram da Covid-19, siga meu robô @RecuperaCovidBR no Twitter. Siga também o @LinuxKamarada se quiser saber de novos textos como esse. Se tiver dúvidas, escreva nos comentários. Até mais!

Me paga um café?
Se você gostou muito, se foi muito útil pra você, será que vale um café? Se quiser, você pode "me pagar um café" pelo PayPal ou contribuir com o projeto de outras formas.

Comentários

Sobre

O Projeto Linux Kamarada visa divulgar e promover o Linux como um sistema operacional robusto, seguro, versátil e fácil de usar, adequado para o uso diário seja em casa, no trabalho ou no servidor. Os focos do projeto são principalmente distribuição e documentação.

Anúncios

Facebook

Autor