Перейти к содержимому

Smart Scrape: документ по URL с автоматическим выбором способа

POST /v1/browser/smart-scrape получает документ по URL самым дешёвым из доступных способов: из кэша, из сохранённой копии поисковой системы, прямым HTTP-запросом и только при необходимости — в headless Chromium. Ответ — JSON с содержимым, его видом (contentKind), Markdown, ссылками и SEO-данными. HTML, JSON, XML, текст, PDF и таблицы Excel читаются одним и тем же запросом.

Пакетный вариант в формате Tavily — POST /v1/tavily/extract, см. ниже.

Окно терминала
curl -X POST "https://proxy.seyka.ru/v1/browser/smart-scrape?timeout=30000" \
-H "Authorization: Bearer $SEYKA_API_KEY" \
-H "Content-Type: application/json" \
-d '{"url": "https://example.com", "formats": ["content", "markdown"]}'
Поле Тип По умолчанию Описание
url string — обязательный, HTTP(S)-адрес
formats string[] ["content"] что вернуть: content, markdown, links, seo, screenshot, pdf; html — синоним content

Query-параметр timeout — в миллисекундах, 1000–60000, по умолчанию 30000. Он действует отдельно на прямой HTTP-запрос и на попытку в браузере; попытка сохранённой копии ограничена двумя секундами. Шлюз ждёт ответа не дольше 75 секунд, поэтому медленный запрос с timeout около максимума, дошедший до браузера, может завершиться ошибкой 502.

Форматы screenshot и pdf сразу запускают браузер; если запрошены оба, они снимаются с одной загрузки страницы. Неизвестные поля тела (например, proxy из Browserless) игнорируются.

  1. Кэш документов — общий для Smart Scrape и Cheerio, документ живёт в нём 12 часов.
  2. Сохранённая копия из кэша поисковой системы — только для HTML и только если URL не оканчивается явным расширением «сырого» файла (.json, .xml, .pdf и т. п.).
  3. Прямой HTTP-запрос к источнику.
  4. Headless Chromium — для страниц, которые строятся JavaScript, и для некачественных HTTP-ответов (пустая или слишком короткая страница, оболочка без содержимого).

В ответе strategy — сработавшая ступень: cache, yandex-cache (сохранённая копия), http-fetch или browser; attempted — все сделанные попытки по порядку.

В браузер запрос переходит не всегда:

  • «сырой» документ — JSON, XML, текст, PDF, таблица — получается только прямым запросом. Ответ 2xx сразу возвращается, а ошибка или не-2xx на «сыром» URL завершают каскад: Chromium не прочитает исходник лучше, а PDF и таблицы вообще скачивает, а не открывает;
  • HTML-ответ 2xx идёт обычным путём, даже если URL выглядит как «сырой» файл;
  • ответ 2xx с распознанным, но неподдерживаемым типом (image/png, application/msword) завершается без браузера; исключение — application/octet-stream, потому что источник может отдать браузеру другое;
  • слишком большой ответ тоже завершается без браузера — рендер не сделает документ меньше.

contentKind говорит, как читать content. Он описывает сам ресурс и возвращается всегда, когда документ получен, даже если формат content не запрошен. Ветвитесь по нему, а не по contentType.

