Прочитать одну веб-страницу и написать краткое резюме несложно. Делать то же самое для нескольких сотен страниц каждое утро, совсем другая задача, и именно для такой работы хорошо подходит языковая модель. Сложность никогда не была в самом суммировании. Трудность, получить чистый читаемый текст со страниц, которые этому противятся, а затем подавать модели больше текста, чем вмещает её контекстное окно, не теряя нить.

Это руководство рассматривает обе части от начала до конца. Вы будете собирать страницы с помощью Crawlbase Crawling API в виде чистого markdown, затем суммировать их с помощью LLM, а когда страница слишком длинна для одного вызова, нарезать её на части и применять map-reduce суммирование, чтобы ничего не выпало. Всё здесь, это исполняемый Python, ориентированный на публичный веб-контент. В итоге у вас будет небольшой пайплайн, превращающий список URL в короткие, последовательные резюме, которые можно хранить, искать или включать в отчёт. Это и есть суть того, как суммировать веб-данные с помощью Crawlbase и AI.

Зачем суммировать веб-данные с помощью Crawlbase и AI

Просмотр одной страницы показывает, что говорит один документ прямо сейчас. Ценность появляется при масштабировании: отслеживать, что говорит набор страниц конкурентов с течением времени, сжимать поток статей в ежедневный дайджест или превращать страницы товаров и отзывов в несколько строк, которые человек действительно прочитает. LLM работает быстро и последовательно, применяя одни и те же критерии к каждому документу без усталости к двухсотой странице.

Однако модель хороша ровно настолько, насколько хорош передаваемый ей текст, и именно здесь большинство проектов «AI-суммаризатора» незаметно ломаются. Современные страницы насыщены JavaScript, завёрнуты в навигацию, рекламу, баннеры cookies и шаблонные блоки, и многие из них прямо блокируют автоматизированный трафик. Передайте сырой HTML в модель, и вы потратите токены на суммирование разметки и меню вместо контента. Решение, разделить сбор и суммирование: пусть Crawlbase занимается рендерингом, разблокировкой и чистым извлечением, а модель делает то, что умеет. Подробнее об этом шаге извлечения, в статье как работает AI-извлечение данных.

Как пайплайн складывается воедино

Есть два этапа, и их разделение делает всё поддерживаемым.

  • Сбор. Crawling API загружает каждый URL за надёжным IP, при необходимости рендерит JavaScript и возвращает чистый markdown вместо сырого HTML. Это означает, что суммируемый текст уже очищен от навигации, скриптов и стилей.
  • Суммирование. LLM читает markdown и возвращает краткое резюме. Для страниц, умещающихся в контекстное окно модели, это один вызов. Для длинных страниц вы разбиваете текст на части, суммируете каждую, затем суммируете резюме. Последний паттерн, map-reduce.

Запрос к Crawlbase на markdown, а не на HTML, важнее, чем кажется. Markdown сохраняет заголовки, списки и структуру, убирая шум, поэтому модель тратит своё контекстное окно на смысл. Подробнее об этом выборе, в статье LLM-готовый markdown-скрапинг.

Markdown вместо сырого HTML

Crawling API может вернуть страницу как markdown, если передать format=markdown (или соответствующий параметр scraper). Всегда предпочитайте это сырому HTML для суммирования. Сырой HTML сжигает токены на тегах и инлайн-стилях, которые модели не нужны, а лишний шум ощутимо ухудшает качество резюме. Markdown сохраняет структуру, полезную модели, и убирает всё остальное.

Настройка проекта

Вам нужен Python 3 и два аккаунта: бесплатный аккаунт Crawlbase для токена и аккаунт OpenAI для модели. Сначала создайте аккаунт Crawlbase; вы получаете до 20 000 бесплатных API-запросов: 1 000 при регистрации и больше по мере прохождения шагов онбординга, этого достаточно, чтобы следовать руководству. Скопируйте Normal request token со страницы документации аккаунта и получите API-ключ OpenAI.

Затем создайте папку проекта и установите библиотеки.

bash
python --version

mkdir web-summarizer && cd web-summarizer
python -m venv .venv && source .venv/bin/activate
pip install requests openai tiktoken

Три зависимости выполняют работу: requests вызывает Crawling API, openai, клиент для модели, а tiktoken считает токены, чтобы знать, когда страница слишком велика для одного вызова. Задайте два секрета как переменные окружения, чтобы они не попали в код.

bash
export CRAWLBASE_TOKEN="your_crawlbase_normal_token"
export OPENAI_API_KEY="your_openai_api_key"

Шаг 1: получение страницы как чистого markdown

