Utilizando o Gumbo-Parser para Análise de Documentos HTML5

O Gumbo-Parser é uma biblioteca de análise HTML5 implementada em C99 puro, projetada para converter documentos HTML em uma árvore DOM estruturada. Esta ferramenta permite o processamento eficiente de conteúdo HTML, facilitando operações como extração de dados ou manipulação de elementos.

Características Técnicas do Gumbo-Parser

  • Implementação em C99: Oferece portabilidade para diversas plataformas sem dependências externas.
  • Conformidade com HTML5: Garante análise correta de estruturas complexas, seguindo especificações padrão.
  • Desempenho Otimizado: Algoritmos eficientes para processamento rápido de documentos grandes.
  • API Simplificada: Interface intuitiva que reduz a curva de aprendizagem para desenvolvedores.

Instalação do Gumbo-Parser

Para instalar a bibliotcea, siga estas etapas:

  1. Obtenha o código-fonte diretamente do repositório oficial.
  2. Execute os scripts de configuração e compile utilizando ferramentas como autotools.
  3. Instale os binários e cabeçalhos no sistema.
cd gumbo-parser
autoreconf -i
./configure --prefix=/usr/local
make -j4
sudo make install

Após a instalação, o cabeçalho principal estará disponível em /usr/local/include/gumbo.h.

Estruturas de Dados Fundamentais

A biblioteca define tipos essenciais para representar o documento HTML:

  • GumboParser: Instância responsável pela análise.
  • GumboNode: Representa um nó genérico na árvore DOM.
  • GumboElement: Especialização para elementos HTML com atributos e filhos.
  • GumboAttribute: Armazena pares nome-valor de atributos.

Exemplo Prático: Extração de Títulos

O código a seguir demonstra como localizar e imprimir o conteúdo da tag <title> em um arquivo HTML:

#include <stdio.h>
#include <stdlib.h>
#include "gumbo.h"

void extract_title(GumboNode* current) {
  if (current->type != GUMBO_NODE_ELEMENT) return;
  GumboElement* elem = &current->v.element;
  if (elem->tag == GUMBO_TAG_TITLE) {
    if (elem->children.length > 0) {
      GumboNode* child = elem->children.data[0];
      if (child->type == GUMBO_NODE_TEXT) {
        printf("Título encontrado: %s\n", child->v.text.text);
      }
    }
  }
  GumboVector* siblings = &elem->children;
  for (unsigned int idx = 0; idx < siblings->length; ++idx) {
    extract_title(siblings->data[idx]);
  }
}

int main(int argc, char** argv) {
  if (argc != 2) {
    fprintf(stderr, "Uso: %s <arquivo.html>\n", argv[0]);
    return EXIT_FAILURE;
  }
  FILE* file_handle = fopen(argv[1], "rb");
  if (!file_handle) {
    perror("Erro ao abrir arquivo");
    return EXIT_FAILURE;
  }
  fseek(file_handle, 0, SEEK_END);
  long file_size = ftell(file_handle);
  rewind(file_handle);
  char* html_buffer = malloc(file_size + 1);
  fread(html_buffer, 1, file_size, file_handle);
  html_buffer[file_size] = '\0';
  fclose(file_handle);

  GumboParser* parser_instance = gumbo_parse(html_buffer);
  extract_title(parser_instance->root);
  gumbo_destroy_parser(parser_instance);
  free(html_buffer);
  return EXIT_SUCCESS;
}

Exemplo Avançado: Coleta de Links

Este exemplo em C++ percorre a árvore DOM para extrair todos os hiperlinks presentes no documento:

#include <iostream>
#include <fstream>
#include <vector>
#include "gumbo.h"

void collect_links(GumboNode* node, std::vector<std::string>& links) {
  if (node->type != GUMBO_NODE_ELEMENT) return;
  GumboElement* element_data = &node->v.element;
  if (element_data->tag == GUMBO_TAG_A) {
    GumboAttribute* href_attr = gumbo_get_attribute(&element_data->attributes, "href");
    if (href_attr) {
      links.emplace_back(href_attr->value);
    }
  }
  for (unsigned int i = 0; i < element_data->children.length; ++i) {
    collect_links(static_cast<GumboNode*>(element_data->children.data[i]), links);
  }
}

int main(int argc, char** argv) {
  if (argc != 2) {
    std::cerr << "Sintaxe: " << argv[0] << " <arquivo.html>" << std::endl;
    return 1;
  }
  std::ifstream input_file(argv[1], std::ios::binary | std::ios::ate);
  if (!input_file.is_open()) {
    std::cerr << "Falha ao ler arquivo." << std::endl;
    return 1;
  }
  std::streamsize size = input_file.tellg();
  input_file.seekg(0, std::ios::beg);
  std::vector<char> buffer(size);
  if (!input_file.read(buffer.data(), size)) {
    std::cerr << "Erro na leitura." << std::endl;
    return 1;
  }
  std::string html_content(buffer.begin(), buffer.end());

  GumboParser* parser = gumbo_parse(html_content.c_str());
  std::vector<std::string> found_links;
  collect_links(parser->root, found_links);
  for (const auto& link : found_links) {
    std::cout << link << std::endl;
  }
  gumbo_destroy_parser(parser);
  return 0;
}

Validação e Testes

A suíte de testes incluída no repositório verifica a conformidade do analisador com diversos cenários HTML. Para executar os testes após a compilação, utilize o comando make check.

Tags: Gumbo-Parser html5 c99 biblioteca de análise DOM

Publicado em 6-26 00:56