Como extrair uma tabela HTML em JavaScript

Mihai Maxim em Jan 31 2023

imagem do blogue

Saber como extrair tabelas HTML com javascript pode ser uma competência crucial quando se lida com dados tabulares apresentados na Web. Os sítios Web apresentam frequentemente informações importantes, como detalhes de produtos, preços, níveis de inventário e dados financeiros em tabelas. A capacidade de extrair estas informações é extremamente útil na recolha de dados para todos os tipos de tarefas de análise. Neste artigo, vamos aprofundar as tabelas HTML e criar um programa simples, mas poderoso, para extrair dados delas e exportá-los para um arquivo CSV ou JSON. Usaremos o Node.js e o cheerio para facilitar o processo.

Compreender a estrutura de uma tabela HTML

HTML tables are a powerful tool for marking up structured tabular data and displaying it in a way that is easy for users to read and understand. Tables are made up of data organized into rows and columns, and HTML provides several different elements for defining and structuring this data. A table must include at least the following elements: <table>, <tr> (table row), and <td> (table data). For added structure and semantic value, tables may also include the <th> (table header) element, as well as the <thead>, <tbody>, and <tfoot> elements.

Vamos explorar as etiquetas com a ajuda de um pequeno exemplo.

imagem do blogue

Repare como a segunda tabela utiliza uma sintaxe mais específica

imagem do blogue

The <thead> tag will apply a bold font to the "Fruit" and "Color" cells in the second table. Other than that, you can see how both syntaxes achieve the same organization of the data.

Ao extrair tabelas da Web, é importante ter em conta que pode encontrar tabelas escritas com diferentes graus de especificidade semântica. Por outras palavras, algumas tabelas podem incluir etiquetas HTML mais detalhadas e descritivas, enquanto outras podem utilizar uma sintaxe mais simples e menos descritiva.

Raspagem de tabelas HTML com Node.js e cheerio

Bem-vindo à parte divertida! Aprendemos sobre a estrutura e o objetivo das tabelas HTML e agora está na altura de pôr esse conhecimento em ação, fazendo algo prático. Nosso alvo para este tutorial é a tabela dos artistas mais vendidos de todos os tempos, encontrada em https://chartmasters.org/best-selling-artists-of-all-time/. Começaremos por configurar o nosso ambiente de trabalho e instalar as bibliotecas necessárias. Em seguida, exploraremos o site de destino e criaremos alguns seletores para extrair os dados encontrados na tabela. Depois disso, escreveremos o código para extrair os dados e, por fim, exportá-los-emos para diferentes formatos, como CSV e JSON.

Criação do ambiente de trabalho

Muito bem, vamos começar com o nosso novo projeto! Antes de começar, certifique-se de que tem o node.js instalado. Você pode baixá-lo em https://nodejs.org/en/.

Agora abra o seu editor de código favorito, abra o diretório do seu projeto e execute (no terminal):

npm init -y

Isso inicializará um novo projeto e criará um arquivo package.json padrão.

{

"name": "html_table_scraper", // the name of your project folder

"version": "1.0.0",

"description": "",

"main": "index.js",

"scripts": {

"test": "echo \"Error: no test specified\" && exit 1"

},

"keywords": [],

"author": "",

"license": "ISC"

}

Para manter as coisas simples, vamos importar nossos módulos com "require". Mas se você quiser importar módulos usando a instrução "import", adicione isso ao seu arquivo package.json:

 "type": "module",

// isto permitir-lhe-á utilizar a declaração de importação

// ex: import * as cheerio from 'cheerio';

A opção "main": "index.js" especifica o nome do ficheiro que é o ponto de entrada do nosso programa. Dito isto, pode agora criar um ficheiro index.js vazio.

Vamos usar a biblioteca cheerio para analisar o HTML do nosso site de destino. Você pode instalá-la com:

npm install cheerio

Agora abra o ficheiro index.js e inclua-o como um módulo:

const cheerio = require('cheerio');

O ambiente de trabalho básico está definido. No próximo capítulo, iremos explorar a estrutura da tabela dos artistas mais vendidos de sempre.

Testar o site de destino usando DevTools

imagem do blogue

Ao inspecionar o separador "Elementos" das Ferramentas de desenvolvimento, podemos extrair informações valiosas sobre a estrutura da tabela:

The table is stored in a <thead>, <tbody> format.

A todos os elementos do quadro são atribuídos id's, classes e funções descritivas.

