Desenvolvendo WebCrawlers performáticos com Puppeteer 🤖🚀
Published: 2021-10-03 05:20:14

## Introdução
    
Você provavelmente já desenvolveu alguma solução de webscraping que percorria várias páginas de algum site, e percebeu um gargalo de desempenho enorme até aquela magnifica mensagem de confirmação no console printar na sua tela. Se sim, tenho certeza que este post vai lhe ajudar.

![Alt text of image](https://png.pngtree.com/png-vector/20190821/ourmid/pngtree-image-icon---vector-loading-download-and-upload-png-image_1695294.jpg)

Pretendo demonstrar neste texto algumas técnicas que aprendi enquanto desenvolvia softwares de automação em meus projetos particulares e alguns freelas por aí, heheh. 

obs. (Este post considera que você esteja minimamente familiarizado com o conceito básico de webcraping e requisições http)

## O que pode dar errado ?

Para começar quero demonstrar uma situação onde você está fazendo 
webscraping em um site qualquer, porém acaba percebendo que o site não é tão simples assim, porque o tempo de carregamento do seu programa para buscar dados de uma única página dele simplesmente não termina, bom, pra esse caso existem 2 possíveis causas: 

1. A primeira é que se o programa apesar da demora, retorna os dados, então o problema deve estar relacionado com a sua conexão com a internet, ou o próprio site pode estar passando por problemas, então não há muito o que fazer. Tente realizar o scraping em outro momento.

2. A segunda e mais plausível na maioria dos casos acontece quando seu robozinho🤖 busca muito mais do que apenas os dados necessários para o webscraping.
 
 Para entender como isso termina dessa forma, precisamos assumir que nossa requisição para o site, não é a única sendo feita, pois para que sua página seja mostrada bonita e gloriosa no seu browser ela necessita de alguns resources externos como arquivos css, fontes, imagens para ser formada, ou seja, a página precisa criar uma nova requisição pra cada um desses recursos.

## Show me the code
 
 Chega de teoria, a melhor maneira de demonstrar como diminuir o overload de requisições no seu crawler com Puppeteer é com código:

- Considerando que você tem o Puppeteer instalado no seu projeto em nodejs, primeiro inicie o browser do puppeter e crie uma nova página para sua aplicação

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6yu1sgfqr46p2uiq57ay.png)

*Dica: Na verdade eu não criei uma nova página, apenas usei pequeno hack pra pegar a primeira página que é aberta com o Browser, assim economizo memória e o debug da aplicação fica mais fácil.*


- Agora para bloquear as requisições de recursos dentro da página faremos o seguinte

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1q4m75d4h51882xft9lc.png)

- Com este trecho de código interceptamos cada requisição da página e bloqueamos sempre que esta for do tipo Fonte, Css Stylesheet ou imagem(considere qualquer um destes bloqueios caso necessite, cada um é interdependente). Com isto na maioria dos casos o tempo de carregamento da página vai ser drasticamente reduzido.

## Como buscar dados de 10k de produtos com Puppeteer

 Agora imagine que você esteja realizando webscraping em uma loja virtual em busca de preço dos produtos, só que para capturar os dados precisa acessar a página de cada produto um por um, então você vai lá e desenvolve um bot com puppeteer que visita cada página de produto e captura os dados

 Caso a loja tenha 100 produtos em estoque tudo bem certo ?, porém e se aumentarmos o escopo do problema, e agora você tiver que buscar dados de 10.000 páginas diferentes ?, isto parece cansativo até mesmo para um bot, certo ?. Então vou lhe dar uma dica para casos assim

 A primeira vista nossa solução pra resolver o problema poderia ser criar várias instâncias do browser e encontrar algum algoritmo para dividir o trabalho entre eles. Várias instâncias do chrome manipulados por software, já sente sua memória ram se esgotando ?. Pois é, isso não funciona tão bem quanto parece a primeira vista.


 ![chrome killer image](https://i.kinja-img.com/gawker-media/image/upload/c_fill,f_auto,fl_progressive,g_center,h_675,pg_1,q_80,w_1200/1262497171475751057.gif)


 Mas para nossa salvação, com Puppeteer temos a capacidade de manipular múltiplas páginas ao mesmo tempo, soa bem melhor certo ?
 Para exemplificar como utilizaremos isso podemos dizer que ao invés de carregar uma página de produto por vez, vamos criar várias páginas e carregar ambas ao mesmo tempo, quando carregadas, capturamos nossos dados e saímos de cada página.

 Vamos ao código >>

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zpkdlbicqlkmymd43ebp.png)

[Aqui uma versão em gist do code >-<](https://gist.github.com/wandersonsousa/ecc4cb63f45a8f4c65b3425edfe6ae1a)

- Para iniciar consideramos que já temos uma lista de urls dos produtos, para que possamos dividir as tarefas temos que limitar quantas páginas serão carregadas ao mesmo tempo por vez, neste exemplos faremos com 5 páginas simultâneas, logo iremos dividir nossa lista/array com as urls dos produtos em pequenos arrays de 5 valores, para isso usaremos o método chunk da biblioteca lodash:

- Com nossa lista de urls divididas, realizamos um for para acessar um conjunto de urls por vez, e a cada interação transformamos este conjunto em uma lista de Promises, que irão retornar os dados do crowler executado utilizando uma nova página, e irão fechar a página ao final, independente de existir ou não 
algum erro, para se livrar de páginas inutilizadas.

- Agora a parte principal do algoritmo já foi executado, agora resta executar as promises, buscar seu resultado e incluir onde desejar, neste caso foi usado uma variável que aponta array com o nome DATA e boom, seu algoritmo agora tem capacidade de realizar scraping de centenas ou milhares de páginas em alguns minutos.

Com esta dica finalizo o post, este é meu primeiro texto publicado, e me diverti tanto que pretendo continuar com essa prática. Espero de coração que você tenha gostado, e que minhas dicas lhe ajudem de alguma forma, até mais amigos! 🧐😎