Начните со сбора. Вы отправляете Crawling API целевой URL и параметр format=markdown, и он возвращает страницу, уже преобразованную в markdown. Функция ниже оборачивает этот вызов, проверяет статус вышестоящего сервера и возвращает только тело markdown, чтобы остальная часть пайплайна никогда не видела сырой HTML.

python
import os
import requests

CRAWLBASE_TOKEN = os.environ["CRAWLBASE_TOKEN"]
API_ENDPOINT = "https://api.crawlbase.com/"

def fetch_markdown(url: str) -> str:
    params = {
        "token": CRAWLBASE_TOKEN,
        "url": url,
        "format": "markdown",
    }
    response = requests.get(API_ENDPOINT, params=params, timeout=90)
    response.raise_for_status()
    return response.text

if __name__ == "__main__":
    markdown = fetch_markdown("https://www.crawlbase.com/blog/")
    print(markdown[:800])

Запустите, и вы получите текст статьи в виде markdown с сохранёнными заголовками и списками, при этом обёртка страницы уже убрана. Если цель рендерит контент с помощью JavaScript, тот же вызов работает с JavaScript-токеном вместо Normal, так что страница рендерится в реальном браузере перед конвертацией. Смените токен, и вы суммируете контент одностраничных приложений без каких-либо других изменений в коде.

Crawlbase Crawling API

Чистый текст на входе, хорошие резюме на выходе. Crawling API рендерит JavaScript, ротирует резидентные IP для обхода блокировок и возвращает каждую страницу в виде готового к суммированию markdown в одном вызове, так что модель никогда не видит навигационные панели или cookie-баннеры. Начните с бесплатного уровня и направьте его на любой публичный URL.

Шаг 2: суммирование короткой страницы в одном вызове

Когда страница комфортно умещается в контекстное окно модели, суммирование, это один запрос. Функция ниже принимает текст в markdown и краткую инструкцию, отправляет их в модель с низкой температурой для последовательности и возвращает строку с резюме. Низкая температура важна: вы хотите, чтобы один и тот же ввод давал стабильный вывод в разных запусках, а не творческое разнообразие.

python
from openai import OpenAI

client = OpenAI()  # reads OPENAI_API_KEY from the environment
MODEL = "gpt-4o-mini"

def summarize(text: str, instruction: str) -> str:
    prompt = f"{instruction}\n\n---\n\n{text}"
    response = client.chat.completions.create(
        model=MODEL,
        messages=[{"role": "user", "content": prompt}],
        temperature=0.2,
    )
    return response.choices[0].message.content.strip()

SUMMARY_PROMPT = (
    "Summarize the following web page in 4-6 sentences. "
    "Lead with the main point, then the key supporting facts. "
    "Ignore navigation, ads, and boilerplate."
)

if __name__ == "__main__":
    page = fetch_markdown("https://www.crawlbase.com/blog/")
    print(summarize(page, SUMMARY_PROMPT))

Это весь счастливый путь для обычной статьи. Получить markdown, отправить с инструкцией, вывести результат. Модель занимается языковой работой; Crawlbase занимался работой с данными. Единственное, что стоит между этим и страницей, которая не влезает, длина, что и является следующим шагом.

Шаг 3: обработка длинных страниц через нарезку на части

У каждой модели есть контекстное окно, жёсткое ограничение на объём текста, который она может прочитать за один вызов. Объёмные статьи, страницы документации и ветки форумов могут его превысить, и тогда API отклоняет запрос. Решение, разбить текст на части, каждая из которых умещается в окно, с небольшим перекрытием, чтобы предложение, разрезанное на границе, всё равно целиком присутствовало в одной из частей.

Для подсчёта токенов, а не символов, используйте tiktoken, поскольку ограничение измеряется в токенах. Функция ниже перебирает список токенов и нарезает его на окна фиксированного размера.

python
import tiktoken

encoder = tiktoken.encoding_for_model("gpt-4o-mini")

def chunk_text(text: str, max_tokens: int = 2000, overlap: int = 150):
    tokens = encoder.encode(text)
    chunks = []
    start = 0
    while start < len(tokens):
        end = start + max_tokens
        window = tokens[start:end]
        chunks.append(encoder.decode(window))
        start = end - overlap
    return chunks

Каждая часть теперь является самодостаточным фрагментом текста, достаточно малым для самостоятельного суммирования. Значение max_tokens в 2 000 оставляет комфортный запас для промта и ответа внутри современного контекстного окна; уменьшите его для меньших моделей. Перекрытие не даёт потерять граничное предложение между двумя частями. При чистом markdown от Crawlbase на входе эти части содержат только контент, что снижает их количество и удерживает резюме по теме.

