Voltar ao blogue
Guias
Raluca PenciucLast updated on Mar 31, 202613 min read

O Guia Definitivo para Web Scraping com C++

O Guia Definitivo para Web Scraping com C++

Há dois milhões de anos, um grupo de homens das cavernas percebeu que uma pedra presa a um pau poderia ser útil. A partir daí, as coisas só se complicaram um pouco. Hoje em dia, os nossos problemas já não têm tanto a ver com fugir de tigres dentes-de-sabre, mas sim com o facto de os colegas de equipa darem nomes como «did sutff» aos seus commits.

Embora as dificuldades tenham mudado, a nossa obsessão em criar ferramentas para as superar não mudou. Os web scrapers são prova disso. São ferramentas digitais concebidas para resolver problemas digitais.

Hoje vamos construir uma nova ferramenta do zero, mas em vez de pedras e paus, vamos usar C++, o que é indiscutivelmente mais difícil. Por isso, fique atento para aprender a criar um web scraper em C++ e a utilizá-lo!

Compreender o web scraping

Independentemente da linguagem de programação que escolher, precisa de compreender como funcionam os web scrapers. Este conhecimento é fundamental para escrever o script e ter uma ferramenta funcional no final do dia.

As vantagens do web scraping

Não é difícil imaginar que um bot que faça toda a sua pesquisa por si é muito melhor do que copiar informações manualmente. As vantagens aumentam exponencialmente se precisar de grandes quantidades de dados. Se estiver a treinar um algoritmo de aprendizagem automática, por exemplo, um web scraper pode poupar-lhe meses de trabalho.

Para maior clareza, vamos rever todas as formas como os web scrapers o ajudam:

  • Gaste menos tempo em trabalho tedioso — este é o benefício mais evidente. Os scrapers extraem dados tão rapidamente quanto o seu navegador demoraria a carregar a página. Dê ao bot uma lista de URLs e obterá instantaneamente o seu conteúdo.
  • Obtenha maior precisão dos dados — a intervenção humana leva inevitavelmente a erros humanos. Em comparação, o bot irá sempre extrair toda a informação, exatamente como está apresentada, e analisá-la de acordo com as suas instruções.
  • Mantenha uma base de dados organizada — à medida que recolhe dados, pode tornar-se cada vez mais difícil acompanhar tudo. O scraper não só obtém o conteúdo, como também o armazena no formato que mais lhe facilitar a vida.
  • Utilize informações atualizadas — em muitas situações, os dados mudam de um dia para o outro. Por exemplo, basta olhar para os mercados bolsistas ou para as listagens de lojas online. Com algumas linhas de código, o seu bot pode extrair as mesmas páginas em intervalos fixos e atualizar a sua base de dados com as informações mais recentes.

A WebScrapingAPI existe para lhe proporcionar todos esses benefícios, ao mesmo tempo que contorna todos os diferentes obstáculos que os scrapers frequentemente encontram na web. Tudo isto parece ótimo, mas como é que se traduz em projetos reais?

Casos de utilização de web scraping

Existem muitas formas diferentes de utilizar os web scrapers. O céu é o limite! Ainda assim, alguns casos de utilização são mais comuns do que outros.

Vamos aprofundar cada situação:

  • Otimização para motores de busca — Extrair páginas de resultados de pesquisa para as suas palavras-chave é uma forma fácil e rápida de determinar quem precisa de ultrapassar no ranking e que tipo de conteúdo o pode ajudar a fazê-lo.
  • Pesquisa de mercado — Depois de verificar o desempenho dos seus concorrentes nas pesquisas, pode ir mais longe e analisar toda a sua presença digital. Use o web scraper para ver como eles utilizam o PPC, descrevem os seus produtos, que tipo de modelo de preços utilizam e assim por diante. Basicamente, qualquer informação pública está ao seu alcance.
  • Proteção da marca — As pessoas estão a falar da sua marca. Idealmente, são todas coisas boas, mas isso não é garantido. Um bot está bem equipado para navegar em sites de avaliações e plataformas de redes sociais e notificá-lo sempre que a sua marca for mencionada. Seja o que for que estejam a dizer, estará pronto para defender os interesses da sua marca.
  • Geração de leads — Colmatar a lacuna entre a sua equipa de vendas e possíveis clientes na Internet raramente é fácil. Bem, torna-se muito mais fácil assim que utiliza um bot de web scraping para recolher informações de contacto em registos comerciais online, como as Páginas Amarelas ou o LinkedIn.
  • Marketing de conteúdo — Criar conteúdo de alta qualidade dá muito trabalho, sem dúvida. Não só tem de encontrar fontes credíveis e uma grande quantidade de informação, como também aprender o tipo de tom e abordagem que o seu público irá apreciar. Felizmente, esses passos tornam-se insignificantes se tiver um bot para fazer o trabalho pesado.

