Volver al blog
Guías
Raluca PenciucLast updated on Mar 31, 202613 min read

La guía definitiva para el web scraping con C++

La guía definitiva para el web scraping con C++

Hace dos millones de años, un grupo de hombres de las cavernas se dio cuenta de que una piedra atada a un palo podía ser útil. A partir de ahí, las cosas se nos fueron un poco de las manos. Hoy en día, nuestros problemas ya no consisten tanto en huir de los tigres dientes de sable como en que nuestros compañeros de equipo llamen a sus commits «did sutff».

Aunque las dificultades han cambiado, nuestra obsesión por crear herramientas para superarlas no ha variado. Los rastreadores web son prueba de ello. Son herramientas digitales diseñadas para resolver problemas digitales.

Hoy vamos a crear una nueva herramienta desde cero, pero en lugar de piedras y palos, usaremos C++, lo cual podría decirse que es más difícil. ¡Así que no te pierdas este artículo para aprender a crear un web scraper en C++ y a utilizarlo!

Comprender el web scraping

Independientemente del lenguaje de programación que elijas, necesitas entender cómo funcionan los web scrapers. Este conocimiento es fundamental para escribir el script y tener una herramienta funcional al final del día.

Las ventajas del web scraping

No es difícil imaginar que un bot que haga toda la investigación por ti es mucho mejor que copiar la información a mano. Las ventajas crecen exponencialmente si necesitas grandes cantidades de datos. Si estás entrenando un algoritmo de aprendizaje automático, por ejemplo, un rastreador web puede ahorrarte meses de trabajo.

Para mayor claridad, repasemos todas las formas en que los rastreadores web te ayudan:

  • Dedica menos tiempo a tareas tediosas: esta es la ventaja más evidente. Los scrapers extraen datos tan rápido como tardaría tu navegador en cargar la página. Dale al bot una lista de URL y obtendrás su contenido al instante.
  • Consigue una mayor precisión en los datos: las manos humanas conducen inevitablemente a errores humanos. En comparación, el bot siempre extraerá toda la información, tal y como se presenta, y la analizará según tus instrucciones.
  • Mantén una base de datos organizada: a medida que recopilas datos, puede resultar cada vez más difícil llevar un control de todo. El scraper no solo obtiene el contenido, sino que también lo almacena en el formato que más te facilite la vida.
  • Utiliza información actualizada: en muchas situaciones, los datos cambian de un día para otro. Por ejemplo, basta con fijarse en los mercados bursátiles o en los listados de tiendas online. Con unas pocas líneas de código, tu bot puede rastrear las mismas páginas a intervalos fijos y actualizar tu base de datos con la información más reciente.

WebScrapingAPI existe para ofrecerte todas esas ventajas, al tiempo que sortea todos los obstáculos con los que suelen encontrarse los rastreadores en la web. Todo esto suena muy bien, pero ¿cómo se traduce en proyectos reales?

Casos de uso del web scraping

Hay muchas formas diferentes de utilizar los rastreadores web. ¡Las posibilidades son infinitas! Aun así, algunos casos de uso son más comunes que otros.

Veamos con más detalle cada situación:

  • Optimización de motores de búsqueda: extraer páginas de resultados de búsqueda para tus palabras clave es una forma fácil y rápida de determinar a quién debes superar en el ranking y qué tipo de contenido puede ayudarte a hacerlo.
  • Investigación de mercado — Después de comprobar cómo les va a tus competidores en las búsquedas, puedes ir más allá y analizar toda su presencia digital. Usa el rastreador web para ver cómo utilizan el PPC, cómo describen sus productos, qué tipo de modelo de precios utilizan, etc. Básicamente, toda la información pública está al alcance de tu mano.
  • Protección de la marca — La gente está hablando de tu marca. Lo ideal es que todo sean cosas buenas, pero eso no está garantizado. Un bot está perfectamente equipado para navegar por sitios de reseñas y plataformas de redes sociales e informarte cada vez que se mencione tu marca. Digan lo que digan, estarás preparado para defender los intereses de tu marca.
  • Generación de clientes potenciales — Tender un puente entre tu equipo de ventas y los posibles clientes en Internet rara vez es fácil. Bueno, se vuelve mucho más fácil una vez que utilizas un bot de web scraping para recopilar información de contacto en registros empresariales online como las Páginas Amarillas o LinkedIn.
  • Marketing de contenidos: crear contenido de alta calidad requiere mucho trabajo, de eso no hay duda. No solo tienes que encontrar fuentes fiables y una gran cantidad de información, sino también aprender el tipo de tono y enfoque que gustará a tu público. Por suerte, esos pasos se vuelven insignificantes si cuentas con un bot que se encargue del trabajo pesado.

