Сбор отзывов App Store и Google Play: конечные точки, ограничения, гео

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

Отзывы о приложениях — это самое дешевое исследование клиентов: нефильтрованные запросы функций, отчеты об ошибках, привязанные к конкретной версии, и текущий анализ настроений по каждому конкуренту в вашей категории. Загвоздка в доступе. Оба магазина показывают несколько отзывов на странице и скрывают остальные за лентами, токенами и витринами по странам. Это руководство показывает, как собирать отзывы App Store и Google Play — реальные конечные точки, ограничения на пагинацию, о которых никто не предупреждает, и географические и лимитные реалии, которые определяют, выживет ли ваш конвейер после нескольких сотен строк.

Apple, простой способ: RSS-лента

Apple предоставляет публичную JSON-ленту отзывов клиентов, для которой не нужен токен. Это самый быстрый способ начать и возвращает чистые, структурированные записи — рейтинг, заголовок, текст, автор, версия приложения. Ограничение — жесткий потолок: лента обслуживает максимум 10 страниц примерно по 50 отзывов, то есть около 500 отзывов на приложение на витрину, с уклоном в сторону самых последних. Для мониторинга свежих отзывов этого часто достаточно; для полной истории — нет.

import requests

def apple_rss_reviews(app_id, country="us", pages=10):
    out = []
    for page in range(1, pages + 1):  # feed caps out around page 10
        url = (f"https://itunes.apple.com/{country}/rss/customerreviews/"
               f"page={page}/id={app_id}/sortby=mostrecent/json")
        # route through a residential exit in the target storefront's country
        proxy = f"http://USER-country-{country}:PASS@gate.quantumproxies.io:8000"
        r = requests.get(url, proxies={"https": proxy}, timeout=20)
        entries = r.json().get("feed", {}).get("entry", [])
        for e in entries[1:]:  # first entry is app metadata, skip it
            out.append({
                "rating":  e["im:rating"]["label"],
                "version": e["im:version"]["label"],
                "title":   e["title"]["label"],
                "text":    e["content"]["label"],
                "author":  e["author"]["name"]["label"],
            })
        if len(entries) <= 1:
            break
    return out

Apple, глубокий способ: API app-store и его токен

Чтобы преодолеть 500, вы используете ту же конечную точку, которую вызывает веб-страница App Store (AMP / MZStore API). Она возвращает более богатые записи — id отзыва, флаг редактирования, ответы разработчиков — но требует токен, который вы сначала собираете с публичной веб-страницы приложения, а затем воспроизводите. Отзывы приходят партиями примерно по двадцать, и вы углубляете пагинацию с помощью offset; чем больше offset, тем старше отзывы, потому что Apple не позволяет этой конечной точке сортировать по дате напрямую.

Реальное ограничение здесь — это лимитирование скорости, и оно быстро наступает с одного IP. Решение не волшебное — это преднамеренная задержка плюс экспоненциальное увеличение интервала, и распределение запросов по IP. Практики, которые добавляют оба, извлекли порядка 15,000 отзывов для одного приложения, не срабатывая ограничитель. Именно здесь вращающийся пул резидентных IP окупается: каждая партия может выходить с другого чистого IP, так что счетчик на IP никогда не поднимается в зону блокировки.

import time, requests

# token is scraped once from the app's App Store web page, then reused
HEADERS = {"Authorization": "Bearer TOKEN_FROM_APP_PAGE",
           "Origin": "https://apps.apple.com"}

def apple_deep_reviews(app_id, country="us", target=2000):
    reviews, offset = [], None
    while len(reviews) < target:
        params = {"l": "en-US", "offset": offset} if offset else {"l": "en-US"}
        url = (f"https://amp-api.apps.apple.com/v1/catalog/{country}/apps/"
               f"{app_id}/reviews")
        proxy = f"http://USER:PASS@rotating.quantumproxies.io:8000"
        r = requests.get(url, headers=HEADERS, params=params,
                         proxies={"https": proxy}, timeout=25)
        if r.status_code == 429:            # rate limited
            time.sleep(8); continue          # back off, gateway rotates the IP
        data = r.json()
        reviews += data.get("data", [])
        offset = data.get("next", "").split("offset=")[-1] or None
        if not offset:
            break
        time.sleep(1.5)                      # be a polite client
    return reviews
Сравнение RSS-ленты отзывов клиентов Apple и AMP API app-store, показывающее ограничения на пагинацию и требования к токенам
RSS-лента быстрая, но ограничена ~500; API с токенами идет глубже, но жестко лимитирует с одного IP.

Google Play: гидратированный JSON, а не HTML

