Usando o Cheerio NPM para Scraping de dados

Aprenda a extrair dados de sites dinâmicos e estáticos usando o Cheerio NPM neste guia passo a passo
8 min de leitura
Cheerio NPM web scraping

O Node.js surgiu como uma opção poderosa para a criação de Scrapers de dados, oferecendo conveniência para desenvolvimentos tanto do lado do cliente quanto do lado do servidor. Seu extenso catálogo de bibliotecas torna o Scraping de dados da web com o Node.js uma tarefa fácil. Neste artigo, o cheerio será destaque e suas capacidades serão exploradas para um Scraping de dados da web eficiente.

O cheerio é uma biblioteca rápida e flexível para analisar e manipular documentos HTML e XML. Ele implementa um subconjunto de recursos do jQuery, o que significa que qualquer pessoa familiarizada com o jQuery se sentirá à vontade com a sintaxe do cheerio. Nos bastidores, o cheerio usa as bibliotecas parse5 e, opcionalmente, htmlparser2 para analisar documentos HTML e XML.

Neste artigo, você criará um projeto que usa o cheerio e aprenderá como extrair dados de sites dinâmicos e páginas estáticas.

Scraping de dados com o cheerio

Antes de começar este tutorial, certifique-se de que o Node.js esteja instalado no seu sistema. Se ainda não o tiver, você pode instalá-lo usando a documentação oficial.

Depois de instalar o Node.js, crie um diretório chamado cheerio-demo e acesse-o com o comando cd:

  mkdir cheerio-demo u0026u0026 cd cheerio-demon

Em seguida, inicialize um projeto npm no diretório:

  npm init -yn

Instale os pacotes cheerio e Axios:

  npm install cheerio axiosn

Crie um arquivo chamado index.js, que é onde você escreverá o código para este tutorial. Em seguida, abra esse arquivo em seu editor favorito para começar.

A primeira coisa que você precisa fazer é importar os módulos necessários:

  const axios = require(u0022axiosu0022);nconst cheerio = require(u0022cheeriou0022);n