Шаг 4: объединение резюме частей через map-reduce

Нарезка даёт несколько частей; map-reduce превращает их обратно в один ответ. Паттерн состоит из двух фаз. В фазе map вы суммируете каждую часть независимо, получая список частичных резюме. В фазе reduce вы конкатенируете эти частичные резюме и суммируете их вместе в одно финальное. Если объединённые частичные резюме сами слишком длинны, вы снова редуцируете, повторяя до получения одного резюме.

python
MAP_PROMPT = (
    "Summarize this section of a longer document in 3-4 sentences. "
    "Keep concrete facts, names, and numbers."
)

REDUCE_PROMPT = (
    "The following are summaries of consecutive sections of one document. "
    "Combine them into a single coherent summary of 5-7 sentences, "
    "removing repetition and keeping the overall narrative."
)

def summarize_long(text: str) -> str:
    chunks = chunk_text(text)

    if len(chunks) == 1:
        return summarize(chunks[0], SUMMARY_PROMPT)

    partials = [summarize(c, MAP_PROMPT) for c in chunks]
    combined = "\n\n".join(partials)

    while len(encoder.encode(combined)) > 2000:
        partials = [summarize(c, MAP_PROMPT) for c in chunk_text(combined)]
        combined = "\n\n".join(partials)

    return summarize(combined, REDUCE_PROMPT)

Теперь эта единственная функция обрабатывает любую длину. Короткая страница делает один вызов и возвращает результат немедленно. Длинная страница проходит map, reduce и, если нужно, reduce снова, при этом цикл гарантирует, что финальный ввод всегда умещается. Разные промты для map и reduce важны: промт map запрашивает насыщенные фактами частичные резюме, чтобы детали выжили в первом проходе, а промт reduce запрашивает чистый нарратив, чтобы финальное резюме читалось как единое целое, а не сшитый список.

Шаг 5: запуск пайплайна для многих URL

Два этапа теперь объединяются в небольшой пайплайн. Передайте ему список URL, получите каждый как markdown, суммируйте каждый с помощью функции с учётом длины и соберите результаты. Оберните каждый URL в try/except, чтобы одна плохая страница не потопила весь пакет, и у вас есть что-то, что можно направить на поток страниц.

python
import json

URLS = [
    "https://www.crawlbase.com/blog/",
    "https://www.crawlbase.com/blog/ai-data-extraction-how-it-works/",
]

def run_pipeline(urls):
    results = []
    for url in urls:
        try:
            markdown = fetch_markdown(url)
            summary = summarize_long(markdown)
            results.append({"url": url, "summary": summary})
        except Exception as error:
            print(f"Skipped {url}: {error}")
    return results

if __name__ == "__main__":
    output = run_pipeline(URLS)
    print(json.dumps(output, indent=2))

Вывод, JSON-массив пар url и summary, готовый для записи в файл, отправки в базу данных или рендеринга в дайджест. Сокращённый пример того, что возвращается:

json
[
  {
    "url": "https://www.crawlbase.com/blog/",
    "summary": "The Crawlbase blog covers web scraping, proxies, and data extraction, with hands-on tutorials for engineers. Recent posts focus on rendering JavaScript sites, avoiding blocks, and turning pages into clean structured data."
  },
  {
    "url": "https://www.crawlbase.com/blog/ai-data-extraction-how-it-works/",
    "summary": "The article explains how AI models extract structured fields from messy web pages, contrasting rule-based scrapers with model-driven extraction that adapts to layout changes."
  }
]

Практические советы для продакшена

Кешируйте полученный markdown

Сбор и суммирование дают сбои по разным причинам, поэтому не связывайте их. Сохраняйте markdown каждой страницы на диск с ключом по URL в момент получения. Когда вы захотите перезапустить с другим промтом или моделью, вы суммируете из кеша вместо повторного сбора, это быстрее и не тратит API-кредиты на уже имеющиеся страницы.

Регулируйте темп и повторяйте запросы

Оба API могут ограничивать тесный цикл. Добавьте небольшую паузу между URL и оберните вызов модели в повторную попытку с откатом, чтобы временная ошибка не потеряла страницу. Crawling API управляет ротацией IP и разблокировкой за вас, поэтому необходимый здесь темп невысок, но всё равно стоит быть вежливым клиентом.

Фиксируйте промты и модель

Переиспользуемые промты под контролем версий, это то, что делает резюме последовательными в разных запусках. Держите map и reduce промты в одном месте, фиксируйте имя модели и держите температуру низкой. Когда что-либо из этого меняется, воспринимайте это как изменение вашего вывода, потому что это так и есть.

