Синхронизация данных
Синхронизация нужна, когда отзывы живут не только у нас, но и в вашей базе: в CRM, в
хранилище, в собственной аналитике. Метод – GET /v3/reviews/sync.
Если своей базы нет, эта страница вам не нужна: показать отзывы на сайте умеет лента, узнать о новом – вебхук.
Цикл
cursor = db.load_cursor() # None при первом запуске
params = {"cursor": cursor} if cursor else {"object_id": 20, "limit": 500}
while True:
page = httpx.get(f"{API}/reviews/sync", headers=H, params=params).json()
for review in page["data"]:
db.upsert_review(review) # склейка по review["id"]
db.save_cursor(page["next_cursor"]) # ПОСЛЕ каждой страницы
if not page["has_next"]:
break
params = {"cursor": page["next_cursor"]}Первый прогон выгружает всю историю, следующие – только изменения.
Отзывы собираются дважды в сутки, поэтому опрашивать поток чаще раза в час смысла нет: между сборами он отдаёт пустую страницу.
Четыре правила
1. Курсор хранится в базе, а не в памяти процесса. Тогда следующий запуск продолжает с той же точки, а не выкачивает всё заново.
2. Сохранять после каждой страницы. Тогда обрыв связи стоит одной страницы, а не всего обхода.
3. В режиме all – UPSERT по id, не INSERT. Изменённый отзыв приходит со старым
id: новой строки мы не заводим, поэтому вставка даст дубли или ошибку уникальности.
В режиме new повтор возможен после смены состава объекта (см. «Границы»), поэтому UPSERT по id надёжнее и здесь. Потерять отзыв поток
не может ни в одном из режимов.
4. next_cursor приходит всегда – и на последней странице, и на пустой. Признак
«догнал» – это has_next: false, а не отсутствие курсора.
Что приходит
Изменением считается: правка текста или оценки на площадке, появившийся или изменившийся
ответ организации, изменившийся набор фотографий, пропажа отзыва с площадки
(is_deleted: true) и его возврат. Пересбор сам по себе – не изменение: если на площадке
ничего не поменялось, отзыв в поток не попадёт.
mode | Что приходит | Как класть к себе |
|---|---|---|
all (по умолчанию) | новые отзывы и изменения | UPSERT по id |
new | только впервые появившиеся | UPSERT по id: повтор возможен после смены состава объекта |
Режим зашит в курсор: для второго режима нужен отдельный курсор.
Отдельного режима «только изменения» нет: после первого полного прохода режим all отдаёт только то, что появилось или изменилось с прошлого запроса.
Границы
- Порядок задан режимом, и своего параметра сортировки у метода нет. В
allстроки идут по времени последнего изменения отзыва, вnew– по времени, когда мы его впервые захватили. Дата публикации на площадке (review_date) порядок не задаёт ни там, ни там: отзыв 2019 года, у которого вчера появился ответ, придёт вallвместе со вчерашними изменениями, а не в хвосте истории. Нужен свой порядок – стройте его у себя. - Фильтров нет. Отзыв, который правкой перестал подходить под фильтр, пришлось бы присылать событием «выбыл» – такого события не существует, поэтому любой фильтр сделал бы поток дырявым. Отбирайте у себя.
- Состав объекта поток не отслеживает. Убрали ссылку или выключили объект – его отзывы
просто перестанут приходить, отдельного события об этом не будет. Чистите у себя
по
link_id. Любая смена состава – ссылку убрали, добавили или вернули, оплатили тариф после пробного периода – сбрасывает сохранённый курсор: поток проходит объект заново с начала истории. Уже полученные отзывы придут ещё раз, upsert поidих перезапишет. - Задержка несколько секунд. Это защита: отзыв, который прямо сейчас записывается, иначе оказался бы позади вашего курсора и не пришёл бы никогда.
Если курсор не принят
400 invalid_cursor – курсор испорчен, изменён или выдан другому аккаунту: начните обход
заново, без cursor. 400 cursor_mismatch – вместе с курсором передан другой object_id,
folder_id или mode: либо не передавайте их вовсе, либо передайте те же.
Полный список параметров и полей – в справочнике метода.