Парсинг на C++: мощь и скорость для сбора данных

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Парсинг на C++: когда скорость решает всё

В мире сбора данных Python давно стал мейнстримом. Requests, BeautifulSoup, Scrapy — эти инструменты знакомы каждому, кто хоть раз сталкивался с парсингом. Но что делать, если нужно обрабатывать тысячи страниц в секунду, а ресурсы сервера не резиновые? Или если проект требует максимальной производительности и минимального потребления памяти?

Тогда на сцену выходит парсинг на C++. Да, этот язык не так прост в освоении, как Python, но он даёт то, что не могут дать интерпретируемые языки — скорость на уровне железа и полный контроль над памятью. В этой статье мы разберём, как организовать скрапинг данных на C++, какие библиотеки использовать и почему иногда C++ оказывается лучшим выбором для парсинга.

Почему C++ для парсинга — это не безумие?

Многие считают, что C++ слишком сложен для такой задачи, как сбор данных с веб-страниц. Отчасти это правда: написать парсер на Python можно за 15 минут, а на C++ придётся потратить час. Но есть сценарии, где C++ незаменим:

  • High-load системы — когда нужно парсить миллионы страниц ежедневно.
  • Микросервисы на C++ — если весь бэкенд написан на C++, проще добавить парсер туда же.
  • Ограниченные ресурсы — встраиваемые системы, IoT, где каждый мегабайт на счету.
  • Требования к стабильности — C++ позволяет избежать проблем с утечками памяти при правильном подходе.

Ключевое преимущество скрапинга на C++ — скорость. Нативный код выполняется в разы быстрее Python, особенно при работе с регулярными выражениями и разборе больших HTML-документов.

Инструментарий для парсинга на C++

Для работы с HTTP-запросами и парсинга HTML/XML нам понадобятся проверенные библиотеки. Вот основной джентльменский набор для парсинга сайтов на C++:

1. libcurl — работа с HTTP

libcurl — это швейцарский нож для сетевых запросов. Он поддерживает HTTP/HTTPS, прокси, куки, таймауты и многое другое. Это стандарт де-факто для C++.

#include <curl/curl.h>
#include <string>

size_t writeCallback(void* contents, size_t size, size_t nmemb, std::string* output) {
    size_t totalSize = size * nmemb;
    output->append((char*)contents, totalSize);
    return totalSize;
}

std::string fetchPage(const std::string& url) {
    CURL* curl = curl_easy_init();
    std::string response;
    
    if (curl) {
        curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeCallback);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
        curl_easy_setopt(curl, CURLOPT_USERAGENT, "Mozilla/5.0");
        
        CURLcode res = curl_easy_perform(curl);
        if (res != CURLE_OK) {
            std::cerr << "curl error: " << curl_easy_strerror(res) << std::endl;
        }
        curl_easy_cleanup(curl);
    }
    return response;
}

2. Gumbo-parser — разбор HTML

Gumbo-parser от Google — это библиотека для парсинга HTML5, написанная на C. Она проста, быстра и не требует зависимостей. Отлично подходит для парсинга HTML на C++.

#include <gumbo.h>
#include <iostream>

void extractLinks(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 << "Found link: " << href->value << std::endl;
        }
    }
    
    const GumboVector& children = node->v.element.children;
    for (unsigned int i = 0; i < children.length; ++i) {
        extractLinks(static_cast<GumboNode*>(children.data[i]));
    }
}

void parseHTML(const std::string& html) {
    GumboOutput* output = gumbo_parse(html.c_str());
    extractLinks(output->root);
    gumbo_destroy_output(&kGumboDefaultOptions, output);
}

3. PugiXML — работа с XML и XPath

Если сайт отдаёт данные в XML или вы парсите RSS-ленты, PugiXML — лучший выбор. Он легковесный и поддерживает XPath.

#include <pugixml.hpp>

void parseXML(const std::string& xmlContent) {
    pugi::xml_document doc;
    if (!doc.load_string(xmlContent.c_str())) {
        std::cerr << "XML parse error" << std::endl;
        return;
    }
    
    // XPath запрос
    pugi::xpath_node_set titles = doc.select_nodes("//item/title");
    for (auto& node : titles) {
        std::cout << "Title: " << node.node().text().get() << std::endl;
    }
}

Практический пример: парсинг заголовков новостей

Давайте соберём всё вместе и напишем полноценный пример парсинга данных на C++. Допустим, мы хотим получить заголовки новостей с главной страницы Habr (или любого другого сайта).

#include <iostream>
#include <string>
#include <vector>
#include <curl/curl.h>
#include <gumbo.h>

// Callback для libcurl (такой же, как выше)
size_t writeCallback(void* contents, size_t size, size_t nmemb, std::string* output) {
    size_t totalSize = size * nmemb;
    output->append((char*)contents, totalSize);
    return totalSize;
}

// Рекурсивный поиск текста внутри тегов h2
void extractTitles(GumboNode* node, std::vector<std::string>& titles) {
    if (node->type != GUMBO_NODE_ELEMENT) {
        if (node->type == GUMBO_NODE_TEXT) {
            // Нам нужны только тексты внутри h2
        }
        return;
    }
    
    if (node->v.element.tag == GUMBO_TAG_H2) {
        // Извлекаем весь текст внутри h2
        GumboNode* textNode = static_cast<GumboNode*>(node->v.element.children.data[0]);
        if (textNode && textNode->type == GUMBO_NODE_TEXT) {
            titles.push_back(textNode->v.text.text);
        }
    }
    
    const GumboVector& children = node->v.element.children;
    for (unsigned int i = 0; i < children.length; ++i) {
        extractTitles(static_cast<GumboNode*>(children.data[i]), titles);
    }
}

int main() {
    std::string html                

Блоги

Рекомендаций по книгам