No contexto de um browser, o utilizador tem acesso direto ao HTML de uma página Web. Isto significa que pode utilizar funções JavaScript como getElementsByTagName ou querySelector para extrair dados do HTML.

Com isto em mente, podemos utilizar a Consola de Ferramentas do Programador para testar alguns selectores.

Vamos extrair os nomes dos cabeçalhos utilizando o atributo role="columnheader"

imagem do blogue

Agora vamos extrair os dados da primeira linha utilizando os atributos role="cell" e role="row":

imagem do blogue

Como se pode ver:

Podemos utilizar "[role=columheader]" para selecionar todos os elementos de cabeçalho.

Podemos utilizar "tbody [role=row]" para selecionar todos os elementos de linha.

Para cada linha, podemos utilizar "[role=cell]" para selecionar as suas células.

Um aspeto a ter em conta é que a célula PIC contém uma imagem e devemos escrever uma regra especial para extrair o seu URL.

Implementação de um raspador de tabelas HTML

Agora é altura de tornar as coisas um pouco mais avançadas, utilizando Node.js e cheerio.

Para obter o HTML de um site em um projeto Node.js, você terá que fazer uma solicitação de busca para o site. Isso retorna o HTML como uma string, o que significa que não é possível usar funções DOM do JavaScript para extrair dados. É aí que entra o cheerio. Cheerio é uma biblioteca que permite analisar e manipular a string HTML como se estivesse no contexto de um navegador. Isto significa que pode utilizar selectores CSS familiares para extrair dados do HTML, tal como faria num browser.

Também é importante notar que o HTML devolvido de um pedido de pesquisa pode ser diferente do HTML que vê no browser. Isso ocorre porque o navegador executa JavaScript, que pode modificar o HTML que é exibido. Num pedido de pesquisa, está apenas a obter o HTML em bruto, sem quaisquer modificações de JavaScript.

Apenas para fins de teste, vamos fazer um pedido de busca ao nosso site de destino e escrever o HTML resultante num ficheiro local:

//index.js

const fs = require('fs');

(async () => {

const response = await fetch('https://chartmasters.org/best-selling-artists-of-all-time/');

const raw_html = await response.text();

fs.writeFileSync('raw-best-selling-artists-of-all-time.html', raw_html);

})();

// it will write the raw html to raw-best-selling-artists-of-all-time.html

// try it with other websites: https://randomwordgenerator.com/

Pode executá-lo com:

node index.js

E vais receber:

imagem do blogue

A estrutura da tabela permanece a mesma. Isto significa que os selectores que encontrámos no capítulo anterior continuam a ser relevantes.

Ok, agora vamos continuar com o código real:

Depois de fazer o pedido de fetch a https://chartmasters.org/best-selling-artists-of-all-time/, terá de carregar o html em bruto no cheerio:

const cheerio = require('cheerio');

(async () => {

const response = await fetch('https://chartmasters.org/best-selling-artists-of-all-time/');

const raw_html = await response.text();

const $ = cheerio.load(raw_html);

})();

Com o cheerio carregado, vamos ver como podemos extrair os cabeçalhos:

    const headers = $("[role=columnheader]")

const header_names = []

headers.each((index, el) => {

header_names.push($(el).text())

})
 //header_names

[

'#',

'PIC',

'Artist',

'Total CSPC',

'Studio Albums Sales',

'Other LPs Sales',

'Physical Singles Sales',

'Digital Singles Sales',

'Sales Update',

'Streams EAS (Update)'

]

E a primeira fila:

    const first_row = $("tbody [role=row]")[0]

const first_row_cells = $(first_row).find('[role=cell]')

const first_row_data = []

first_row_cells.each((index, f_r_c) => {

const image = $(f_r_c).find('img').attr('src')

if(image) {

first_row_data.push(image)

}

else {

first_row_data.push($(f_r_c).text())

}

})
   //first_row_data

[

'1',

'https://i.scdn.co/image/ab6761610000f178e9348cc01ff5d55971b22433',

'The Beatles',

'421,300,000',

'160,650,000',

'203,392,000',

'116,080,000',

'35,230,000',

'03/01/17',

'17,150,000 (01/03/23)'

]

Lembra-se de quando raspamos a tabela HTML com JavaScript no console do Browser Developer Tools? Neste ponto, replicamos a mesma funcionalidade que implementamos lá, mas no contexto do projeto Node.js. Você pode rever o último capítulo e observar as muitas semelhanças entre as duas implementações.

