Наша собственная статистика посещений включена всегда. Google Analytics помогает нам понять, как пользуются нашими публичными страницами (но не вашим рабочим пространством после входа), и включается только с вашего разрешения. См. нашу политику конфиденциальности.

Пакетный сбор комментариев Xiaohongshu: от списка заметок к проверяемым результатам

Пошаговая интеграция comments_batch для Xiaohongshu: подготовка полных URL заметок, различение числа URL и числа комментариев, выявление результатов с флагами partial и missed, дедупликация по заметкам, а также обработка пустых результатов, повторных попыток и списаний за каждую цель.

При исследовании комментариев в Xiaohongshu первым шагом часто оказывается не анализ тональности, а наведение порядка в URL заметок. Несколько участников присылают списки с повторяющимися заметками, со временем часть ссылок перестаёт работать, а пакетный запрос возвращает 200, хотя в результатах есть только часть заметок. Если не решить эти проблемы сначала, последующие «частые проблемы» и «доля негатива» могут оказаться просто другим отражением пробелов в сборе.

Эндпоинт xiaohongshu.comments_batch в EveryInfra принимает массив URL заметок, позволяя отправить несколько целей за раз. Это руководство начинается с одной заметки и подробно показывает, как перейти к пакетному процессу с журналированием и проверяемыми результатами: подготовить цели, проверить параметры, отправить запросы, сгруппировать комментарии по заметкам и определить, для каких целей можно повторить запрос.

Ограничения на входные данные и порядок обработки ответов в этом руководстве сверены с публичным каталогом и исходным кодом по состоянию на 2026-09-04. Бизнес-запросы приведены как шаблоны, которые можно адаптировать, а офлайн-примеры явно помечены как синтетические и не выдаются за реальные комментарии в рамках этой работы. Перед вызовом убедитесь, что ваши цели, предполагаемое использование данных и параметры их хранения согласованы.

Выбор подходящей возможности: поиск заметок, сбор комментариев и сбор ответов — это разные задачи

Эндпоинт search находит заметки по ключевым словам, note читает данные конкретной заметки, comments работает с одной заметкой, а comments_batch — с несколькими. Если нужны вложенные ответы на конкретный комментарий, в каталоге есть sub_comments, которому также нужен comment_id на входе. Эти интерфейсы нельзя заменить друг другом, просто поменяв имя параметра.

Сначала определите объект исследования. Например, для анализа обратной связи пользователей в конкретном наборе заметок о товаре нужен список заметок. Получение всех комментариев с упоминанием бренда требует учитывать охват поиска заметок, пропуски при получении данных, полноту сбора комментариев и временные окна; одна лишь возможность пакетного сбора комментариев не гарантирует полного охвата.

Это также нужно отличать от официальной интеграции с аккаунтами. Официальный справочник API Xiaohongshu описывает эндпоинты для авторизации, токенов и информации о пользователе; если вам нужен вход пользователя или чтение профилей авторизованных аккаунтов, начните с соответствующего официального процесса. Запрос EveryInfra в этой статье не является официальным API аккаунтов, и официальные ссылки не доказывают, что чтение комментариев одобрено платформой.

Шаг 1. Проверьте входные данные, режимы и поля в каталоге

Читайте только актуальное описание comments_batch
curl -fsS --max-time 30 \
  'https://api.everyinfra.com/api/v1/social/catalog?platform=xiaohongshu' \
  | jq -e '.capabilities[] | select(.action == "comments_batch") | {
      action, required_params, optional_params, param_meanings,
      mode, available, default_limit, max_limit, response_fields
    }'

В этой версии каталога обязательный параметр — urls, режим — sync, значение count по умолчанию — 30, а max_limit — 200; массивы целей тарифицируются за каждую цель. Обратите внимание, что здесь две разные величины: длина urls означает число заметок, а count в результате — число доставленных записей. Если считать, что 200 означает возможность «отправить 200 заметок за один раз», ошибка возникнет уже на первом шаге проектирования запроса.

В текущем исходном коде для comments_batch есть явные проверки входных данных: urls должен быть непустым списком не более чем из 20 элементов, из каждого элемента должен успешно извлекаться идентификатор заметки, и каждый элемент должен содержать непустой параметр xsec_token. Превышение лимита целей или отсутствие нужных данных в ссылке приводит к ошибке параметров. Число 20 взято из этой проверки в реализации, а не вычислено из max_limit.

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