Hay muchos otros ejemplos por ahí. Por supuesto, también podrías desarrollar una forma completamente nueva de utilizar la extracción de datos en tu beneficio. Siempre fomentamos el uso creativo de nuestra API.

Los retos del web scraping

Por muy valiosos que sean los web scrapers, no todo es de color de rosa. A algunos sitios web no les gusta que los visiten los bots. No es difícil programar tu scraper para evitar sobrecargar el sitio web visitado, pero su vigilancia frente a los bots está justificada. Al fin y al cabo, es posible que el sitio no sea capaz de distinguir entre un bot educado y uno malicioso.

Como resultado, los rastreadores se enfrentan a algunos retos en su trabajo.

Los obstáculos más problemáticos son:

  • Bloqueos de IP: hay varias formas de determinar si un visitante es un humano o una máquina. Sin embargo, la medida a tomar tras identificar un bot es mucho más sencilla: el bloqueo de IP. Aunque esto no suele ocurrir si se toman las precauciones necesarias, sigue siendo una buena idea tener preparada una lista de proxies para poder seguir extrayendo datos incluso si se bloquea una IP.
  • Huella digital del navegador: cada solicitud que envías a un sitio web también revela parte de tu información. La IP es el ejemplo más común, pero los encabezados de solicitud también informan al sitio sobre tu sistema operativo, navegador y otros pequeños detalles. Si un sitio web utiliza esta información para identificar quién envía las solicitudes y se da cuenta de que estás navegando mucho más rápido de lo que debería hacerlo un humano, es de esperar que te bloqueen rápidamente.
  • Renderización de JavaScript: la mayoría de los sitios web modernos son dinámicos. Es decir, utilizan código JavaScript para personalizar las páginas para el usuario y ofrecer una experiencia más adaptada. El problema es que los bots simples se atascan en ese código, ya que no pueden ejecutarlo. El resultado: el rastreador recupera JavaScript en lugar del HTML previsto que contiene la información relevante.
  • Captchas — Cuando los sitios web no están seguros de si un visitante es un humano o un bot, lo redirigen a una página de Captcha. Para nosotros, es una molestia leve en el mejor de los casos, pero para los bots suele suponer un bloqueo total, a menos que incluyan scripts para resolver Captchas.
  • Limitación de solicitudes — La forma más sencilla de evitar que los visitantes saturen el servidor del sitio web es limitar el número de solicitudes que una sola IP puede enviar en un tiempo determinado. Una vez alcanzado ese número, es posible que el rastreador tenga que esperar a que termine el temporizador o que tenga que resolver un Captcha. En cualquier caso, no es bueno para tu proyecto de extracción de datos.

Comprender la web

Si vas a crear un scraper web, debes conocer algunos conceptos clave sobre cómo funciona Internet. Al fin y al cabo, tu bot no solo utilizará Internet para recopilar datos, sino que también tendrá que mezclarse con los otros miles de millones de usuarios.

Nos gusta pensar en los sitios web como libros, y leer una página solo significa pasar a la página correcta y mirar. En realidad, se parece más a telegramas que se envían entre tú y el libro. Solicitas una página y te la envían. Luego pides la siguiente, y ocurre lo mismo.

Todo este intercambio se produce a través del HTTP, o Protocolo de Transferencia de Hipertexto. Para que tú, el visitante, veas una página, tu navegador envía una solicitud HTTP y recibe una respuesta HTTP del servidor. El contenido que deseas se incluirá en esa respuesta.

Las solicitudes HTTP se componen de cuatro elementos:

  • La URL (Localizador Uniforme de Recursos) es la dirección a la que envías las solicitudes. Conduce a un recurso único que puede ser una página web completa, un solo archivo o cualquier cosa intermedia.
  • El método indica qué tipo de acción quieres realizar. El método más común es GET, que recupera datos del servidor. Aquí tienes una lista de los métodos más comunes.
  • Los encabezados son fragmentos de metadatos que dan forma a tu solicitud. Por ejemplo, si tienes que proporcionar una contraseña o credenciales para acceder a los datos, se incluyen en su encabezado específico. Si deseas recibir datos específicamente en formato JSON, lo indicas en un encabezado. User-Agent es uno de los encabezados más conocidos en el web scraping porque los sitios web lo utilizan para identificar a los visitantes.
  • El cuerpo (Body) es la parte de uso general de la solicitud que almacena los datos. Si estás obteniendo contenido, probablemente estará vacío. Por otro lado, cuando quieras enviar información al servidor, se encontrará aquí.

