eptaccio

Automatizando o chrome com Node.js para zoar amigos

April 27, 2020

Logo do puppeteer

Estava revisitando meus repositórios antigos no github e achei um projeto de mais de um ano atrás, onde, eu configurava uma postagem alvo no facebook, meu usuário e senha e com isso fazia um monte de comentários no mesmo.

A gente não usa tanto facebook porem leia até o final, as vezes consegue ter uma ideia legal a partir dessa.

O que vamos fazer hoje:

Controlando o Chrome com puppeteer

Puppeteer é uma lib open source criada pelo google que disponibiliza uma série de métodos para controle do chrome de forma automatizada, clicks, execução de scripts no console do browser, prints-screens, downloads entre outros. Quase tudo que um usuário faz, porem de forma programática com Node.js.

Criando o script

I - Instalando a dependência, puppeteer x puppeteer-core

O jeito mais fácil e simples é instalando o puppeteer, conforme o código abaixo.

npm add puppeteer

Existe outra opção de instalação: puppeteer-core. Qual a diferença?
Se você instalar o puppeteer da forma simples, junto com os códigos será baixado uma versão do chrome para sua node_modules também.

No puppeteer-core você consegue informar um browser que já existe na sua máquina.

Eu geralmente faço a instalação normal pela comodidade.

piada com o tamanho da node_modules

II - Instanciando o browser

const puppeteer = require('puppeteer') const browser = await puppeteer.launch({ headless: false, args: ['--disable-notifications'] })

Opções passadas no launch:

  • headless:
    Define se o puppeteer vai abrir a interface gráfica do browser quando for executar o script, por padrão essa opção é true, ou seja, a interface não é aberta. Eu gosto de deixar false para ver a magia acontecendo.
  • args:
    Com essa opção você consegue enviar argumentos mais específicos para o chrome. Nesse caso estou passado apenas --disable-notifications, para bloquear as notificações do browser, que estavam travando o proceso.

Notificação do chrome

II - Navegando até o POST

const page = await browser.newPage()

Cria uma “nova aba” no browser e retorna um objeto do tipo Page.

await page.goto(config.FACEBOOK.POST_URL)

Navega até a página informada. Nesse caso estou importando essa variavel de config de outro arquivo, mas é bem simples.

// config.js const config = { COMMENTS_LIMIT: process.env.COMMENTS_LIMIT, FACEBOOK: { USER_NAME: process.env.USER_NAME, PASSWORD: process.env.PASSWORD, POST_URL: process.env.POST_URL, COMMENT_TEXT: process.env.COMMENT_TEXT } }

⚠️⚠️⚠️ USE VARIAVEIS DE AMBIENTE PARA EVITAR COMITAR SUA SENHA SEM QUERER ⚠️⚠️⚠️

await page.type('#email', config.FACEBOOK.USER_NAME) await page.type('#pass', config.FACEBOOK.PASSWORD) await page.click('#loginbutton')

Digita login, senha e clica no botão de login. A função page.type recebe um selector e o texto que você quer digitar naquele input. A função de page.click segue a mesma lógica.

III - Escrevendo os comentários

await page.click('[contenteditable]')

Clica naquela caixa de comentários:

Input de comentários do facebook

E a parte final:

for (let index = 0; index < config.COMMENTS_LIMIT; index++) { await page.keyboard.type( config.FACEBOOK.COMMENT_TEXT, { delay: 30 } ) await page.keyboard.press('Enter') await page.waitFor(1000) }

Faz um loop besta usando a função page.keyboard.type para simular um teclado.

Porque não usei o page.type nesse caso?

Eu não entendo como funcionam esses reactos do facebook, mas toda hora o campo fica com um id diferente, então foi mais fácil simular o click na caixa de comentários e depois usar o page.keyboard.

Usei a opção de delay { delay: 30 } para que fica-se mais parecido com um usuário real digitando, não tenho muita pressa nesse caso já que, se fizer os comentários sem uma pausa, o facebook te bloqueia por um tempo.

Resultado final

post alvo de comentários

Código no github

Se tiver algum feedback ou conseguir construir algo legal à partir disso, por favor me chame no twitter twitter ou telegram.

Obrigado por ler até o final. Um salve pro Marcel que me apresentou essa ferramenta muito tempo atrás.


marcos

dev, parte do @afrotechbr, @quebradev e akatsuki. chaotic good (ele/he/el)