Existem muitos outros exemplos por aí. Claro que também pode desenvolver uma forma totalmente nova de utilizar a extração de dados a seu favor. Encorajamos sempre a utilização criativa da nossa API.

Os desafios do web scraping

Por mais valiosos que sejam os web scrapers, nem tudo são flores. Alguns sites não gostam de ser visitados por bots. Não é difícil programar o seu scraper para evitar sobrecarregar o site visitado, mas a vigilância deles contra bots é justificada. Afinal, o site pode não ser capaz de distinguir entre um bot bem-educado e um malicioso.

Como resultado, existem alguns desafios com que os scrapers se deparam enquanto estão em ação.

Os obstáculos mais problemáticos são:

  • Bloqueios de IP — Existem várias formas de determinar se um visitante é humano ou uma máquina. A ação a tomar após identificar um bot, no entanto, é muito mais simples: o bloqueio de IP. Embora isto não aconteça frequentemente se tomar as precauções necessárias, continua a ser uma boa ideia ter um conjunto de proxies preparado para que possa continuar a extrair dados mesmo que um IP seja banido.
  • Identificação do navegador — Cada pedido que envia a um site também revela algumas das suas informações. O IP é o exemplo mais comum, mas os cabeçalhos dos pedidos também informam o site sobre o seu sistema operativo, navegador e outros pequenos detalhes. Se um site usar esta informação para identificar quem está a enviar os pedidos e perceber que está a navegar muito mais rápido do que um humano deveria, pode esperar ser bloqueado imediatamente.
  • Renderização de JavaScript — A maioria dos sites modernos é dinâmica. Ou seja, utilizam código JavaScript para personalizar as páginas para o utilizador e oferecer uma experiência mais personalizada. O problema é que os bots simples ficam presos nesse código, uma vez que não o conseguem executar. O resultado: o scraper recupera JavaScript em vez do HTML pretendido, que contém informações relevantes.
  • Captchas — Quando os sites não têm a certeza se um visitante é um humano ou um bot, redirecionam-no para uma página de Captcha. Para nós, é, na melhor das hipóteses, um pequeno incómodo, mas para os bots, é normalmente um bloqueio total; a menos que tenham scripts de resolução de Captcha incluídos.
  • Limitação de pedidos — A forma mais simples de impedir que os visitantes sobrecarreguem o servidor do site é limitar o número de pedidos que um único IP pode enviar num período de tempo fixo. Depois de atingido esse número, o scraper pode ter de esperar que o temporizador termine ou pode ter de resolver um Captcha. Seja como for, não é bom para o seu projeto de extração de dados.

Compreender a web

Se pretende criar um scraper da web, deve conhecer alguns conceitos-chave sobre o funcionamento da Internet. Afinal, o seu bot não só utilizará a Internet para recolher dados, como também terá de se misturar com os outros milhares de milhões de utilizadores.

Gostamos de pensar nos sites como livros, e ler uma página significa apenas virar para o número correto e olhar. Na realidade, é mais parecido com telegramas enviados entre si e o livro. Solicita uma página e ela é-lhe enviada. Depois, pede a seguinte e acontece o mesmo.

Todo este vaivém ocorre através do HTTP, ou Protocolo de Transferência de Hipertexto. Para que você, o visitante, veja uma página, o seu navegador envia um pedido HTTP e recebe uma resposta HTTP do servidor. O conteúdo que deseja estará incluído nessa resposta.