Tras enviar la solicitud, recibirás una respuesta incluso si la solicitud no ha conseguido obtener ningún dato. La estructura tiene este aspecto:

  • El código de estado es un código de tres dígitos que te indica de un vistazo lo que ha ocurrido. En resumen, un código que empieza por «2» suele significar éxito, y uno que empieza por «4» indica un fallo.
  • Los encabezados tienen la misma función que sus homólogos. Por ejemplo, si recibes un tipo específico de archivo, un encabezado te indicará el formato.
  • El cuerpo también está presente. Si has solicitado contenido con GET y la solicitud se ha realizado correctamente, encontrarás los datos aquí.

Las API REST utilizan protocolos HTTP, al igual que los navegadores web. Por lo tanto, si decides que los rastreadores web en C++ suponen demasiado trabajo, esta información también te resultará útil si optas por utilizar WebScrapingAPI, que ya se encarga de todos los retos de extracción de datos.

Comprender C++

En cuanto a lenguajes de programación, no hay nada más clásico que C y C++. El lenguaje apareció en 1985 como la versión perfeccionada de «C con clases».

Aunque C++ se utiliza para la programación de propósito general, no es realmente el primer lenguaje que uno consideraría para un rastreador web. Tiene algunas desventajas, pero la idea no carece de méritos. ¿Las exploramos?

C++ es orientado a objetos, lo que significa que utiliza clases, abstracción de datos y herencia para que tu código sea más fácil de reutilizar y adaptar a diferentes necesidades. Dado que los datos se tratan como un objeto, te resulta más fácil almacenarlos y analizarlos.

Muchos desarrolladores saben al menos un poco de C++. Aunque no lo hayas estudiado en la universidad, es probable que tú (o algún compañero de equipo) sepas algo de C++. Esto se extiende a toda la comunidad de desarrollo de software, por lo que no te resultará difícil obtener una segunda opinión sobre el código.

C++ es altamente escalable. Si empiezas con un proyecto pequeño y decides que el web scraping es lo tuyo, la mayor parte del código es reutilizable. Con unos pocos ajustes aquí y allá, estarás listo para volúmenes de datos mucho mayores.

Por otro lado, C++ es un lenguaje de programación estático. Aunque esto garantiza una mayor integridad de los datos, no resulta tan útil como los lenguajes dinámicos a la hora de trabajar con Internet.

Además, C++ no es muy adecuado para crear rastreadores. Puede que esto no sea un problema si solo quieres un scraper. Pero si vas a añadir un rastreador para generar listas de URL, C++ no es una buena opción.

Bien, hemos hablado de muchas cosas importantes, pero vayamos al meollo del artículo: programar un scraper web en C++.

Creación de un scraper web con C++

Requisitos previos

  • IDE de C++. En esta guía, utilizaremos Visual Studio.
  • vcpkg es un gestor de paquetes de C/C++ creado y mantenido por Windows
  • cpr es una biblioteca de C/C++ para solicitudes HTTP, creada como envoltura del clásico cURL e inspirada en la biblioteca requests de Python.
  • gumbo es un analizador HTML escrito íntegramente en C, que proporciona envoltorios para múltiples lenguajes de programación, incluido C++.

Configuración del entorno

1. Después de descargar e instalar Visual Studio, crea un proyecto sencillo utilizando una plantilla de aplicación de consola.

2. Ahora configuraremos nuestro gestor de paquetes. Vcpkg ofrece un tutorial muy bien redactado para que puedas empezar lo antes posible.

Nota: cuando la instalación haya finalizado, sería útil definir una variable de entorno para que puedas ejecutar vcpkg desde cualquier ubicación de tu ordenador.

3. Ahora es el momento de instalar las bibliotecas que necesitamos. Si has establecido una variable de entorno, abre cualquier terminal y ejecuta los siguientes comandos:

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

Si no has establecido una variable de entorno, simplemente navega hasta la carpeta donde instalaste vcpkg, abre una ventana de terminal y ejecuta los mismos comandos.

Los dos primeros comandos instalan los paquetes que necesitamos para crear nuestro scraper, y el tercero nos ayuda a integrar las bibliotecas en nuestro proyecto sin esfuerzo.

Elige un sitio web e inspecciona el HTML

¡Y ya estamos listos! Antes de crear el scraper web, tenemos que elegir un sitio web e inspeccionar su código HTML.