contentKind MIME-типы Что лежит в content
html text/html, application/xhtml+xml очищенный HTML: удалены скрипты, стили, iframe, обработчики событий, ссылки javascript: и data:
json application/json, text/json, application/*+json исходный текст как есть, без очистки
xml application/xml, text/xml, image/svg+xml, application/*+xml исходный текст как есть, без очистки
text text/plain, text/markdown, text/csv, text/css, text/javascript, application/robots+txt и другие text/* исходный текст как есть, без очистки
pdf application/pdf извлечённый текстовый слой, не байты файла
spreadsheet Excel (.xls, .xlsx, .xlsm, .xlsb), OpenDocument (.ods) и их шаблоны CSV; несколько листов разделяются строками === Sheet: имя ===

Вид определяется по Content-Type ответа — он всегда важнее расширения в URL. Расширение конечного URL (после редиректов) учитывается, только если заголовка нет или он не говорит о формате (application/octet-stream); если заголовка нет и расширение ничего не подсказывает, документ считается HTML. text/event-stream и нераспознанные типы — изображения, .doc, бинарные файлы без подсказки — документом не считаются.

{
"ok": true,
"statusCode": 200,
"content": "<html><head><title>Example Domain</title></head><body>…</body></html>",
"contentKind": "html",
"contentType": "text/html; charset=utf-8",
"headers": { "content-type": "text/html; charset=utf-8" },
"redirects": [],
"strategy": "http-fetch",
"attempted": ["cache", "http-fetch"],
"message": null,
"screenshot": null,
"pdf": null,
"markdown": "# Example Domain\n\nThis domain is for use in illustrative examples…",
"links": null,
"seo": null
}
Поле Описание
ok получен ли документ
statusCode, contentType, headers код, тип и безопасные заголовки ответа источника; Set-Cookie, авторизационные и подобные заголовки не передаются
redirects цепочка редиректов: from, to, statusCode
content, contentKind документ и его вид; content — null, если формат content не запрошен
markdown Markdown документа (см. ниже)
links, seo ссылки и SEO-данные — только для HTML, для остальных видов null
screenshot, pdf PNG и PDF страницы в base64, если запрошены
strategy, attempted сработавшая ступень и все попытки
message диагностика, если ok: false

Конечный адрес документа приходит в заголовке X-Response-URL.

markdown строится по виду: для HTML — из очищенной страницы; для text — сам исходник; для xml — таблица sitemap или список записей RSS/Atom, иначе блок кода; для json — исходник в блоке кода; для pdf — извлечённый текст; для spreadsheet — таблица по каждому листу, не больше 100 строк на лист с пометкой об остальных (content при этом не усекается).

Тело декодируется по объявленной кодировке — BOM, charset заголовка, <meta charset> или объявление XML, иначе UTF-8, — поэтому сайты в windows-1251 читаются одинаково на всех ступенях.

Если ни одна ступень не дала документ, HTTP-статус всё равно 200: в теле ok: false, message с причиной и content, contentKind равны null, а statusCode, contentType, заголовки и редиректы описывают последнюю попытку. Проверяйте ok, а не только код ответа. В смешанном запросе вроде ["content", "screenshot"] скриншот при этом остаётся в ответе.

Ошибки самого запроса — неверный URL, адрес во внутренней сети, неизвестный формат, timeout вне диапазона — возвращают 400 до начала работы.

Ситуация content contentKind
документ получен, content запрошен строка вид документа
документ получен, content не запрошен null вид документа
запрошены только screenshot и/или pdf null null
каскад исчерпан, не-2xx, неподдерживаемый тип null null
  • Текстовый документ — до 4 МиБ, PDF и таблица — до 10 МиБ; крупнее — ok: false.
  • Текст, извлечённый из PDF или таблицы, — не больше 1,5 МБ.
  • Скан PDF без текстового слоя — ok: false с message: "PDF has no text layer".
  • PDF и таблицы извлекаются только прямым HTTP-запросом: если он не прошёл, браузер не поможет.

Заголовок Cache-Control: no-cache пропускает кэш ответов шлюза, кэш документов и сохранённую копию и идёт сразу к источнику; ответ приходит с X-Cache: BYPASS, а свежий результат обновляет кэши. Учтите, что без дешёвых ступеней запрос чаще доходит до браузера.

Окно терминала
curl -s -D - -X POST "https://proxy.seyka.ru/v1/browser/smart-scrape" \
-H "Authorization: Bearer $SEYKA_API_KEY" \
-H "Content-Type: application/json" \
-H "Cache-Control: no-cache" \
-d '{"url": "https://example.com", "formats": ["content"]}'
# x-cache: BYPASS; в теле strategy — "http-fetch" или "browser"

Форматы seo и links работают для HTML-документов:

Окно терминала
curl -s -X POST "https://proxy.seyka.ru/v1/browser/smart-scrape" \
-H "Authorization: Bearer $SEYKA_API_KEY" \
-H "Content-Type: application/json" \
-d '{"url": "https://example.com", "formats": ["seo", "links"]}'
{
"links": ["https://www.iana.org/domains/example"],
"seo": {
"title": "Example Domain",
"metadata": { "viewport": "width=device-width, initial-scale=1" },
"canonical": null,
"language": null,
"headings": [{ "level": 1, "text": "Example Domain" }],
"links": [{ "url": "https://www.iana.org/domains/example", "text": "More information..." }],
"images": [],
"jsonLd": [],
"diagnostics": []
}
}

seo содержит title, мета-теги (metadata), canonical, language, заголовки h1–h6, ссылки (url, text, rel), изображения (src, alt, title), разобранные блоки JSON-LD и diagnostics — замечания с полями code и message.

Визуальные форматы идут сразу в браузер. PNG приходит в поле screenshot в base64:

Окно терминала
curl -s -X POST "https://proxy.seyka.ru/v1/browser/smart-scrape" \
-H "Authorization: Bearer $SEYKA_API_KEY" \
-H "Content-Type: application/json" \
-d '{"url": "https://example.com", "formats": ["screenshot"]}' \
| jq -r '.screenshot // empty' | base64 -d > page.png

Здесь contentKind равен null: документ не запрашивался. Запрос ["screenshot", "markdown"] вернёт и скриншот, и contentKind.

Запрос ничем не отличается от обычного — вид придёт в contentKind:

Окно терминала
curl -s -X POST "https://proxy.seyka.ru/v1/browser/smart-scrape" \
-H "Authorization: Bearer $SEYKA_API_KEY" \
-H "Content-Type: application/json" \
-d '{"url": "https://example.com/stats.xlsx", "formats": ["content", "markdown"]}'
# contentKind: "spreadsheet"; content — CSV, markdown — таблицы по листам

Smart Scrape оплачивается по ступени, на которой получен документ, и тарифицируется по двум позициям таблицы цен:

  • дешёвая ступень — кэш документов, сохранённая копия или прямой HTTP-запрос, без запуска браузера;
  • рендер в браузере — любая попытка Chromium, включая неудачную, а также все запросы с screenshot или pdf. Если все браузеры были заняты и рендер так и не начался, вызов не оплачивается.

Баланс перед вызовом проверяется по цене рендера в браузере, а списывается фактическая ступень.

Поверх каскада работает кэш ответов шлюза. Повтор запроса с тем же URL и тем же набором форматов в пределах окна кэша возвращается с X-Cache: HIT, strategy: "cache" и оплачивается по цене повтора из кэша, без обращения к браузеру. URL сравнивается в канонической форме; порядок и повторы форматов, html вместо content и timeout на совпадение не влияют. Не кэшируются ответы с ok: false, с screenshot или pdf (X-Cache: UNCACHEABLE), ответы, которые источник пометил no-store, и слишком большие ответы.

POST /v1/tavily/extract — пакетное извлечение в формате Tavily Extract: до 20 URL за запрос через тот же каскад. Существующий клиент Tavily достаточно направить на https://proxy.seyka.ru — путь POST /extract у базового адреса работает как синоним. Поиск в формате Tavily описан в разделе Tavily.

Окно терминала
curl -X POST "https://proxy.seyka.ru/v1/tavily/extract" \
-H "Authorization: Bearer $SEYKA_API_KEY" \
-H "Content-Type: application/json" \
-d '{"urls": ["https://example.com", "http://10.0.0.1/"], "timeout": 30}'
Поле Тип Описание
urls string или string[] обязательный, один адрес или до 20
timeout number секунды, 1–60, по умолчанию 30 — на весь запрос, включая ожидание свободного браузера
extract_depth, format string принимаются для совместимости и ни на что не влияют
{
"results": [
{ "url": "https://example.com", "raw_content": "# Example Domain\n\nThis domain is for use in…" }
],
"failed_results": [
{ "url": "http://10.0.0.1/", "error": "Access to private IPs not allowed" }
],
"response_time": 1.84
}
  • raw_content — всегда Markdown документа, независимо от format; в сумме не больше 16 МиБ на ответ. Документы сверх лимита попадают в failed_results с просьбой запросить меньше URL, но оплачиваются по своей ступени — работа уже сделана.
  • failed_results — адреса, которые не удалось получить, с причиной; response_time — в секундах.
  • Пустой urls — 400; больше 20 адресов — 413. Если сервис перегружен пакетами, ответ 503 с заголовком Retry-After.
  • Ответы не кэшируются шлюзом и не несут X-Cache, но каскад, включая кэш документов, работает как обычно.

Каждый уникальный URL оплачивается по ступени, на которой он получен: дешёвая ступень или рендер в браузере, включая исчерпанный каскад. Отклонённые адреса, ошибки сервиса и занятый пул браузеров не оплачиваются. Итог приходит в заголовках:

  • X-Cost-Cents — списанная сумма в копейках;
  • X-Extract-Tiers — сколько URL прошло по каждой ступени, например cheap=3,browser=2.

Перед вызовом баланс проверяется по цене рендера в браузере за каждый уникальный URL.

https://production-sfo.browserless.io/smart-scrape
https://proxy.seyka.ru/v1/browser/smart-scrape

Запросы Browserless Smart Scrape работают без изменений: formats: ["html"] принимается как content, поле proxy игнорируется. Отличия ответа:

  • обязательное поле contentKind — ветвитесь по нему; content для HTML приходит очищенным, а не сырым;
  • неудача — 200 с ok: false и данными последней попытки, а не код ошибки;
  • добавлены формат seo, каскад с общим кэшем документов и сохранённой копией и двухступенчатая тарификация.

Остальные эндпоинты Browserless — см. обзор Browser API.