Шаг 2. Храните ссылки для запросов и идентификаторы заметок отдельно

Для запросов используйте полные URL заметок, полученные по согласованным каналам. Не удаляйте параметры запроса перед отправкой ради «чистых» URL, не угадывайте и не подделывайте параметры доступа и не переносите параметры с одной цели на другую. Короткие ссылки и текст, скопированный через «Поделиться», сначала нужно привести к ссылкам на заметки, которые принимает эта возможность; не рассчитывайте, что интерфейс сам разберёт произвольный текст.

При этом дедупликация не должна опираться только на сравнение полных строк URL. Ссылки на одну заметку могут содержать разные параметры запроса, и дедупликация по строкам оставит несколько одинаковых целей. Разделяйте ключ идентичности и текущую рабочую ссылку: ключ состоит из платформы и ID заметки, а ссылка хранится в исходном виде вместе со временем получения.

  • Список целей: ключ идентичности заметки, полная ссылка для запроса, канал получения, время получения и причина, по которой заметка нужна для исследования.
  • Список дедупликации: какие входные данные указывают на одну заметку и какая подтверждённая ссылка в итоге выбрана; сохраняйте связи с источниками, а не просто удаляйте дубли.
  • Список на проверку: ссылки, которые не удаётся разобрать, ссылки без нужных параметров и ссылки на одну и ту же заметку с противоречивыми источниками. Разберитесь с ними в первую очередь, а не смешивайте их с платными пакетами.

Храните полные ссылки только во входных данных с контролем доступа или в хранилище задач. В логах, тикетах и экспортированных отчётах обычно достаточно ID заметок и обработанных ссылок на источник, а параметры доступа с ограниченным сроком действия не стоит копировать повсюду. Если нужно делиться читаемыми источниками, храните отдельные ссылки для публичного показа, не трогая реальные входные данные запросов.

Шаг 3. Сначала проверьте запрос и привязку комментариев на одной заметке

В примерах ниже используется формат пакетного действия, но в массиве только одна согласованная заметка, чтобы легко проверить, относятся ли комментарии именно к ней. Предполагается, что на сервере заданы EVERYINFRA_API_KEY и EVERYINFRA_XHS_NOTE_URL; во второй переменной должна быть реальная полная ссылка на заметку, а не заглушка, созданная для этой статьи.

Шаблон пакетного запроса с одной целью: отправьте ровно один раз
: "${EVERYINFRA_API_KEY:?set the API Key first}"
: "${EVERYINFRA_XHS_NOTE_URL:?set the authorized full note URL first}"
jq -cn --arg url "${EVERYINFRA_XHS_NOTE_URL}" '{
  platform: "xiaohongshu",
  action: "comments_batch",
  params: {urls: [$url], limit: 5}
}' | curl --silent --show-error --include --max-time 180 \
  'https://api.everyinfra.com/api/v1/social' \
  -H "Authorization: Bearer ${EVERYINFRA_API_KEY}" \
  -H 'Content-Type: application/json' \
  --data-binary @-

В этом примере URL сериализуются через jq, а не склеиваются в JSON вручную; limit: 5 нужен, чтобы проверить небольшое число записей, а тайм-аут клиента в 180 секунд тоже лишь пример настройки. Это не гарантирует, что вернутся пять записей, и тем более не означает, что у заметки всего пять комментариев. При первой проверке проверьте внешнюю структуру ответа, ID комментариев, note_id или note_url, значения null и форматы времени и только потом добавляйте другие цели.

Шаг 4. При разбиении целей на пакеты не считайте limit гарантией числа записей для каждой заметки

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

Здесь важно прояснить деталь реализации: текущий код применяет limit к настройкам сбора для каждой цели, а затем обрезает итоговый объединённый список по тому же значению. Поэтому limit: 5 для нескольких целей не означает «по пять записей на каждую заметку». Даже если цели нет в missed, в итоговом обрезанном списке её записей может не оказаться.