Vamos reescrever o código para extrair todas as linhas:

    const rows = $("tbody [role=row]")

const rows_data = []

rows.each((index, row) => {

const row_cell_data = []

const cells = $(row).find('[role=cell]')

cells.each((index, cell) => {

const image = $(cell).find('img').attr('src')

if(image) {

row_cell_data.push(image)

}

else {

row_cell_data.push($(cell).text())

}

})
        rows_data.push(row_cell_data)

})

//rows_data

[

[

'1',

'https://i.scdn.co/image/ab6761610000f178e9348cc01ff5d55971b22433',

'The Beatles',

'421,300,000',

'160,650,000',

'203,392,000',

'116,080,000',

'35,230,000',

'03/01/17',

'17,150,000 (01/03/23)'

],

[

'2',

'https://i.scdn.co/image/ab6761610000f178a2a0b9e3448c1e702de9dc90',

'Michael Jackson',

'336,084,000',

'182,600,000',

'101,997,000',

'79,350,000',

'79,930,000',

'09/27/17',

'15,692,000 (01/06/23)'

],

...

]

Agora que obtivemos os dados, vamos ver como podemos exportá-los.

Exportar os dados

Depois de ter obtido com êxito os dados que pretende extrair, é importante considerar a forma como pretende armazenar as informações. As opções mais populares são .json e .csv. Escolha o formato que melhor se adapta às suas necessidades e requisitos específicos.

Exportar os dados para json

Se pretender exportar os dados para .json, deve primeiro agrupar os dados num objeto JavaScript que se assemelhe ao formato .json.

Temos uma matriz de nomes de cabeçalho (header_names) e outra matriz (rows_data, uma matriz de matrizes) que contém os dados das linhas. O formato .json armazena informações em pares chave-valor. Precisamos de agrupar os nossos dados de forma a que sigam essa regra:

[ // this is what we need to obtain

{

'#': '1',

PIC: 'https://i.scdn.co/image/ab6761610000f178e9348cc01ff5d55971b22433',

Artist: 'The Beatles',

'Total CSPC': '421,300,000',

'Studio Albums Sales': '160,650,000',

'Other LPs Sales': '203,392,000',

'Physical Singles Sales': '116,080,000',

'Digital Singles Sales': '35,230,000',

'Sales Update': '03/01/17',

'Streams EAS (Update)': '17,150,000 (01/03/23)'

},

{

'#': '2',

PIC: 'https://i.scdn.co/image/ab6761610000f178a2a0b9e3448c1e702de9dc90',

Artist: 'Michael Jackson',

'Total CSPC': '336,084,000',

'Studio Albums Sales': '182,600,000',

'Other LPs Sales': '101,997,000',

'Physical Singles Sales': '79,350,000',

'Digital Singles Sales': '79,930,000',

'Sales Update': '09/27/17',

'Streams EAS (Update)': '15,692,000 (01/06/23)'

}

...

]

Eis como o pode conseguir:

     // go through each row

const table_data = rows_data.map(row => {

// create a new object

const obj = {};

// forEach element in header_names

header_names.forEach((header_name, i) => {

// add a key-value pair to the object where the key is the current header name and the value is the value at the same index in the row

obj[header_name] = row[i];

});

// return the object

return obj;

});

Agora pode utilizar a função JSON.stringify() para converter o objeto JavaScript numa cadeia de caracteres .json e depois escrevê-la num ficheiro.

 const fs = require('fs');

const table_data_json_string = JSON.stringify(table_data, null, 2)

fs.writeFile('table_data.json', table_data_json_string, (err) => {

if (err) throw err;

console.log('The file has been saved as table_data.json!');

})

Exportar os dados para csv

O formato .csv significa "valores separados por vírgulas". Se quiser guardar a sua tabela em .csv, terá de a escrever num formato semelhante a este:

id,name,age // os cabeçalhos da tabela seguidos das linhas

1,Alice,20

2,Bob,25

3,Charlie,30

Os dados da nossa tabela são constituídos por uma matriz de nomes de cabeçalho (header_names) e outra matriz (rows_data, uma matriz de matrizes) que contém os dados das linhas. Eis como pode escrever estes dados num ficheiro .csv:

    let csv_string = header_names.join(',') + '\n'; // add the headers

// forEach row in rows_data