As solicitações HTTP são compostas por quatro componentes:

  • O URL (Uniform Resource Locator) é o endereço para o qual está a enviar os pedidos. Conduz a um recurso único que pode ser uma página web inteira, um único ficheiro ou qualquer coisa entre ambos.
  • O Método indica que tipo de ação pretende realizar. O método mais comum é o GET, que recupera dados do servidor. Aqui está uma lista dos métodos mais comuns.
  • Os cabeçalhos são fragmentos de metadados que dão forma à sua solicitação. Por exemplo, se tiver de fornecer uma senha ou credenciais para aceder aos dados, elas vão para o seu cabeçalho especial. Se quiser receber dados especificamente no formato JSON, mencione isso num cabeçalho. O User-Agent é um dos cabeçalhos mais conhecidos na extração de dados da web, porque os sites o utilizam para identificar os visitantes.
  • O Corpo é a parte de uso geral da solicitação que armazena dados. Se estiver a obter conteúdo, provavelmente estará vazio. Por outro lado, quando quiser enviar informações para o servidor, elas estarão aqui.

Após enviar a solicitação, receberá uma resposta mesmo que a solicitação não tenha conseguido receber quaisquer dados. A estrutura é semelhante a esta:

  • O Código de Estado é um código de três dígitos que indica imediatamente o que aconteceu. Resumidamente, um código que começa por «2» significa normalmente sucesso, e um que começa por «4» indica falha.
  • Os cabeçalhos têm a mesma função que os seus equivalentes. Por exemplo, se receber um tipo específico de ficheiro, um cabeçalho indicará o formato.
  • O Corpo também está presente. Se solicitou conteúdo com GET e a solicitação for bem-sucedida, encontrará os dados aqui.

As APIs REST utilizam protocolos HTTP, tal como os navegadores web. Assim, se decidir que os web scrapers em C++ dão demasiado trabalho, esta informação também lhe será útil caso opte por utilizar a WebScrapingAPI, que já lida com todos os desafios de extração de dados.

Compreender o C++

Em termos de linguagens de programação, não há nada mais clássico do que C e C++. A linguagem surgiu em 1985 como a versão aperfeiçoada do «C com classes».

Embora o C++ seja utilizado para programação de uso geral, não é propriamente a primeira linguagem que se consideraria para um web scraper. Tem algumas desvantagens, mas a ideia não é desprovida de méritos. Vamos explorá-los, está bem?

O C++ é orientado a objetos, o que significa que utiliza classes, abstração de dados e herança para tornar o seu código mais fácil de reutilizar e adaptar a diferentes necessidades. Uma vez que os dados são tratados como um objeto, é mais fácil para si armazená-los e analisá-los.

Muitos programadores conhecem pelo menos um pouco de C++. Mesmo que não o tenha aprendido na universidade, você (ou um colega de equipa) provavelmente sabe um pouco de C++. Isso estende-se a toda a comunidade de desenvolvimento de software, por isso não será difícil obter uma segunda opinião sobre o código.

O C++ é altamente escalável. Se começar com um projeto pequeno e decidir que o web scraping é para si, a maior parte do código é reutilizável. Algumas pequenas alterações aqui e ali, e estará pronto para volumes de dados muito maiores.

Por outro lado, o C++ é uma linguagem de programação estática. Embora isso garanta uma melhor integridade dos dados, não é tão útil quanto as linguagens dinâmicas quando se lida com a Internet.

Além disso, o C++ não é adequado para criar crawlers. Isto pode não ser um problema se pretender apenas um scraper. Mas se pretender adicionar um crawler para gerar listas de URLs, o C++ não é uma boa escolha.

Ok, falámos sobre muitas coisas importantes, mas vamos ao cerne do artigo — programar um web scraper em C++.

Criar um scraper web com C++

Pré-requisitos

  • IDE de C++. Neste guia, iremos utilizar o Visual Studio.
  • O vcpkg é um gestor de pacotes C/C++ criado e mantido pela Windows
  • O cpr é uma biblioteca C/C++ para pedidos HTTP, construída como um wrapper para o clássico cURL e inspirada na biblioteca requests do Python.
  • O gumbo é um analisador HTML inteiramente escrito em C, que fornece wrappers para várias linguagens de programação, incluindo C++.