Fuimos a Wikipedia y elegimos una página al azar de la sección «¿Sabías que…». Así que la página que vamos a extraer hoy será el artículo de Wikipedia sobre la defensa de las semillas de amapola, y extraeremos algunos de sus componentes. Pero primero, echemos un vistazo a la estructura de la página. Haz clic con el botón derecho en cualquier parte del artículo, luego en «Inspeccionar elemento» y ¡voilá! El HTML es nuestro.

Extraer el título

Ahora podemos empezar a escribir el código. Para extraer la información, tenemos que descargar el HTML localmente. Primero, importamos las bibliotecas que acabamos de descargar:

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

A continuación, realizamos una solicitud HTTP al sitio web de destino para recuperar el 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();
}

La variable page_content contiene ahora el HTML del artículo, y la utilizaremos más adelante para extraer los datos que necesitamos. Aquí es donde la biblioteca gumbo nos resulta útil.

Usamos el método gumbo_parse para convertir la cadena page_content anterior en un árbol HTML, y luego llamamos a nuestra función implementada search_for_title para el nodo raíz.

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);

}

La función llamada recorrerá el árbol HTML en profundidad para buscar la etiqueta <h1> mediante llamadas recursivas. Cuando encuentre el título, lo mostrará en la consola y saldrá de la ejecución.

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]));
}

Extraer los enlaces

Se aplica el mismo principio básico al resto de las etiquetas: recorrer el árbol y obtener lo que nos interesa. Obtengamos todos los enlaces y extrayamos su 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]));
    }
}

¿Lo ves? Es prácticamente el mismo código, salvo por la etiqueta que estamos buscando. El método gumbo_get_attribute puede extraer cualquier atributo que le indiquemos. Por lo tanto, puedes utilizarlo para buscar clases, ID, etc.

Es esencial comprobar si el valor del atributo es nulo antes de mostrarlo. En los lenguajes de programación de alto nivel, esto es innecesario, ya que simplemente se mostrará una cadena vacía, pero en C++, el programa se bloqueará.

Escribir en un archivo CSV

Hay muchos enlaces por ahí, todos mezclados a lo largo del contenido. Y este era un artículo realmente corto, además. Así que guardémoslos todos externamente y veamos cómo podemos distinguirlos.

Primero, creamos y abrimos un archivo CSV. Lo hacemos fuera de la función, justo al lado de las importaciones. Nuestra función es recursiva, lo que significa que tendremos MUCHOS archivos si crea un nuevo archivo cada vez que se llama.

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

A continuación, en nuestra función principal, escribimos la primera fila del archivo CSV justo antes de llamar a la función por primera vez. No olvides cerrar el archivo una vez finalizada la ejecución.

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

Ahora, escribimos su contenido. En nuestra función search_for_links, cuando encontramos una etiqueta <a>, en lugar de mostrarla en la consola, ahora hacemos lo siguiente:

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";
    }
}

Tomamos el valor del atributo href con este código y lo clasificamos en 3 categorías: artículos, citas y el resto.

Por supuesto, puedes ir mucho más allá y definir tus propios tipos de enlaces, como aquellos que parecen un artículo pero que en realidad son un archivo, por ejemplo.

Alternativas al web scraping

Ahora ya sabes cómo crear tu propio rastreador web con C++. Genial, ¿verdad?

Aun así, es posible que en algún momento te hayas dicho: «¡Esto empieza a dar más problemas de lo que vale la pena!», y lo entendemos perfectamente. A decir verdad, programar un scraper es una excelente experiencia de aprendizaje, y los programas son adecuados para pequeños conjuntos de datos, pero eso es todo.

Una API de web scraping es tu mejor opción si necesitas una herramienta de extracción de datos rápida, fiable y escalable. Esto se debe a que incluye todas las funcionalidades que necesitas, como un conjunto de proxies rotativos, renderización de Javascript, solucionadores de Captcha, opciones de geolocalización y muchas más.

¿No me crees? ¡Pues compruébalo tú mismo! ¡Empieza tu prueba gratuita de WebScrapingAPI y descubre lo accesible que puede ser el web scraping!

Acerca del autor
Raluca Penciuc, Desarrollador full-stack @ WebScrapingAPI
Raluca PenciucDesarrollador full-stack

Raluca Penciuc es desarrolladora full stack en WebScrapingAPI, donde se dedica a crear rastreadores, mejorar las técnicas de evasión y buscar formas fiables de reducir la detección en los sitios web de destino.

Empieza a crear

¿Estás listo para ampliar tu recopilación de datos?

Únete a más de 2000 empresas que utilizan WebScrapingAPI para extraer datos de la web a escala empresarial sin ningún gasto de infraestructura.