Neste tutorial, você irá extrair a página Books to Scrape, uma área de testes pública para testar Scrapers de dados. Primeiro, você usará o Axios para fazer uma solicitação GET à página da web com o seguinte código:

  axios.get(u0022https://books.toscrape.com/u0022).then((response) =u003e {n    n});n

O objeto de resposta na chamada de retorno contém o código HTML da página da web na propriedade de dados. Esse HTML precisa ser passado para a função load do módulo cheerio. Essa função retorna uma instância do CheerioAPI, que será usada para acessar e manipular o DOM para o restante do código. Observe que a instância do CheerioAPI é armazenada em uma variável chamada $, que é uma referência à sintaxe do jQuery:

  axios.get(u0022https://books.toscrape.com/u0022).then((response) =u003e {n    const $ = cheerio.load(response.data);n});n

Localizando elementos

O cheerio suporta o uso de seletores CSS e XPath para selecionar elementos da página. Se você já usou jQuery, vai achar a sintaxe familiar — passe o seletor CSS para a função $(). Use essa sintaxe para encontrar e extrair informações na primeira página do site Books to Scrape.

Acesse https://books.toscrape.com/ e abra o Console do desenvolvedor. Pesquise na guia Inspecionar elemento, onde você aprenderá mais sobre a estrutura HTML da página. Nesse caso, você pode ver que todas as informações sobre os livros estão contidas nas tags de artigo com a classe product-pod:

Inspect element

Para selecionar os livros, você precisa usar o seletor CSS article.product_pod desta forma:

  $(u0022article.product_podu0022);n

Essa função retorna uma lista de todos os elementos que correspondem ao seletor. Você pode usar o método each para iterar sobre a lista:

  $(u0022article.product_podu0022).each( (i, element) =u003e {nn});n

Dentro do loop, você pode usar a variável element para extrair os dados.

Tente extrair o título dos livros na primeira página. Voltando ao console Inspecionar Elemento, você pode ver como os títulos são armazenados:

inspect title elements

Você verá que precisa encontrar um h3, que é um filho da variável element. Dentro do h3, há um elemento a que contém o título do livro. Você pode usar o método find com um seletor CSS para encontrar os filhos de um elemento, mas inicialmente, você precisa passar o elemento por $ para convertê-lo em uma instância do Cheerio:

  $(u0022article.product_podu0022).each( (i, element) =u003e {n    const titleH3 = $(element).find(u0022h3u0022);nn});n

Agora, você pode encontrar o a dentro do titleH3:

  $(u0022article.product_podu0022).each( (i, element) =u003e {n    const titleH3 = $(element).find(u0022h3u0022);n    const title = titleH3.find(u0022au0022);n});n

Observação: titleH3 já é uma instância do Cheerio, então você não precisa passá-lo por $.

Extraindo texto

Depois de selecionar um elemento, você pode obter o texto desse elemento usando o método text.

Modifique o exemplo anterior para extrair o título do livro chamando o método text no resultado do método find:

  $(u0022article.product_podu0022).each( (i, element) =u003e {n    const titleH3 = $(element).find(u0022h3u0022);n    const title = titleH3.find(u0022au0022).text();nn    console.log(title);n});n

O código completo deve ficar assim:

  const axios = require(u0022axiosu0022);nconst cheerio = require(u0022cheeriou0022);nnaxios.get(u0022https://books.toscrape.com/u0022).then((response) =u003e {n    const $ = cheerio.load(response.data);nn    $(u0022article.product_podu0022).each( (i, element) =u003e {n        const titleH3 = $(element).find(u0022h3u0022);n        const title = titleH3.find(u0022au0022).text();nn        console.log(title);n    });n});n

Execute o código com node index.js e você deverá ver o seguinte resultado:

  A Light in the ...nTipping the VelvetnSoumissionnSharp ObjectsnSapiens: A Brief History ...nThe Requiem RednThe Dirty Little Secrets ...nThe Coming Woman: A ...nThe Boys in the ...nThe Black MarianStarving Hearts (Triangular Trade ...nShakespeare's SonnetsnSet Me FreenScott Pilgrim's Precious Little ...nRip it Up and ...nOur Band Could Be ...nOlionMesaerion: The Best Science ...nLibertarianism for BeginnersnIt's Only the Himalayasn

Navegando no DOM: localizando filhos e irmãos

Depois de extrair os títulos, é hora de extrair o preço e a disponibilidade de cada livro. O Inspect Element revela que tanto o preço quanto a disponibilidade estão armazenados em um div com a classe product_price. Você pode selecionar esse div com o seletor CSS .product_price, mas como você já abordou os seletores CSS, a seguir discutiremos outra maneira de fazer isso:

Finding children and siblings code

Observação: o div é um irmão do titleH3 que você selecionou anteriormente. Ao chamar o método next do titleH3, você pode selecionar o próximo irmão:

  const priceDiv = titleH3.next();n

Você já viu que pode usar o método find para encontrar os filhos de um elemento com base em seletores CSS. Você também pode selecionar todos os filhos com o método children e, em seguida, usar o método eq para selecionar um filho específico. Isso é equivalente ao seletor CSS nth-child.

Nesse caso, o preço é o primeiro filho do priceDiv e a disponibilidade é o segundo filho do priceDiv. Isso significa que você pode selecioná-los com priceDiv.children().eq(0) e priceDiv.children().eq(1), respectivamente. Faça isso e imprima o preço e a disponibilidade:

  $(u0022article.product_podu0022).each( (i, element) =u003e {n    const titleH3 = $(element).find(u0022h3u0022);n    const title = titleH3.find(u0022au0022).text();nnn    const priceDiv = titleH3.next();n    const price = priceDiv.children().eq(0).text().trim();n    const availability = priceDiv.children().eq(1).text().trim();n    console.log(title, price, availability);n});n

Agora, ao executar o código, é exibida a seguinte saída:

  A Light in the ... £51.77 In stocknTipping the Velvet £53.74 In stocknSoumission £50.10 In stocknSharp Objects £47.82 In stocknSapiens: A Brief History ... £54.23 In stocknThe Requiem Red £22.65 In stocknThe Dirty Little Secrets ... £33.34 In stocknThe Coming Woman: A ... £17.93 In stocknThe Boys in the ... £22.60 In stocknThe Black Maria £52.15 In stocknStarving Hearts (Triangular Trade ... £13.99 In stocknShakespeare's Sonnets £20.66 In stocknSet Me Free £17.46 In stocknScott Pilgrim's Precious Little ... £52.29 In stocknRip it Up and ... £35.02 In stocknOur Band Could Be ... £57.25 In stocknOlio £23.88 In stocknMesaerion: The Best Science ... £37.59 In stocknLibertarianism for Beginners £51.33 In stocknIt's Only the Himalayas £45.17 In stockn

Acessando atributos

Até agora, você navegou pelo DOM e extraiu textos dos elementos. Também é possível extrair atributos de um elemento usando o cheerio, que é o que você fará nesta seção. Aqui, você extrairá a classificação dos livros lendo a lista de classes dos elementos.

A classificação dos livros tem uma estrutura interessante. As classificações estão contidas em uma tag p. Cada tag p tem exatamente cinco estrelas, mas as estrelas são coloridas usando CSS com base no nome da classe do elemento p. Por exemplo, em um p com a classe star-rating.Four, as quatro primeiras estrelas são coloridas de amarelo, denotando uma classificação de quatro estrelas:

Star ratings code

Para extrair a classificação de um livro, você precisa extrair os nomes de classe do elemento p. O primeiro passo é encontrar o parágrafo que contém a classificação:

  const ratingP = $(element).find(u0022p.star-ratingu0022);n

Passando o nome do atributo para o método attr, você pode ler os atributos de um elemento. Neste caso, você precisa ler a lista de classes, que é demonstrada no código a seguir:

  const starRating = ratingP.attr('class');n

A lista de classes tem a seguinte forma: classificação por estrelas X, onde X é um dos seguintes valores: Um, Dois, Três, Quatro e Cinco. Isso significa que você precisa dividir a lista de classes por espaço e pegar o segundo elemento. O código a seguir faz isso e converte a classificação textual em uma classificação numérica:

  const rating = { One: 1, Two: 2, Three: 3, Four: 4, Five: 5 }[starRating.split(u0022 u0022)[1]];n

Se você juntar tudo, seu código ficará assim:

  $(u0022article.product_podu0022).each( (i, element) =u003e {n    const titleH3 = $(element).find(u0022h3u0022);n    const title = titleH3.find(u0022au0022).text();nnn    const priceDiv = titleH3.next();n    const price = priceDiv.children().eq(0).text().trim();n    const availability = priceDiv.children().eq(1).text().trim();nn    const ratingP = $(element).find(u0022p.star-ratingu0022);n    const starRating = ratingP.attr('class');n    const rating = { One: 1, Two: 2, Three: 3, Four: 4, Five: 5 }[starRating.split(u0022 u0022)[1]];nn    console.log(title, price, availability, rating);n});n

A saída ficará assim:

  A Light in the ... £51.77 In stock 3nTipping the Velvet £53.74 In stock 1nSoumission £50.10 In stock 1nSharp Objects £47.82 In stock 4nSapiens: A Brief History ... £54.23 In stock 5nThe Requiem Red £22.65 In stock 1nThe Dirty Little Secrets ... £33.34 In stock 4nThe Coming Woman: A ... £17.93 In stock 3nThe Boys in the ... £22.60 In stock 4nThe Black Maria £52.15 In stock 1nStarving Hearts (Triangular Trade ... £13.99 In stock 2nShakespeare's Sonnets £20.66 In stock 4nSet Me Free £17.46 In stock 5nScott Pilgrim's Precious Little ... £52.29 In stock 5nRip it Up and ... £35.02 In stock 5nOur Band Could Be ... £57.25 In stock 3nOlio £23.88 In stock 1nMesaerion: The Best Science ... £37.59 In stock 1nLibertarianism for Beginners £51.33 In stock 2nIt's Only the Himalayas £45.17 In stock 2n

Salvando os dados

Depois de extrair os dados da página da web, geralmente você vai querer salvá-los. Existem várias maneiras de fazer isso, como salvar em um arquivo, salvar em um banco de dados ou alimentar um pipeline de processamento de dados. Nesta seção, você aprenderá a maneira mais simples de todas: salvar dados em um arquivo CSV.

Para fazer isso, instale o pacote node-csv:

  npm install csvn

Em index.js, importe os módulos fs e csv-stringify:

  const fs = require(u0022fsu0022);nconst { stringify } = require(u0022csv-stringifyu0022);n

Para gravar um arquivo local, você precisa criar um WriteStream:

  const filename = u0022scraped_data.csvu0022;nconst writableStream = fs.createWriteStream(filename);n

Declare os nomes das colunas, que são adicionados ao arquivo CSV como cabeçalhos:

  const columns = [n  u0022titleu0022,n  u0022ratingu0022,n  u0022priceu0022,n  u0022availabilityu0022n];n

Crie um stringifier com os nomes das colunas:

  const stringifier = stringify({ header: true, columns: columns });n

Dentro da função each, você usará o stringifier para gravar os dados:

  $(u0022article.product_podu0022).each( (i, element) =u003e {n    ...nn    const data = { title, rating, price, availability };n    stringifier.write(data);nn});n

Por fim, fora da função each, você precisa gravar o conteúdo do stringifier na variável writableStream:

  stringifier.pipe(writableStream);n

Neste ponto, seu código deve ficar assim:

  const axios = require(u0022axiosu0022);nconst cheerio = require(u0022cheeriou0022);nconst fs = require(u0022fsu0022);nconst { stringify } = require(u0022csv-stringifyu0022);nnconst filename = u0022scraped_data.csvu0022;nconst writableStream = fs.createWriteStream(filename);nnconst columns = [n  u0022titleu0022,n  u0022ratingu0022,n  u0022priceu0022,n  u0022availabilityu0022n];nconst stringifier = stringify({ header: true, columns: columns });nnaxios.get(u0022https://books.toscrape.com/u0022).then((response) =u003e {n    const $ = cheerio.load(response.data);nn    $(u0022article.product_podu0022).each( (i, element) =u003e {n        const titleH3 = $(element).find(u0022h3u0022);n        const title = titleH3.find(u0022au0022).text();n    n        const priceDiv = titleH3.next();n        const price = priceDiv.children().eq(0).text().trim();n        const availability = priceDiv.children().eq(1).text().trim();n        const ratingP = $(element).find(u0022p.star-ratingu0022);n        const starRating = ratingP.attr('class');n        const rating = { One: 1, Two: 2, Three: 3, Four: 4, Five: 5 }[starRating.split(u0022 u0022)[1]];nn        console.log(title, price, availability, rating);nn        const data = { title, rating, price, availability };n        stringifier.write(data);nn    });nn    stringifier.pipe(writableStream);nn});n

Execute o código, e ele deve criar um arquivo scraped_data.csv com os dados coletados dentro:

  title,rating,price,availabilitynA Light in the ...,3,£51.77,In stocknTipping the Velvet,1,£53.74,In stocknSoumission,1,£50.10,In stocknSharp Objects,4,£47.82,In stocknSapiens: A Brief History ...,5,£54.23,In stocknThe Requiem Red,1,£22.65,In stocknThe Dirty Little Secrets ...,4,£33.34,In stocknThe Coming Woman: A ...,3,£17.93,In stocknThe Boys in the ...,4,£22.60,In stocknThe Black Maria,1,£52.15,In stocknStarving Hearts (Triangular Trade ...,2,£13.99,In stocknShakespeare's Sonnets,4,£20.66,In stocknSet Me Free,5,£17.46,In stocknScott Pilgrim's Precious Little ...,5,£52.29,In stocknRip it Up and ...,5,£35.02,In stocknOur Band Could Be ...,3,£57.25,In stocknOlio,1,£23.88,In stocknMesaerion: The Best Science ...,1,£37.59,In stocknLibertarianism for Beginners,2,£51.33,In stocknIt's Only the Himalayas,2,£45.17,In stockn

Conclusão

Como você viu aqui, a biblioteca cheerio facilita o Scraping de dados da web com sua sintaxe semelhante à jQuery e operação extremamente rápida. Neste artigo, você aprendeu a fazer o seguinte:

  • Carregar e realizar o Parsing de uma página da web HTML com o cheerio
  • Encontrar elementos com seletores CSS
  • Extrair dados de elementos
  • Navegar pelo DOM
  • Salvar dados coletados no armazenamento de arquivos local

Você pode encontrar o código completo no GitHub.

No entanto, o cheerio é apenas um analisador HTML, portanto, não pode executar código JavaScript. Isso significa que você não pode usá-lo para coletar páginas da web dinâmicas e aplicativos de página única. Para coletar esses dados, você precisa ir além do cheerio e procurar ferramentas complexas como Selenium ou Playwright. E é aí que entra a Bright Data. As vastas soluções de Scraping de dados da Bright Data incluem um Selenium Scraping Browser e um Playwright Scraping Browser. Para saber mais sobre os produtos, você pode visitar nossa documentação do Navegador de scraping.