Voltar ao blogue
Guias
Mihnea-Octavian ManolacheLast updated on Mar 31, 20267 min read

Como criar um scraper e enviar um formulário com o Puppeteer

Como criar um scraper e enviar um formulário com o Puppeteer

Já alguma vez teve de trabalhar com pedidos POST ao fazer web scraping? Tenho a certeza de que sim! E, na maioria das vezes, são os formulários que temos de tratar. É por isso que hoje vou falar sobre como enviar um formulário com o Puppeteer. Se ainda não sabe o que é o Puppeteer, não se preocupe. Vais descobrir daqui a pouco. Até lá, deixa-me definir algumas expectativas para o artigo de hoje. Se me acompanhares no nosso percurso de aprendizagem, hoje deverás conseguir aprender:

  • O que é o Puppeteer na extração de dados da web
  • Como configurar um projeto simples com o Puppeteer
  • Como é que o envio de formulários é tratado no Puppeteer

Então, sem mais delongas, vamos a isso!

O que é o Puppeteer e por que é importante para o web scraping?

Em geral, o web scraping refere-se ao processo de automatização da extração de dados de vários servidores. Antigamente, um simples cliente HTTP teria sido suficiente para realizar esta tarefa. Hoje em dia, porém, os sites dependem cada vez mais do JavaScript. E os clientes HTTP tradicionais são incapazes de renderizar ficheiros JavaScript. É aí que o Puppeteer entra em cena.

O Puppeteer é uma biblioteca Node.js que permite controlar um navegador Chrome ou Chromium sem interface gráfica através do Protocolo DevTools. Resumindo, fornece uma API de alto nível para automatizar o Chrome.

Em termos de web scraping, o Puppeteer é útil para extrair dados de sites que requerem a renderização de JavaScript. Além disso, também pode ser utilizado para interagir com páginas web de uma forma semelhante à de um ser humano. Por exemplo, clicar em botões ou, o nosso foco de hoje, preencher formulários. Isto torna-o ideal para extrair dados de sites que utilizam técnicas anti-scraping.

Configurar um projeto Puppeteer simples

Acredito que devemos ir devagar para compreender melhor o processo global. Antes de entrarmos na forma de enviar o formulário com o Puppeteer, vamos falar sobre o Puppeteer de forma simples. Nesta secção, vou mostrar-lhe como configurar um projeto Node, instalar o Puppeteer e usá-lo para extrair dados. Então, antes de mais nada, vamos criar uma nova pasta e abri-la no nosso IDE preferido. Eu prefiro o Visual Studio Code, mas fique à vontade para usar o que quiser.

Sabias que...

  • Podes criar «programaticamente» uma nova pasta a partir do teu terminal, digitando o comando `mkdir`.
  • Pode usar o comando `npm init -y` para configurar um projeto Node e aceitar os valores predefinidos
  • Podes criar um novo ficheiro com o comando `touch`.
  • E também pode abrir o VSCode com o comando `code .`.

Se quiser, pode combinar os quatro e iniciar um projeto em segundos, assim:

~ » mkdir scraper && cd scraper && npm init -y && code .

Dentro do seu IDE, abra um novo terminal (Terminal > Novo Terminal) e vamos instalar o Puppeteer. Digite `npm i puppeteer --save` no seu terminal. Além disso, eu prefiro usar módulos JS em vez de CommonJS. Confira as diferenças entre os dois aqui. Se também quiser usar módulos, abra o `package.json` e adicione `"type": "module"` ao objeto JSON.

Agora que estamos todos prontos, podemos começar a adicionar algum código. Crie um novo ficheiro `index.js` e abra-o no IDE. Não é preciso fazê-lo a partir do terminal desta vez, mas apenas como dica, pode usar o comando `touch`. Agora vamos adicionar o código:

import puppeteer, { executablePath } from 'puppeteer'

const scraper = async (url) => {

   const browser = await puppeteer.launch({

       headless: false,

       executablePath: executablePath(),

   })

   const page = await browser.newPage()

   await page.goto(url)

   const html = await page.content()

   await browser.close()

   return html

}

E vamos ver o que estamos a fazer:

  • Estamos a importar o Puppeteer e o `executablePath` para o nosso projeto
  • Estamos a definir uma nova função, que recebe um parâmetro `url`
  • Estamos a iniciar um novo navegador usando `puppeteer.launch` a. Estamos a especificar que queremos que ele seja executado em modo head-full b. Estamos a usar `executablePath` para obter o caminho do Chrome
  • Estamos a abrir uma nova página e a navegar para o `url`
  • Estamos a guardar o `page.content()` numa constante
  • Fechamos a instância do navegador
  • E, finalmente, estamos a devolver a saída `html` da página que acabámos de extrair

Até agora, as coisas não são complicadas. Este é o mínimo necessário para uma implementação de um scraper web com Node JS e Puppeteer. Se quiser executar o código, basta atribuir um alvo à função `scraper` e registar o seu valor de retorno:

console.log(await scraper('https://webscrapingapi.com/'))

Mas lembre-se de que o nosso objetivo é extrair dados ao enviar um formulário. Isto significa que temos de pensar numa forma de enviar o formulário com o Puppeteer. Felizmente, já o fiz antes e sei que não é difícil. Vamos então ver como também o pode fazer.

Como enviar formulários com o Puppeteer