Configurar o ambiente

1. Após descarregar e instalar o Visual Studio, crie um projeto simples utilizando um modelo de Aplicação de Consola.

2. Agora vamos configurar o nosso gestor de pacotes. O vcpkg fornece um tutorial bem escrito para o ajudar a começar o mais rápido possível.

Nota: quando a instalação estiver concluída, será útil definir uma variável de ambiente para que possa executar o vcpkg a partir de qualquer local no seu computador.

3. Agora é hora de instalar as bibliotecas de que precisamos. Se definiu uma variável de ambiente, abra qualquer terminal e execute os seguintes comandos:

> vcpkg install cpr
> vcpkg install gumbo
> vcpkg integrate install

Se não definiu uma variável de ambiente, basta navegar até à pasta onde instalou o vcpkg, abrir uma janela de terminal e executar os mesmos comandos.

Os dois primeiros comandos instalam os pacotes de que precisamos para construir o nosso scraper, e o terceiro ajuda-nos a integrar as bibliotecas no nosso projeto sem esforço.

Escolha um site e inspecione o HTML

E agora estamos prontos! Antes de construir o scraper web, precisamos de escolher um site e inspecionar o seu código HTML.

Fomos à Wikipédia e escolhemos uma página aleatória da secção «Sabias que…». Assim, a página extraída de hoje será o artigo da Wikipédia sobre a defesa da semente de papoila, e iremos extrair alguns dos seus componentes. Mas primeiro, vamos dar uma vista de olhos à estrutura da página. Clica com o botão direito em qualquer ponto do artigo, depois em «Inspecionar elemento» e voilà! O HTML é nosso.

Extrair o título

Agora podemos começar a escrever o código. Para extrair a informação, temos de descarregar o HTML localmente. Primeiro, importamos as bibliotecas que acabámos de descarregar:

#include <iostream>
#include <fstream>
#include "cpr/cpr.h"
#include "gumbo.h"

Em seguida, fazemos um pedido HTTP ao site de destino para recuperar o HTML.

std::string extract_html_page()
{
    cpr::Url url = cpr::Url{"https://en.wikipedia.org/wiki/Poppy_seed_defence"};
    cpr::Response response = cpr::Get(url);
    return response.text;
}

int main()
{
    std::string page_content = extract_html_page();
}

A variável page_content contém agora o HTML do artigo, e vamos utilizá-la para extrair os dados de que precisamos. É aqui que a biblioteca gumbo se torna útil.

Usamos o método gumbo_parse para converter a string page_content anterior numa árvore HTML e, em seguida, chamamos a nossa função implementada search_for_title para o nó raiz.

int main()

{

    std::string page_content = extract_html_page();

    GumboOutput* parsed_response = gumbo_parse(page_content.c_str());

    search_for_title(parsed_response->root);

    // free the allocated memory

    gumbo_destroy_output(&kGumboDefaultOptions, parsed_response);

}

A função chamada percorrerá a árvore HTML em profundidade para procurar a tag <h1> através de chamadas recursivas. Quando encontrar o título, irá exibi-lo na consola e encerrará a execução.

void search_for_title(GumboNode* node)
{
    if (node->type != GUMBO_NODE_ELEMENT)
        return;

    if (node->v.element.tag == GUMBO_TAG_H1)
    {
        GumboNode* title_text = static_cast<GumboNode*>(node->v.element.children.data[0]);
        std::cout << title_text->v.text.text << "\n";
        return;
    }

    GumboVector* children = &node->v.element.children;
    for (unsigned int i = 0; i < children->length; i++)
        search_for_title(static_cast<GumboNode*>(children->data[i]));
}

O mesmo princípio básico é aplicado ao resto das tags, percorrendo a árvore e obtendo o que nos interessa. Vamos obter todos os links e extrair o seu atributo href.

