Поиск

Документация на метод "serp-yandex-search-and-context"

Асинхронный метод

SERP Яндекса: органика, контекстная реклама и колдунщики

Метод собирает выдачу Яндекса по списку запросов и возвращает вместе с органикой рекламные блоки — над выдачей, внутри выдачи и под выдачей, а также состав колдунщиков. Работает асинхронно: сначала ставится задача, затем опрашивается статус, после готовности забирается результат.

GET · POST /api/serp/yandex/searchAndContext/set?key={ключ-api} постановка задачи
GET · POST /api/serp/yandex/status?key={ключ-api}&task_id={id} прогресс
GET · POST /api/serp/yandex/get?key={ключ-api}&task_id={id} результат

Как это работает

  • 1 Ставим задачу — передаём список запросов и регион в searchAndContext/set. В ответ приходит task_id. Лимиты списываются в момент создания задачи.
  • 2 Ждём готовности — периодически (раз в 5–10 секунд) опрашиваем serp/yandex/status, пока progress не станет равным 100.
  • 3 Забираем результат — вызываем serp/yandex/get с тем же task_id. Большие выборки читаем постранично через limit и offset.
Ключ доступа к API создаётся в настройках аккаунта. API доступен пользователям платных тарифов; ключ передаётся в query-строке параметром key даже для POST-запросов.

1Постановка задачи

/api/serp/yandex/searchAndContext/set — принимает GET и POST.

Параметр Тип Обяз. По умолчанию Описание
keywords string | array да Список поисковых запросов. Строкой — по одному запросу на строку (разделитель \n), либо массивом при POST. Дубликаты и пустые строки отбрасываются автоматически. Максимум 15 000 запросов на задачу.
region int да Код региона Яндекса (lr), например 213 — Москва. Полный список поддерживаемых регионов отдаёт метод /api/serp/regions/get. Регион вне справочника — ошибка wrong region.
deep int нет 50 Глубина сбора — сколько результатов органической выдачи собирать по каждому запросу. На стоимость не влияет.
is_mobile 0 | 1 нет 0 Мобильная выдача вместо десктопной.
ads_only 0 | 1 нет 0 Собирать только рекламные блоки, без органической выдачи. Полезно для мониторинга конкурентов в Директе.

Ответ

{
  "task_id": 18452301
}

2Проверка статуса

/api/serp/yandex/status — общий для всех задач Яндекса метод проверки прогресса.

Параметр Тип Обяз. Описание
task_id int да Идентификатор задачи, полученный на шаге 1.

Ответ

{
  "progress": 64
}
progress — процент готовности от 0 до 100. Пока задача не появилась в очереди, метод отдаёт {"error": "session is not ready"} — это не фатальная ошибка, запрос нужно повторить.

3Получение результата

/api/serp/yandex/get — вызывается после того, как progress достиг 100.

Параметр Тип Обяз. По умолчанию Описание
task_id int да Идентификатор задачи.
limit int нет 60000 Сколько запросов вернуть за один вызов.
offset int нет 0 Смещение для постраничного чтения результата.

Структура ответа

Результат — набор объектов, по одному на каждый запрос задачи. Ключевые поля:

Поле Тип Описание
query string Поисковый запрос.
query_id string Порядковый номер запроса в задаче.
region int Регион сбора (lr).
is_mobile 0 | 1 Тип выдачи: мобильная или десктопная.
organic array Органическая выдача: position, url, domain, title, snippet, visible_link.
ads_top array Рекламные объявления над органической выдачей (премиум-показы).
ads_middle array Рекламные объявления внутри выдачи.
ads_bottom array Рекламные объявления под органической выдачей (гарантированные показы).
koldunshiki object Наличие колдунщиков в выдаче, флаги true/false: entity_card — карточка организации, alice_answer — ответ Алисы, facts — факты, see_also — «смотрите также», map — Яндекс.Карты справа, companies — организации, currency_converter — конвертер валют.

Пример результата

[
  {
    "query": "купить смартфон",
    "query_id": "0",
    "region": 213,
    "is_mobile": 0,
    "source": "yandex",
    "organic": [
      {
        "position": 1,
        "url": "https://www.example-shop.ru/smartfony/",
        "domain": "example-shop.ru",
        "title": "Смартфоны — купить в интернет-магазине",
        "snippet": "Более 2000 моделей смартфонов с доставкой...",
        "visible_link": "example-shop.ru › smartfony"
      }
    ],
    "ads_top": [
      {
        "position": 1,
        "url": "https://ads.example.ru/phones/",
        "domain": "ads.example.ru",
        "title": "Смартфоны со скидкой до 30%",
        "snippet": "Рассрочка 0%. Доставка за 2 часа."
      }
    ],
    "ads_middle": [],
    "ads_bottom": [
      {
        "position": 1,
        "url": "https://shop2.example.ru/",
        "domain": "shop2.example.ru",
        "title": "Смартфоны в наличии",
        "snippet": "Официальная гарантия 2 года."
      }
    ],
    "koldunshiki": {
      "entity_card": false,
      "alice_answer": false,
      "facts": false,
      "see_also": true,
      "map": false,
      "companies": true,
      "currency_converter": false
    }
  }
]

