<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: W.Sousa</title>
    <description>The latest articles on DEV Community by W.Sousa (@wandersonsousa).</description>
    <link>https://dev.to/wandersonsousa</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F717296%2F94e1f949-ac79-45e2-bbcc-c759d95d9bb0.jpg</url>
      <title>DEV Community: W.Sousa</title>
      <link>https://dev.to/wandersonsousa</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/wandersonsousa"/>
    <language>en</language>
    <item>
      <title>Caching Best Practices</title>
      <dc:creator>W.Sousa</dc:creator>
      <pubDate>Thu, 09 Feb 2023 21:13:14 +0000</pubDate>
      <link>https://dev.to/wandersonsousa/caching-best-practices-1501</link>
      <guid>https://dev.to/wandersonsousa/caching-best-practices-1501</guid>
      <description>&lt;p&gt;&lt;strong&gt;Lazy caching&lt;/strong&gt;&lt;br&gt;
When an user request a data, the application will check if the data exists in cache(cache hit), if so, user receives cache data, but when the data do not exist in cache(cache miss), so the data its created for next requests.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Write-through&lt;/strong&gt;&lt;br&gt;
Following this, cache its set always a data is updated, ex:&lt;br&gt;
if I update the user profile from my app, the cache will updated as well.&lt;br&gt;
&lt;strong&gt;Time-to-live&lt;/strong&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Why choose Nodejs for your nextjs webscraping project ✔</title>
      <dc:creator>W.Sousa</dc:creator>
      <pubDate>Sun, 21 Aug 2022 22:57:06 +0000</pubDate>
      <link>https://dev.to/wandersonsousa/why-choose-nodejs-for-your-nextjs-webscraping-project-3mig</link>
      <guid>https://dev.to/wandersonsousa/why-choose-nodejs-for-your-nextjs-webscraping-project-3mig</guid>
      <description>&lt;p&gt;&lt;strong&gt;Something I never understood, was why people forget about NodeJS to web scraping to use Python instead.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It seems it's forgotten JavaScript it's the language for the web, and always have great libraries been released for good or bad.&lt;/p&gt;

&lt;p&gt;On my experience with Web scraping and Web automation, each project has it own issue, and it seems NodeJS has always the tool for what it needs.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;If you have to scrape a simple page, just use libraries to make requests, or maybe even the native Fetch module can fit.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;When scraping a page "JS Rendered"(React, Svelte, Vue) use Puppeteer/Selenium or Playwright the new Browser Automation lib written by Google&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Sometimes when scraping, even using a Browser Automation Lib, websites may block you, using bot detection. Well, that was the main point that you should consider yourself replacing Python by NodeJS for some cases, simple because NodeJS has a great tooling to avoid bot detections when scraping, such as:&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;1.Puppeteer-extra that comes with great plugins for Puppeteer, and more recently they are updating to use playwright as well. You can use puppeteer-stealth to avoid detection.&lt;/p&gt;

&lt;p&gt;2.To avoid bot detection with simple requests scraping, just try to replace the user -agents and other tiny things, libs like Axios, got can make this work totally fine with just some adjustments.&lt;/p&gt;

&lt;p&gt;3.And of course, now we have Crawlee, "A full-featured library that helps you build reliable crawlers with NodeJS", think in Scrapy but for NodeJS, this for sure will facilitate the work for all of us, because this lib can handle with Bot detections, Storage, Proxy Management, and other problems related with web scraping out of the box, which can be great for the majority of use cases. &lt;/p&gt;

&lt;p&gt;This post do not intend to claim the NodeJS use for web scraping over python, but let the people know about how NodeJS can be not only suitable, but a great decision for your next scraping project 😁&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Desenvolvendo WebCrawlers performáticos com Puppeteer 🤖🚀</title>
      <dc:creator>W.Sousa</dc:creator>
      <pubDate>Sun, 03 Oct 2021 05:20:14 +0000</pubDate>
      <link>https://dev.to/wandersonsousa/desenvolvendo-webcrawlers-performaticos-com-puppeteer-57hh</link>
      <guid>https://dev.to/wandersonsousa/desenvolvendo-webcrawlers-performaticos-com-puppeteer-57hh</guid>
      <description>&lt;h2&gt;
  
  
  Introdução
&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0dzIPdJ5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://png.pngtree.com/png-vector/20190821/ourmid/pngtree-image-icon---vector-loading-download-and-upload-png-image_1695294.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0dzIPdJ5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://png.pngtree.com/png-vector/20190821/ourmid/pngtree-image-icon---vector-loading-download-and-upload-png-image_1695294.jpg" alt="Alt text of image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;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. &lt;/p&gt;

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

&lt;h2&gt;
  
  
  O que pode dar errado ?
&lt;/h2&gt;

&lt;p&gt;Para começar quero demonstrar uma situação onde você está fazendo &lt;br&gt;
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: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;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.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;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.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h2&gt;
  
  
  Show me the code
&lt;/h2&gt;

&lt;p&gt;Chega de teoria, a melhor maneira de demonstrar como diminuir o overload de requisições no seu crawler com Puppeteer é com código:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;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&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--WJAY_jy3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6yu1sgfqr46p2uiq57ay.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WJAY_jy3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6yu1sgfqr46p2uiq57ay.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;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.&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Agora para bloquear as requisições de recursos dentro da página faremos o seguinte&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--r1_EK9q4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1q4m75d4h51882xft9lc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--r1_EK9q4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1q4m75d4h51882xft9lc.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;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.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Como buscar dados de 10k de produtos com Puppeteer
&lt;/h2&gt;

&lt;p&gt;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&lt;/p&gt;

&lt;p&gt;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&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Zfx1CW8l--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://i.kinja-img.com/gawker-media/image/upload/c_fill%2Cf_auto%2Cfl_progressive%2Cg_center%2Ch_675%2Cpg_1%2Cq_80%2Cw_1200/1262497171475751057.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Zfx1CW8l--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://i.kinja-img.com/gawker-media/image/upload/c_fill%2Cf_auto%2Cfl_progressive%2Cg_center%2Ch_675%2Cpg_1%2Cq_80%2Cw_1200/1262497171475751057.gif" alt="chrome killer image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Mas para nossa salvação, com Puppeteer temos a capacidade de manipular múltiplas páginas ao mesmo tempo, soa bem melhor certo ?&lt;br&gt;
 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.&lt;/p&gt;

&lt;p&gt;Vamos ao código &amp;gt;&amp;gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--RJWgEF1a--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zpkdlbicqlkmymd43ebp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RJWgEF1a--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zpkdlbicqlkmymd43ebp.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://gist.github.com/wandersonsousa/ecc4cb63f45a8f4c65b3425edfe6ae1a"&gt;Aqui uma versão em gist do code &amp;gt;-&amp;lt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;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:&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;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 &lt;br&gt;
algum erro, para se livrar de páginas inutilizadas.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;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.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;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! 🧐😎&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