Если результаты по каждой заметке нужно принимать отдельно, в первых версиях можно организовать обработку в виде запросов с одной целью и проверять возвращённые результаты по отдельности; «пакетность» не требует, чтобы результаты по всем заметкам приходили в одном ответе. При использовании пакетов с несколькими целями проверяйте привязку результатов к каждой цели и учитывайте значение количественных параметров в критериях приёмки интеграции, а не закладывайте «число заметок × limit» как ожидаемое число записей.

Идентификаторы пакетов тоже должны быть независимы от запросов API. Ваш собственный batch_id обозначает набор бизнес-целей, а ID, возвращённый вызовом API, обозначает один вызов. Повторные попытки создают новые записи попыток со ссылкой на исходный пакет. Это позволяет не перезаписывать первоначальный ответ и не терять историю отслеживания проблем.

Шаг 5. Разбирайте partial, missed и результаты по каждой цели

Синхронный ответ этой возможности помещает список комментариев в results, а count показывает число возвращённых записей. Если по части целей данные не доставлены, ответ содержит partial: true и missed; missed отмечает недоставленные цели и не является списком заметок, у которых «ноль комментариев».

При обработке результатов сначала сопоставьте каждый комментарий со списком целей по note_id или подтверждённому note_url. Записи, которые не удалось сопоставить, отправляются на проверку; их нельзя приписывать первой заметке ради заполнения отчёта. Отсутствие цели в missed не означает, что получены все комментарии этой заметки: по-прежнему действуют ограничения вроде обрезки по количеству, отсутствующих полей и неохваченной истории.

Ниже приведён офлайн-пример на JavaScript с синтетическими данными, который показывает только классификацию статусов на уровне целей. note-a и подобные значения являются вымышленными идентификаторами, а не настоящими ID платформы и не ответами API. Входные данные уже преобразованы в идентификаторы заметок на стороне приложения; при реальном использовании сначала нужно сопоставить URL и note_id.

Офлайн-демо: «есть записи», «явно не доставлено» и «не подтверждено» хранятся раздельно
function classifyBatch(targetIds, rows, missedIds) {
  const targets = new Set(targetIds);
  if (targets.size !== targetIds.length) throw new Error("duplicate target");
  const missed = new Set(missedIds);
  const counts = new Map(targetIds.map(id => [id, 0]));
  for (const id of missed) {
    if (!targets.has(id)) throw new Error("unknown missed target");
  }
  for (const row of rows) {
    if (!targets.has(row.note_id)) throw new Error("unmatched row");
    counts.set(row.note_id, counts.get(row.note_id) + 1);
  }
  return targetIds.map(note_id => {
    const count = counts.get(note_id);
    if (count > 0 && missed.has(note_id)) {
      throw new Error("conflicting target state");
    }
    return {
      note_id, count,
      state: count > 0 ? "records_observed"
        : missed.has(note_id) ? "not_delivered" : "unconfirmed"
    };
  });
}

console.log(classifyBatch(
  ["note-a", "note-b", "note-c"],
  [{note_id: "note-a", id: "synthetic-comment"}],
  ["note-b"]
));

У третьей цели нет записей и нет явного флага недоставки, поэтому пример оставляет её в статусе unconfirmed, а не записывает «ноль комментариев». Точно так же records_observed означает лишь, что записи были получены, а не all_comments_complete. Если названия статусов отражают это различие, последующая статистика не приведёт к незаметному и необоснованному расширению выводов.

Шаг 6. Обрабатывайте дедупликацию комментариев и обновления контента на двух уровнях

Текущий каталог перечисляет id, text, like_count, posted_at, ip_location, author_name, author_id, sub_comment_count, note_id, note_url и platform. Это объявления полей, а не гарантия значений в каждой записи. Перед сохранением проверьте фактическую структуру ответа, особенно ID комментариев и их связь с исходными заметками.

Смотреть определения полей отзывов и поля без описания
curl -fsS --max-time 30 \
  'https://api.everyinfra.com/api/v1/social/fields?platform=xiaohongshu&action=comments_batch' \
  | jq '{fields, undocumented}'

Если есть стабильные ID, используйте «платформа + ID заметки + ID комментария» как бизнес-ключ дедупликации и при повторном получении того же комментария обновляйте время наблюдения и изменяемые поля. Не используйте никнеймы как ключи: никнеймы могут меняться и не являются уникальными идентификаторами. Не удаляйте записи только из-за совпадения текста: разные пользователи действительно могут написать одно и то же.