rows_data.forEach(row => {

// add the row to the CSV string

csv_string += row.join(',') + '\n';

});



// write the string to a file

fs.writeFile('table_data.csv', csv_string, (err) => {

if (err) throw err;

console.log('The file has been saved as table_data.csv!');

});

Evitar ser bloqueado

Já alguma vez se deparou com o problema de tentar fazer scraping de um Web site e perceber que a página da qual está a tentar extrair informações não está a carregar totalmente? Isto pode ser frustrante, especialmente se souber que o site está a utilizar JavaScript para gerar o seu conteúdo. Não temos a capacidade de executar JavaScript como um navegador normal faz, o que pode levar a dados incompletos ou até mesmo ser banido do site por fazer muitos pedidos num curto período de tempo.

Uma solução para este problema é o WebScrapingApi. Com o nosso serviço, pode simplesmente fazer pedidos à nossa API e esta tratará de todas as tarefas complexas por si. Executa JavaScript, roda proxies e até trata de CAPTCHAs.

Here is how you can make a simple fetch request to a <target_url> and write the response to a file:

const fs = require('fs');

(async () => {

const result = await fetch('https://api.webscrapingapi.com/v1?' + new URLSearchParams({

api_key: '<api_key>',

url: '<target_url>',

render_js: 1,

proxy_type: 'residential',

}))



const html = await result.text();

fs.writeFileSync('wsa_test.html', html);

})();

Pode obter uma API_KEY gratuita criando uma nova conta em https://www.webscrapingapi.com/

Ao especificar o parâmetro render_js=1, activará a capacidade do WebScrapingAPI de aceder à página Web visada utilizando um browser sem cabeça que permite que os elementos da página JavaScript sejam processados antes de lhe entregar o resultado final da recolha de dados.

Consulte https://docs.webscrapingapi.com/webscrapingapi/advanced-api-features/proxies para descobrir as capacidades dos nossos proxies rotativos.

Conclusão

Neste artigo, aprendemos sobre o poder da raspagem de tabelas HTML com JavaScript e como ela pode nos ajudar a extrair dados valiosos de sites. Explorámos a estrutura das tabelas HTML e aprendemos a utilizar a biblioteca cheerio em combinação com o Node.js para extrair facilmente dados das mesmas. Também analisámos diferentes formas de exportar os dados, incluindo os formatos CSV e JSON. Ao seguir as etapas descritas neste artigo, você deve ter uma base sólida para extrair tabelas HTML em qualquer site.

Quer seja um profissional experiente ou esteja apenas a começar o seu primeiro projeto de scraping, a WebScrapingAPI's está aqui para o ajudar em cada passo do caminho. A nossa equipa tem todo o gosto em responder a quaisquer questões que possa ter e oferecer orientação nos seus projectos. Por isso, se alguma vez se sentir bloqueado ou apenas precisar de uma ajuda, não hesite em contactar-nos.

Notícias e actualizações

Mantenha-se atualizado com os mais recentes guias e notícias sobre raspagem da Web, subscrevendo a nossa newsletter.

We care about the protection of your data. Read our <l>Privacy Policy</l>.Privacy Policy.

Artigos relacionados

miniatura
GuiasTutorial do Scrapy Splash: Dominando a arte de raspar sites renderizados em JavaScript com Scrapy e Splash

Aprenda a extrair sites dinâmicos renderizados em JavaScript usando o Scrapy e o Splash. Desde a instalação até à escrita de um spider, à manipulação da paginação e à gestão das respostas do Splash, este guia abrangente oferece instruções passo a passo tanto para principiantes como para especialistas.

Ștefan Răcila
avatar do autor
Ștefan Răcila
6 min. de leitura
miniatura
Ciência da recolha de dados da WebWeb Scraping facilitado: a importância da análise de dados

Descubra como extrair e organizar eficientemente dados para raspagem da Web e análise de dados através de análise de dados, bibliotecas de análise de HTML e metadados schema.org.

Suciu Dan
avatar do autor
Suciu Dan
12 min ler
miniatura
GuiasDesbloqueie sítios Web e proteja a sua identidade com proxies e Axios Node.js

Saiba como usar proxies com Axios e Node.js para uma raspagem eficiente da Web. Dicas, exemplos de código e os benefícios de usar WebScrapingAPI incluídos.

Suciu Dan
avatar do autor
Suciu Dan
7 min. de leitura