Pense no Puppeteer como o meio de imitar o comportamento humano num determinado site. Como é que nós, seres humanos, submetemos formulários? Bem, identificamos o formulário, preenchemo-lo e, normalmente, clicamos num botão. Essa é a mesma lógica utilizada para submeter formulários com o Puppeteer. A única diferença é a forma como realizamos estas ações. Porque os seres humanos dependem dos sentidos. Uma vez que o Puppeteer é software, vamos fazê-lo programaticamente, utilizando os métodos integrados do Puppeteer, da seguinte forma:

#1: Enviar formulários simples com o Puppeteer

Primeiro, precisamos de «visualizar» o nosso formulário. Num site, todos os elementos estão agrupados num bloco HTML e cada elemento tem um identificador. Os identificadores consistem normalmente em atributos CSS do elemento. No entanto, poderá deparar-se com sites que não têm esses seletores. Nesses cenários, pode usar xPaths, por exemplo. Mas isso é assunto para outra palestra. Vamos concentrar-nos em identificar elementos no Puppeteer usando CSS.

Para contextualizar, digamos que queremos automatizar a ação de login no Stack Overflow. Portanto, o alvo é https://stackoverflow.com/users/login. Abra o seu navegador, aceda à página de login e abra as Ferramentas do Desenvolvedor. Pode clicar com o botão direito do rato na página e selecionar «Inspecionar». Deverá ver algo semelhante a isto:

No lado esquerdo, há uma interface gráfica. No lado direito, está a estrutura HTML. Se olhar atentamente para o lado direito, verá o nosso formulário. Consiste principalmente em dois campos de entrada e um botão. Estes são os três elementos que estamos a visar. E, como pode ver, todos os três elementos têm um `id` como identificador CSS. Vamos traduzir o que aprendemos até agora em código:

import puppeteer, { executablePath } from 'puppeteer'

const scraper = async (target) => {

   const browser = await puppeteer.launch({

       headless: false,

       executablePath: executablePath(),

   })

   const page = await browser.newPage()

   await page.goto(target.url,{waitUntil: 'networkidle0'})

   await page.type(target.username.selector, target.username.value)

   await page.type(target.password.selector, target.password.value)

   await page.click(target.buttonSelector)

   const html = await page.content()

   await browser.close()

   return html

}

Para mantê-lo funcional e reutilizável, optei por substituir o parâmetro da minha função por um objeto. Este objeto consiste na URL de destino, nos seletores e valores dos campos de entrada e no seletor do botão de envio. Assim, para executar o código, basta criar um novo objeto `TARGET` que contenha os seus dados e passá-lo para a sua função `scraper`:

const TARGET = {

   url: 'https://stackoverflow.com/users/login',

   username: {

       selector: 'input[id=email]',

       value: '<YOUR_USERNAME>'

   },

   password: {

       selector: 'input[id=password]',

       value: '<YOUR_PASSWORD>'

   },

   buttonSelector: 'button[id=submit-button]'

}

console.log(await scraper(TARGET))

#2: Carregar ficheiros com o Puppeteer

Às vezes, a automação web exige que enviemos ficheiros, em vez de submetermos formulários simples. Se se deparar com uma tarefa desse tipo e precisar de anexar ficheiros antes de submeter o formulário com o Puppeteer, vai querer utilizar o método `uploadFile` do Puppeteer. Para simplificar as coisas, sugiro que crie uma nova função para esta ação:

const upload = async (target) => {

   const browser = await puppeteer.launch({

       headless: false,

       executablePath: executablePath(),

   })

   const page = await browser.newPage()

   await page.goto(target.url,{waitUntil: 'networkidle0'})

   const upload = await page.$(target.form.file)

   await upload.uploadFile(target.file);

   await page.click(target.form.submit)

  

   await browser.close()

}

Repara como, desta vez, estou a usar `page.$` para identificar primeiro o elemento. E só depois disso é que chamo o método `uploadFile`, que só funciona com tipos `ElementHandle`. No que diz respeito aos parâmetros, tal como anteriormente, estou a usar um objeto para passar todos os dados de uma só vez para a minha função. Se quiseres testar o script, basta adicionares o código seguinte e executares `node index.js` no teu terminal:

const TARGET = {

   url: 'https://ps.uci.edu/~franklin/doc/file_upload.html',

   form: {

       file: 'input[type=file]',

       submit: 'input[type=submit]'

   } ,

   file: './package.json'

}

upload(TARGET)

Conclusões

Resumindo tudo, diria que é bastante fácil enviar o formulário com o Puppeteer. Além disso, considero que, em comparação com as suas alternativas, o Puppeteer lida plenamente com esta ação. Basicamente, tudo o que o utilizador tem de fazer é identificar corretamente os elementos.

Agora, devo referir que um scraper no mundo real requer muito mais para ser eficiente. Na maioria das vezes, se «abusar» de um servidor enviando demasiados formulários num curto espaço de tempo, provavelmente será bloqueado. É por isso que, se quiser automatizar o processo de envio de formulários, recomendo a utilização de um serviço profissional de scraping. Na Web Scraping API, oferecemos a opção de enviar pedidos POST e PUT. Pode ler mais sobre isso na nossa documentação.

Sobre o autor
Mihnea-Octavian Manolache, Desenvolvedor Full Stack @ WebScrapingAPI
Mihnea-Octavian ManolacheDesenvolvedor Full Stack

Mihnea-Octavian Manolache é engenheiro Full Stack e DevOps na WebScrapingAPI, onde desenvolve funcionalidades do produto e mantém a infraestrutura que garante o bom funcionamento da plataforma.

Comece a construir

Pronto para expandir a sua recolha de dados?

Junte-se a mais de 2.000 empresas que utilizam a WebScrapingAPI para extrair dados da Web à escala empresarial, sem quaisquer custos de infraestrutura.