Подбирайте инструмент под страницу

Используйте Normal token для статических страниц и JavaScript token для одностраничных приложений, рендерящих контент в браузере. Если вы хотите получать структурированные данные, цену, название, рейтинг, а не прозу, используйте Crawling API для получения структурированного JSON, а затем суммируйте его. Если вы встраиваете это в агента или рабочий процесс на основе MCP, Web MCP открывает те же возможности сбора и извлечения вашей модели как инструменты. Для полноценной агентной сборки статья создание AI-пайплайна данных с LangChain и Crawlbase развивает эту тему дальше.

Итоги

Ключевые выводы

  • Разделяйте сбор и суммирование. Crawlbase получает чистый текст; модель занимается языковой работой. Разделение двух этапов делает пайплайн поддерживаемым.
  • Получайте markdown, а не HTML. Передавайте format=markdown, чтобы модель тратила контекст на контент, а не на навигационные панели и скрипты.
  • Считайте токены, затем нарезайте. Используйте tiktoken для разбивки длинных страниц на перекрывающиеся части, каждая из которых умещается в контекстное окно.
  • Map-reduce масштабируется до любой длины. Суммируйте каждую часть, затем суммируйте резюме, снова редуцируя до получения одного.
  • Кешируйте и фиксируйте для продакшена. Сохраняйте полученный markdown, ведите версионирование промтов, фиксируйте модель и держите температуру низкой для стабильного вывода.

Часто задаваемые вопросы

Зачем получать markdown вместо сырого HTML для суммирования?

Сырой HTML полон тегов, скриптов, инлайн-стилей, навигации и рекламы, которые не несут смысла для резюме, но всё равно стоят токены. Crawling API может вернуть страницу как markdown, который сохраняет заголовки, списки и основной текст, убирая шум. Это означает, что модель тратит своё ограниченное контекстное окно на реальный контент, резюме получаются чище, и вы платите за меньше токенов на страницу.

Что такое map-reduce суммирование и когда оно нужно?

Map-reduce, это двухфазный паттерн для текста, слишком длинного для одного вызова модели. В фазе map вы суммируете каждую часть документа самостоятельно; в фазе reduce вы суммируете эти частичные резюме вместе в один финальный ответ. Он нужен всякий раз, когда страница превышает контекстное окно модели. Короткие страницы переходят прямо к единственному вызову, что и объясняет, почему в примере сначала проверяется количество частей.

Как выбрать размер части?

Задавайте размер части в токенах, а не в символах, и оставляйте запас для промта и ответа. Часть в 2 000 токенов хорошо работает на современных моделях с большими контекстными окнами; уменьшите для меньших моделей. Добавьте небольшое перекрытие, около 100–200 токенов, чтобы предложение, разрезанное на границе части, всё равно целиком присутствовало в одной из них. Считайте токены через tiktoken, используя ту же кодировку, что и ваша модель.

Можно ли суммировать JavaScript-рендеримые страницы?

Да. Замените Normal token на JavaScript token в вызове Crawling API. Он рендерит страницу в реальном браузере перед конвертацией в markdown, так что контент одностраничных приложений присутствует, когда модель его читает. Остальная часть пайплайна, нарезка и map-reduce, вообще не меняется.

Нужен ли платный аккаунт Crawlbase или OpenAI для следования этому руководству?

Нет. Crawlbase даёт вам до 20 000 бесплатных API-запросов: 1 000 при регистрации и больше по мере прохождения шагов онбординга, этого достаточно для тестирования пайплайна от начала до конца. Использование OpenAI тарифицируется по токенам, и небольшая модель вроде gpt-4o-mini делает суммирование дешёвым. Оба подходят для начала на бесплатных или недорогих уровнях перед масштабированием.

Можно ли использовать другую модель или провайдера?

Да. Пайплайн зависит от модели только в двух аспектах: вызов в стиле чата, принимающий промт и возвращающий текст, и счётчик токенов для нарезки. Замените клиент в функции summarize на любого предпочтительного провайдера и обновите кодировку tiktoken в соответствии с моделью. Этап сбора и логика map-reduce остаются ровно такими же.

Начать создавать

Обходите любой сайт в масштабе, без борьбы с инфраструктурой.

Crawlbase берёт на себя прокси, отпечатки и CAPTCHA, чтобы ваша команда выпускала конвейеры данных вместо поддержки обвязки краулинга. 1 000 запросов бесплатно, без карты.

Самообслуживание · Звонок отдела продаж не требуется · Доступны корпоративные объёмы краулинга