Если стабильных ID нет, для приблизительной дедупликации можно сохранить комбинации вроде «идентификатор автора + время + краткое содержание текста», но их нужно помечать как имеющие низкую степень уверенности, а не считать надёжными идентификаторами. Изменения метрик вовлечённости и правки текста тоже следует отличать от новых комментариев: новое наблюдение того же комментария не является новым комментарием.

sub_comment_count сообщает число ответов, и по нему одному нельзя утверждать, что получены тексты всех вложенных ответов. Если нужны вложенные ответы, сверяйтесь с описанием sub_comments в каталоге и фактическими ответами API. При анализе по времени отделяйте posted_at от записанного вами observed_at; ошибки разбора нельзя молча заменять датой запроса.

Если реализовать это правило идентичности в PostgreSQL, составное ограничение уникальности может выразить комбинированный ключ, но отсутствующие ID нужно обрабатывать отдельно. В официальной документации отмечено, что при ограничении уникальности по умолчанию значения NULL не считаются равными; добавление unique само по себе не устраняет дубли записей с неполной идентичностью. Это пример проектирования локального хранилища, он не касается внутренней базы данных API.

Шаг 7. Проверяйте расходы по каждой цели и повторяйте запросы только для чётко определённых целей

Такие пакеты учитываются по отправленным целям, а не по HTTP-вызовам или числу возвращённых комментариев. Удаляйте дубли до отправки и сохраняйте данные billing после ответа. Текущая реализация содержит поля возврата средств для частично недоставленных целей, в том числе total_targets, billed_targets и refunded_credits, когда они применимы; не рассчитывайте, что эти три поля есть в каждом billing, и не подменяйте billed_targets значением count.

Особенно важно не путать два счётчика: заметка, вернувшая несколько комментариев, остаётся одной целью, а заметка, вернувшая меньше комментариев, чем ожидалось, не даёт права на возврат средств пропорционально значению count. Аудит проводите по ответам и записям о списаниях, а случаи с отсутствующими полями помечайте как неподтверждаемые по ответу. В этом руководстве нет фиксированных цен: фактические тарифы и условия аккаунта зависят от условий, действующих на момент вызова.

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

Сетевой тайм-аут отличается от missed: при тайм-ауте вы не получили полный ответ и не можете подтвердить, по каким целям запрос был выполнен. В таком случае сохраните попытку с неизвестным исходом и проверьте журнал вызовов или запросите проверку, а не отправляйте весь пакет заново автоматически. Клиентский batch_id не даёт гарантий идемпотентности на стороне сервера; ограничения на повторы неидемпотентных запросов описаны в официальной спецификации HTTP.

Соберите исследовательский датасет после получения комментариев

Аналитические таблицы должны по возможности прослеживаться до конкретных заметок и комментариев, но хранить в них все доступные поля не нужно. Для исследования проблем товара может хватить текста комментария, ссылок на источник, времени и тематических тегов. Хранить ли никнеймы, идентификаторы авторов и ip_location, решайте исходя из практических целей, а не держите всё долго только потому, что это вернулось в ответе.

Выносите оценки модели в отдельный слой и сохраняйте версии модели, версии правил классификации и ручные исправления. На примерах с иронией, отрицанием или цитатами метки могут быть нестабильными; в отчётах показывайте проверяемые примеры и границы выборки, а не выдавайте оценки модели за реальное отношение пользователей.

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

Определите охват и правила хранения до масштабирования

Публичная видимость сама по себе не решает вопросы прав на контент, обработки персональных данных и разрешений на распространение. Изучите применимые правила платформы и конкретные сценарии, чтобы определить, кто может получать доступ к исходным текстам, сколько их хранить, когда удалять и можно ли передавать результаты в другие системы. В этом руководстве нет способов обойти вход в аккаунт, настройки приватности или ограничения доступа.

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

Правила хранения распространяются и на диагностические логи. OWASP рекомендует удалять или обрабатывать токены доступа, идентификаторы сессий и чувствительные персональные данные. Для диагностики в первую очередь оставляйте ссылки на запросы, число целей и сводку статусов, а не записывайте целые пакеты комментариев в поля логов по умолчанию.

Что должен оставить после себя надёжный пакетный запуск

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

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

Справочник LF-02