Тарификация

2 лимита × количество уникальных запросов Списание происходит один раз — при успешной постановке задачи. Проверка статуса и получение результата бесплатны, повторные вызовы get лимиты не расходуют.

Например, задача на 500 запросов спишет 1000 лимитов независимо от значений deep, is_mobile и ads_only. Если доступных лимитов не хватает, задача не создаётся, а в ответе приходит код ошибки и точные значения available / need.

Сбор рекламных блоков стоит вдвое дороже, чем сбор только органики методом /api/serp/yandex/set (1 лимит за запрос). Если реклама и колдунщики не нужны — используйте его.

Коды ошибок

Код Текст Причина
-1 Access denied Параметр key не передан.
-2 Access denied Ключ не найден или недействителен.
-50 empty keywords Список запросов пуст после очистки.
-50 too much keywords, current limit 15000 Больше 15 000 запросов в одной задаче.
-50 wrong region Регион отсутствует в справочнике /api/serp/regions/get.
-55 empty task_id task_id не передан или не является числом.
-75 server error Задачу не удалось поставить в очередь — повторите запрос.
-80 Not enough hourly limits Исчерпан часовой лимит. В ответе — available и need.
-68 Not enough daily limits Исчерпан суточный лимит.
-81 Not enough weekly limits Исчерпан недельный лимит.
-82 Not enough monthly limits Исчерпан месячный лимит.
-83 Not enough yearly limits Исчерпан годовой лимит.

Пример ответа при нехватке лимитов

{
  "error": "Not enough daily limits",
  "code": "-68",
  "available": 340,
  "need": 1000
}

Примеры

cURL

curl -X POST 'https://tools.pixelplus.ru/api/serp/yandex/searchAndContext/set?key={ключ-api}' \
  --data-urlencode 'keywords=купить смартфон
купить ноутбук' \
  -d 'region=213' \
  -d 'deep=50' \
  -d 'is_mobile=0'

PHP

<?php

$key = '{ключ-api}';
$base = 'https://tools.pixelplus.ru/api';

function apiPost(string $url, array $data = []): array
{
    $curl = curl_init();
    curl_setopt_array($curl, [
        CURLOPT_URL => $url,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_POST => true,
        CURLOPT_POSTFIELDS => http_build_query($data),
        CURLOPT_TIMEOUT => 120,
    ]);
    $response = curl_exec($curl);
    curl_close($curl);

    return json_decode($response, true) ?: [];
}

// 1. Ставим задачу
$task = apiPost("{$base}/serp/yandex/searchAndContext/set?key={$key}", [
    'keywords'  => implode("\n", ['купить смартфон', 'купить ноутбук']),
    'region'    => 213,
    'deep'      => 50,
    'is_mobile' => 0,
]);

if (empty($task['task_id'])) {
    exit('Ошибка: ' . ($task['error'] ?? 'unknown'));
}

$taskId = $task['task_id'];

// 2. Ждём готовности
do {
    sleep(10);
    $status = apiPost("{$base}/serp/yandex/status?key={$key}", ['task_id' => $taskId]);
    $progress = (int)($status['progress'] ?? 0);
} while ($progress < 100);

// 3. Забираем результат
$result = apiPost("{$base}/serp/yandex/get?key={$key}", [
    'task_id' => $taskId,
    'limit'   => 60000,
    'offset'  => 0,
]);

print_r($result);

Python

import time
import requests

KEY = '{ключ-api}'
BASE = 'https://tools.pixelplus.ru/api'

task = requests.post(
    f'{BASE}/serp/yandex/searchAndContext/set',
    params={'key': KEY},
    data={
        'keywords': '\n'.join(['купить смартфон', 'купить ноутбук']),
        'region': 213,
        'deep': 50,
        'is_mobile': 0,
    },
).json()

task_id = task['task_id']

while True:
    status = requests.post(
        f'{BASE}/serp/yandex/status',
        params={'key': KEY}, data={'task_id': task_id},
    ).json()
    if status.get('progress', 0) >= 100:
        break
    time.sleep(10)

result = requests.post(
    f'{BASE}/serp/yandex/get',
    params={'key': KEY},
    data={'task_id': task_id, 'limit': 60000, 'offset': 0},
).json()

print(result)

Ограничения и рекомендации

  • Не более 15 000 запросов в одной задаче; при большем объёме разбивайте список на несколько задач.
  • Запросы внутри задачи дедуплицируются — платить дважды за один и тот же запрос не придётся.
  • Опрашивайте статус не чаще одного раза в 5 секунд: задача с тысячами запросов выполняется минутами.
  • Результат читается постранично: при больших задачах увеличивайте offset с шагом limit, пока не получите пустую выборку.
  • Реклама в Яндексе ротируется, поэтому состав ads_top / ads_bottom отражает выдачу на момент сбора, а не «средний» набор объявлений.
  • Регион задаётся кодом lr — коды, которых нет в справочнике /api/serp/regions/get, отклоняются.