void search_for_links(GumboNode* node)
{
    if (node->type != GUMBO_NODE_ELEMENT)
        return;

    if (node->v.element.tag == GUMBO_TAG_A)
    {
        GumboAttribute* href = gumbo_get_attribute(&node->v.element.attributes, "href");
        if (href)
            std::cout << href->value << "\n";
    }

    GumboVector* children = &node->v.element.children;
    for (unsigned int i = 0; i < children->length; i++)
    {
        search_for_links(static_cast<GumboNode*>(children->data[i]));
    }
}

Vê? Praticamente o mesmo código, exceto pela tag que estamos à procura. O método gumbo_get_attribute pode extrair qualquer atributo que nomeemos. Portanto, pode usá-lo para procurar classes, IDs, etc.

É essencial verificar se o valor do atributo é nulo antes de o apresentar. Em linguagens de programação de alto nível, isto é desnecessário, uma vez que irá simplesmente apresentar uma cadeia de caracteres vazia, mas em C++, o programa irá falhar.

Escrever num ficheiro CSV

Existem muitos links por aí, todos misturados pelo conteúdo. E este foi um artigo realmente curto, também. Então, vamos guardá-los todos externamente e ver como podemos fazer uma distinção entre eles.

Primeiro, criamos e abrimos um ficheiro CSV. Fazemos isto fora da função, mesmo junto às importações. A nossa função é recursiva, o que significa que teremos MUITOS ficheiros se criar um novo ficheiro sempre que for chamada.

std::ofstream writeCsv("links.csv");

Depois, na nossa função principal, escrevemos a primeira linha do ficheiro CSV mesmo antes de chamar a função pela primeira vez. Não se esqueça de fechar o ficheiro depois de a execução estar concluída.

writeCsv << "type,link" << "\n";
search_for_links(parsed_response->root);
writeCsv.close();

Agora, escrevemos o seu conteúdo. Na nossa função search_for_links, quando encontramos uma tag <a>, em vez de a exibir na consola, fazemos o seguinte:

if (node->v.element.tag == GUMBO_TAG_A)
{
    GumboAttribute* href = gumbo_get_attribute(&node->v.element.attributes, "href");
    if (href)
    {
        std::string link = href->value;
        if (link.rfind("/wiki") == 0)
            writeCsv << "article," << link << "\n";
        else if (link.rfind("#cite") == 0)
            writeCsv << "cite," << link << "\n";
        else
            writeCsv << "other," << link << "\n";
    }
}

Pegamos no valor do atributo href com este código e colocamo-lo em 3 categorias: artigos, citações e o resto.

Claro que pode ir muito mais longe e definir os seus próprios tipos de links, como aqueles que parecem um artigo mas que, na verdade, são um ficheiro, por exemplo.

Alternativas ao web scraping

Agora já sabe como criar o seu próprio web scraper com C++. Fixe, não é?

Ainda assim, pode ter-se dito a si mesmo, a certa altura: «Isto está a começar a dar mais trabalho do que vale a pena!», e nós compreendemos perfeitamente. Na verdade, programar um scraper é uma excelente experiência de aprendizagem, e os programas são adequados para pequenos conjuntos de dados, mas é basicamente isso.

Uma API de web scraping é a sua melhor opção se precisar de uma ferramenta de extração de dados rápida, fiável e escalável. Isso porque ela vem com todas as funcionalidades de que precisa, como um conjunto rotativo de proxies, renderização em Javascript, solucionadores de Captcha, opções de geolocalização e muito mais.

Não acredita em mim? Então tem de ver por si mesmo! Comece o seu período de teste gratuito da WebScrapingAPI e descubra como o web scraping pode ser acessível!

Sobre o autor
Raluca Penciuc, Desenvolvedor Full-Stack @ WebScrapingAPI
Raluca PenciucDesenvolvedor Full-Stack

Raluca Penciuc é programadora Full Stack na WebScrapingAPI, onde desenvolve scrapers, aperfeiçoa estratégias de evasão e procura formas fiáveis de reduzir a deteção nos sites-alvo.

Comece a construir

Pronto para expandir a sua recolha de dados?

Junte-se a mais de 2.000 empresas que utilizam a WebScrapingAPI para extrair dados da Web à escala empresarial, sem quaisquer custos de infraestrutura.