Отзывы Play не находятся в HTML страницы. Магазин загружает их через внутреннюю конечную точку, которая возвращает вложенный JSON, с пагинацией по токену продолжения, а не по номерам страниц, и фильтруется по порядку сортировки (новейшие, рейтинг, полезность). Восстановление этих запросов вручную хлопотно, поэтому большинство команд полагаются на хорошо поддерживаемые open-source библиотеки google-play-scraper (Node и Python), которые оборачивают конечную точку и предоставляют параметры country и lang. Как и в случае с Apple, результаты по странам различаются, поэтому задайте оба параметра явно.

# pip install google-play-scraper
from google_play_scraper import reviews, Sort

result, token = reviews(
    "com.example.app",
    lang="en",       # review language
    country="us",    # storefront
    sort=Sort.NEWEST,
    count=200,       # per call; loop with continuation_token for more
)
for r in result[:3]:
    print(r["score"], r["reviewCreatedVersion"], r["content"][:80])

При реальных объемах конечная точка Play также ограничивает по IP, и структура JSON периодически меняется. Если вы предпочитаете не заниматься этим обслуживанием, Scraper API, который рендерит и возвращает гидратированные данные в виде чистого JSON, устраняет обе проблемы — он берет на себя проксирование и парсинг, так что вы получаете стабильную форму. Та же логика компромиссов, которую мы описываем для сбора отзывов о продуктах в больших объемах, применима и здесь.

Одна пара полей сбивает людей с толку: язык и страна — это не одно и то же. Витрина (страна) определяет, какие отзывы вообще существуют; параметр языка определяет, какие из них вы получите. На двуязычном рынке, таком как Канада или Швейцария, вы часто хотите оба языка, поэтому задайте их независимо, а не предполагая, что страна подразумевает один язык. На стороне Apple более богатые записи также раскрывают ответы разработчиков — публичный ответ, который поставщик публикует под отзывом — это тихо ценный сигнал о том, как конкуренты решают жалобы и какие проблемы они выбирают для публичного ответа.

Гео-витрины — это вся суть

Оба магазина организованы по витринам стран, ключом которых является двухбуквенный код. Отзывы о приложении в США ничего не говорят о том, как оно воспринимается в Германии, Японии или Бразилии — разные языки, разные жалобы, разные пробелы в функциях. Чтобы честно прочитать каждую витрину, вы запрашиваете с выходного IP в этой стране; IP дата-центра в неправильном регионе дает вам несогласованный или заблокированный ответ. С резидентными выходами в более чем 200 странах вы можете прокрутить одно и то же приложение через каждый рынок и построить карту настроений по странам — сырье для серьезной работы ASO.

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

От отзывов к сигналу ASO

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

Получите резидентные IP для каждой витрины приложения

Часто задаваемые вопросы

Как собрать отзывы App Store на Python?

Начните с публичной RSS-ленты отзывов клиентов Apple в формате JSON — без токена, структурированный вывод, но ограничен примерно 500 последними отзывами на приложение на витрину. Чтобы углубиться, вызовите AMP API app-store с токеном, собранным с веб-страницы приложения, используйте пагинацию с offset, и добавьте задержку плюс увеличение интервала. Направьте каждую витрину через резидентный IP в этой стране.

Существует ли официальный API отзывов App Store?

Публичная RSS-лента Apple — это самое близкое к официальному источнику отзывов без токена, но она ограничена. Более богатая конечная точка AMP — это то, что использует собственная веб-страница магазина и требует собранного токена. Ни один из них не является документированным продуктом для разработчиков для массового сбора отзывов третьими сторонами, поэтому относитесь к лимитам и условиям с осторожностью.

Как собрать отзывы Google Play?

Play предоставляет отзывы через внутреннюю конечную точку, возвращающую вложенный JSON, с пагинацией по токену продолжения и фильтруемую по порядку сортировки. Поддерживаемые open-source библиотеки google-play-scraper оборачивают ее и предоставляют параметры country и lang. Установите оба, прокрутите токен продолжения для объема и распределите запросы по IP, потому что конечная точка ограничивает по адресу.

Зачем мне нужны прокси для сбора отзывов о приложениях?

Две причины. Лимитирование скорости: оба магазина быстро ограничивают один IP, поэтому вращающиеся резидентные выходы держат счетчик на IP достаточно низким, чтобы собрать тысячи отзывов. География: отзывы специфичны для витрины, поэтому точное чтение отзывов страны означает запрос с IP в этой стране. IP дата-центра в неправильном регионе дают несогласованные или заблокированные ответы.

Данные магазина приложений — это золотая жила, огражденная тремя простыми препятствиями — ограничениями, токенами и витринами. Знайте, какую конечную точку использовать, правильно ее пагинируйте и выходите из правильной страны на чистых IP, и вы превратите разбросанные звездные рейтинги в поток клиентского голоса по версиям и рынкам.

Пусть Scraper API возвращает данные отзывов в формате JSON