# Исследование VK API для проведения розыгрышей Данный документ содержит детальный анализ методов официального VK API, типов токенов, ограничений, прав доступа и лимитов для реализации сервиса розыгрышей. --- ## 1. Типы токенов и уровни доступа | Тип токена | Как получается | Права / Scope | Применимость в розыгрышах | Ограничения | |---|---|---|---|---| | **Сервисный ключ доступа (Service Token)** | В настройках VK App (Standalone / Web) | Публичные данные (стены открытых групп, открытые профили) | Базовый сбор лайков и комментариев с открытых стен | Не может получать список репостов (`wall.getReposts`), не может проверять закрытые профили | | **Ключ сообщества (Community / Group Token)** | В настройках группы (Управление -> Работа с API) | `wall`, `photos`, `messages`, `manage` | Идеален, когда розыгрыш проводит само сообщество-организатор | Работает только в рамках данного сообщества | | **Пользовательский токен (User Token / OAuth)** | VK ID OAuth 2.0 (Implicit Flow / Authorization Code) | `wall`, `groups`, `friends`, `offline` | Максимальный доступ (проверка репостов, членства в закрытых группах) | Требует авторизации организатора через VK ID | --- ## 2. Ключевые методы VK API для розыгрыша ### 2.1. Получение информации о посте - **Метод**: `wall.getById` - **Параметры**: - `posts`: строка формата `"{owner_id}_{post_id}"` (например, `-123456_7890`) - `extended`: `1` (возвращает данные авторов и прикрепленных сообществ) - **Токен**: Сервисный, Сообщества или Пользовательский. - **Возвращаемые данные**: Текст записи, вложения (фотографии/видео), счетчики (`likes.count`, `comments.count`, `reposts.count`, `views.count`), дата публикации. ### 2.2. Сбор лайков - **Метод**: `likes.getList` - **Параметры**: - `type`: `"post"` - `owner_id`: ID владельца стены (отрицательный для групп) - `item_id`: ID записи - `filter`: `"likes"` (или `"copies"` для репостов) - `extended`: `1` (возвращает имя, фамилию, аватарку) - `count`: до `1000` за один запрос - `offset`: смещение для пагинации - **Токен**: Сервисный или Пользовательский. - **Особенности**: Позволяет быстро выгрузить до 1000 пользователей за запрос. С помощью `execute` можно за один сетевой запрос выгрузить до 25 000 лайков. ### 2.3. Сбор комментариев - **Метод**: `wall.getComments` - **Параметры**: - `owner_id`: ID сообщества / пользователя - `post_id`: ID записи - `need_likes`: `0` или `1` - `extended`: `1` (возвращает профили комментаторов `profiles` и `groups`) - `count`: до `100` за один запрос - `offset`: смещение - `fields`: `"photo_100,photo_200,screen_name,sex"` - **Токен**: Сервисный или Пользовательский. - **Особенности**: Лимит 100 комментариев на вызов. Для постов с тысячами комментариев необходима пакетная выгрузка через `execute`. ### 2.4. Сбор и проверка репостов - **Метод 1**: `wall.getReposts` - **Параметры**: `owner_id`, `post_id`, `count` (до 1000), `offset` - **Ограничение**: Метод возвращает только репосты на открытые стены и доступен преимущественно с пользовательским токеном с правами `wall` или токеном сообщества. - **Метод 2**: `likes.getList` с параметром `filter="copies"` - Возвращает пользователей, сделавших репост записи (если их профили и настройки приватности позволяют отображать действие). - **Спорные места и Privacy Policy VK**: - Если профиль пользователя закрыт (приватный аккаунт), стороннее приложение **не может** увидеть репост на его стене без авторизации самого этого пользователя. В регламенте розыгрышей организаторы обычно указывают: *"На время розыгрыша страница участника должна быть открыта"*. ### 2.5. Проверка подписки на сообщество - **Метод 1 (пакетная проверка)**: `groups.isMember` - **Параметры**: `group_id`, `user_id` или `user_ids` (до 500 ID через запятую), `extended: 1` - **Возвращает**: `member: 1/0`, `can_invite`, `can_post`. - Высокая скорость: можно проверить сразу пачку из 500 участников. - **Метод 2 (полный список подписчиков)**: `groups.getMembers` - **Параметры**: `group_id`, `count` (до 1000), `offset`, `fields` - Подходит для сверки базы подписчиков. --- ## 3. Оптимизация через `execute` (VK Script) VK API предоставляет процедуру `execute`, позволяющую исполнять код на серверах VK (язык VKScript, подмножество JS/ActionScript). - **Лимит**: До 25 вызовов API внутри одного `execute`. - **Эффективность**: - `likes.getList`: 25 * 1000 = **25 000 лайков за 1 сетевой HTTP-запрос**. - `groups.isMember`: 25 * 500 = **12 500 проверок подписки за 1 запрос**. - `wall.getComments`: 25 * 100 = **2 500 комментариев за 1 запрос**. Пример VKScript для пакетного сбора лайков: ```javascript var owner_id = Args.owner_id; var item_id = Args.item_id; var offset = parseInt(Args.offset); var i = 0; var all_items = []; while (i < 25) { var res = API.likes.getList({ "type": "post", "owner_id": owner_id, "item_id": item_id, "count": 1000, "offset": offset + (i * 1000), "extended": 1 }); if (res.items.length == 0) { return {"items": all_items, "count": res.count, "done": 1}; } all_items = all_items + res.items; i = i + 1; } return {"items": all_items, "offset": offset + (i * 1000), "done": 0}; ``` --- ## 4. Лимиты и Rate Limiting - **Частота запросов**: - Пользовательский токен: до 3 запросов в секунду. - Сервисный ключ / токен сообщества: до 20 (в некоторых случаях до 50) запросов в секунду. - При превышении возвращается `Error 6: Too many requests per second`. - **Обработка ошибок**: - `Error 15: Access denied` — закрытая группа/профиль. - `Error 18: User was deleted or banned` — деактивированные аккаунты (собачки), которые автоматически должны исключаться фильтрами. - `Error 29: Rate limit reached` — дневной лимит. --- ## 5. Выводы для Архитектуры приложения 1. **Многоуровневый сбор данных**: - На этапе 1 создана модульная архитектура со слоем `SocialMediaProvider`. - Реализован `VkMockProvider` для детерминированного тестирования и работы без ключей API, и каркас `VkProvider` с чистыми контрактами. 2. **Асинхронность и очереди**: - Для масштабных розыгрышей (10 000+ участников) сбор данных должен происходить поэтапно (лайки -> комменты -> подписка) с индикатором прогресса в UI. 3. **Требование открытых профилей**: - В UI и аудит-отчете необходимо явно фиксировать причину недопуска (`exclusionReason = "PRIVATE_PROFILE_OR_NO_REPOST"`, `"NOT_SUBSCRIBED"`, `"IS_ADMIN"`, `"DUPLICATE_COMMENT"`).