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

Это руководство проведёт вас именно через этот процесс. Вы будете получать отрендеренные страницы листингов App Store через Crawling API, используя официальный Python-клиент crawlbase, разбирать разметку с помощью BeautifulSoup и извлекать структурированную запись для каждого приложения. Всё руководство ограничено публичными данными листингов, а раздел о законности ближе к концу, не формальность, поэтому прочитайте его, прежде чем применять это к реальным объёмам.

Что вы создадите

Python-скрипт, который принимает публичный URL приложения в App Store, получает отрендеренный HTML через Crawling API и извлекает структурированную запись. В качестве основного примера мы будем использовать хорошо известное бесплатное приложение и извлечём следующие поля:

  • Название приложения, заголовок листинга, например "Microsoft Authenticator".
  • Разработчик, издатель или продавец, например "Microsoft Corporation".
  • Рейтинг, средняя оценка в звёздах, например "4.8".
  • Количество отзывов, число оценок, составляющих этот рейтинг.
  • Категория, категория App Store, к которой относится приложение.
  • Цена, указанная цена или "Free", если приложение бесплатное.

Почему обычный запрос не работает с App Store

Если запросить URL листинга App Store с помощью обычного HTTP-клиента, вы столкнётесь с двумя проблемами. Во-первых, страница листинга использует JavaScript для заполнения части своего контента, поэтому сырой HTML, который вы получите, может не содержать искомых полей. Во-вторых, Apple отслеживает автоматический трафик: IP-адреса датацентров и паттерны запросов, которые не похожи на действия реального браузера, блокируются или ограничиваются по частоте ещё до того, как достигнут полезной разметки.

Таким образом, рабочий скрапер App Store нуждается в двух вещах в одном запросе: браузере, который действительно рендерит страницу, и IP-адресе, который платформа воспринимает как реального посетителя. Можно собрать это самостоятельно с помощью headless-браузера плюс пула ротируемых резидентных прокси, но соединение этих компонентов и поддержание их в рабочем состоянии, это и есть основная работа. Crawling API объединяет оба компонента в один вызов: вы отправляете ему URL, он рендерит страницу за доверенным IP и возвращает готовый HTML для разбора.

Зачем нужен JS-токен

Crawlbase предлагает два типа токенов. Обычный токен получает статичный HTML; токен JavaScript (JS) сначала рендерит страницу в настоящем браузере. Листинги App Store используют клиентский рендеринг для некоторых элементов, поэтому JS-токен является более надёжным выбором. Если поле возвращается пустым при использовании обычного токена, переключитесь на JS-токен, и отрендеренная разметка будет его содержать.

Предварительные требования

Перед написанием кода необходимо подготовить несколько вещей. Это не займёт много времени.

Базовые знания Python. Вы должны уметь писать и запускать Python-скрипты и устанавливать пакеты с помощью pip. Если вы только начинаете знакомство с языком, официальная документация Python и любой вводный курс приведут вас к уровню, который предполагает это руководство.

Python 3.8 или новее. Проверьте вашу версию с помощью python --version. Если она не установлена, установите её с python.org или через дистрибутив, например Anaconda.

Аккаунт и токен Crawlbase. Зарегистрируйтесь, откройте панель управления и скопируйте токен со страницы документации аккаунта. Используйте токен JavaScript (JS) для листингов App Store. Обращайтесь с токеном как с паролем: он аутентифицирует ваши запросы, поэтому не включайте его в систему контроля версий.

Настройка проекта

Создайте виртуальное окружение, чтобы зависимости проекта оставались изолированными, а затем установите две библиотеки, необходимые скраперу.

bash
python --version

python -m venv appstore_env
source appstore_env/bin/activate

pip install crawlbase beautifulsoup4

В Windows активируйте окружение с помощью appstore_env\Scripts\activate вместо строки с source. Две зависимости выполняют основную работу: crawlbase, официальный клиент для Crawling API, а beautifulsoup4 разбирает возвращённый HTML, позволяя извлекать отдельные поля с помощью CSS-селекторов. Если вам нужно повторить материал по библиотеке разбора, руководство по BeautifulSoup в Python охватывает используемые ниже селекторы.

Шаг 1: Получение отрендеренного листинга

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

python
from crawlbase import CrawlingAPI

api = CrawlingAPI({"token": "YOUR_CRAWLBASE_JS_TOKEN"})

def crawl(page_url):
    options = {"ajax_wait": "true", "page_wait": 3000}
    response = api.get(page_url, options)
    if response["status_code"] == 200:
        return response["body"].decode("utf-8")
    print(f"Request failed: {response['status_code']}")
    return None

if __name__ == "__main__":
    page_url = "https://apps.apple.com/us/app/microsoft-authenticator/id983156458"
    html = crawl(page_url)
    print(html[:500] if html else "No HTML returned")

Два параметра ожидания помогают с элементами, которые рендерятся с задержкой. ajax_wait указывает API дождаться завершения загрузки асинхронного контента, а page_wait держит фиксированное количество миллисекунд после загрузки, чтобы поздно рендерящиеся части появились до захвата страницы. Три секунды, разумное начало; увеличьте значение, если поля возвращаются пустыми. Запустите скрипт командой python scraper.py, и вы должны увидеть реальную разметку листинга, а не урезанную оболочку. Это подтверждает, что рендеринг работает ещё до написания единого селектора.

Crawlbase Crawling API

Листинг App Store требует отрендеренной страницы за доверенным IP в одном вызове. Crawling API принимает ваш токен, запускает страницу в настоящем браузере, ротирует резидентные IP на стороне сервера и возвращает готовый HTML, так что вам не нужно самостоятельно запускать парк headless-браузеров и пул прокси. Направьте его на публичный листинг приложения в бесплатном тарифе.

Шаг 2: Разбор полей приложения с помощью BeautifulSoup

Имея отрендеренный HTML, загрузите его в BeautifulSoup и извлеките каждое поле по его селектору. Листинги App Store располагают основные данные в предсказуемой структуре, поэтому вы можете сопоставить название, разработчика, рейтинг, количество отзывов, категорию и цену с отдельными селекторами. Оберните извлечение в вспомогательные функции, чтобы отсутствие одного поля не прерывало выполнение.

python
from bs4 import BeautifulSoup

def text_of(soup, selector):
    el = soup.select_one(selector)
    return el.get_text(strip=True) if el else None

def scrape_app(html):
    soup = BeautifulSoup(html, "html.parser")

    rating_text = text_of(soup, ".we-rating-count.star-rating__count")
    stars, reviews = (rating_text.split(" • ") + [None, None])[:2] if rating_text else (None, None)

    return {
        "name": text_of(soup, ".product-header__title"),
        "developer": text_of(soup, ".product-header__identity a"),
        "rating": stars,
        "review_count": reviews,
        "category": text_of(soup, ".information-list__item__term:-soup-contains('Category') + dd a"),
        "price": text_of(soup, ".app-header__list__item--price"),
    }

Вспомогательная функция text_of делает сразу два полезных дела: она запрашивает единственный элемент и возвращает None, когда элемент отсутствует, вместо того чтобы выбрасывать исключение при вызове .get_text() на ничто. Это делает извлечение устойчивым, когда одно поле отсутствует в конкретном листинге. Строка рейтинга в App Store объединяет и звёздную оценку, и количество отзывов в одно значение, разделённое буллетом, поэтому мы разбиваем её один раз и присваиваем обе части, устанавливая по умолчанию None, когда формат не совпадает.

Селекторы меняются

Имена классов Apple (маркеры we-rating-count, элементы product-header и строки information-list) меняются без предупреждения. Относитесь к приведённым выше селекторам как к начальному шаблону, а не контракту. Когда поле возвращается как None, повторно осмотрите живой листинг в инструментах разработчика браузера и обновите селектор. Периодическое обслуживание селекторов, норма для любого промышленного скрапера, а не признак поломки.

Шаг 3: Соединяем всё вместе

Теперь соедините получение и разбор в один исполняемый скрипт. Получите отрендеренный HTML, передайте его парсеру и напечатайте структурированную запись.

python
import json
from crawlbase import CrawlingAPI
from bs4 import BeautifulSoup

api = CrawlingAPI({"token": "YOUR_CRAWLBASE_JS_TOKEN"})

def crawl(page_url):
    options = {"ajax_wait": "true", "page_wait": 3000}
    response = api.get(page_url, options)
    if response["status_code"] == 200:
        return response["body"].decode("utf-8")
    print(f"Request failed: {response['status_code']}")
    return None

def text_of(soup, selector):
    el = soup.select_one(selector)
    return el.get_text(strip=True) if el else None

def scrape_app(html):
    soup = BeautifulSoup(html, "html.parser")
    rating_text = text_of(soup, ".we-rating-count.star-rating__count")
    stars, reviews = (rating_text.split(" • ") + [None, None])[:2] if rating_text else (None, None)

    return {
        "name": text_of(soup, ".product-header__title"),
        "developer": text_of(soup, ".product-header__identity a"),
        "rating": stars,
        "review_count": reviews,
        "category": text_of(soup, ".information-list__item__term:-soup-contains('Category') + dd a"),
        "price": text_of(soup, ".app-header__list__item--price"),
    }

def main():
    page_url = "https://apps.apple.com/us/app/microsoft-authenticator/id983156458"
    html = crawl(page_url)
    if not html:
        return
    data = scrape_app(html)
    print(json.dumps(data, indent=2))

if __name__ == "__main__":
    main()

Как выглядит результат

Запустите полный скрипт командой python scraper.py, и вы получите чистую структурированную запись приложения, готовую для записи в JSON, CSV или базу данных.

json
{
  "name": "Microsoft Authenticator",
  "developer": "Microsoft Corporation",
  "rating": "4.8",
  "review_count": "339.5K Ratings",
  "category": "Productivity",
  "price": "Free"
}

Масштабирование на множество приложений

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

python
import time

apps = [
    "https://apps.apple.com/us/app/microsoft-authenticator/id983156458",
    "https://apps.apple.com/us/app/google-authenticator/id388497605",
]

results = []
for url in apps:
    html = crawl(url)
    if html:
        results.append(scrape_app(html))
    time.sleep(2)

with open("apps.json", "w") as f:
    json.dump(results, f, indent=2)

Вызов time.sleep между запросами сделан намеренно. Даже несмотря на то, что Crawling API ротирует IP-адреса за вас, выдержка темпа делает запуск вежливым и предсказуемым, и даёт каждой отрендеренной странице время вернуться, не накапливая запросы один на другой. Если вы хотите также собирать отзывы на каждое приложение, тот же паттерн «получить, разобрать» распространяется на раздел отзывов; руководство по скрапингу отзывов покупателей подробнее описывает эту структуру.

Структурированные данные о приложениях без скрапинга

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

  • iTunes Search API и RSS-каналы App Store. Публичный iTunes Search API возвращает данные приложений (название, разработчик, средний рейтинг, количество оценок, категория, цена и др.) в формате JSON, а RSS-каналы App Store публикуют рейтинговые списки лучших бесплатных, платных и трендовых приложений. Для структурированных метаданных на уровне листинга, это то, к чему стоит обратиться в первую очередь.
  • App Store Connect API. Если приложения принадлежат вам, App Store Connect API даёт первичный доступ к вашим листингам, продажам и аналитике в вашем аккаунте разработчика без какого-либо скрапинга.

Обращайтесь к скраперу, когда вам нужны данные, которые официальные каналы не предоставляют, или когда вы собираете информацию по множеству листингов третьих лиц. Для всего, что iTunes Search API и RSS-каналы уже возвращают в JSON, используйте их в первую очередь.

Как оставаться незаблокированным

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

  • Соблюдайте темп запросов. Обрушиваться на листинги в плотном цикле, быстрейший способ получить ограничение скорости. Распределяйте запросы во времени и варьируйте цели вместо того, чтобы обходить один путь на полной скорости.
  • Используйте ротацию. Пул резидентных IP распределяет запросы по множеству адресов реальных пользователей, чтобы ни один из них не превысил лимит запросов. Crawling API делает это за вас; если вы используете собственный стек, именно эта часть требует правильной реализации.
  • Читайте коды статуса. Запуск, который начинает возвращать запросы верификации или ошибки, сигнализирует, что текущая частота запросов или уровень IP больше не достаточны. Воспринимайте это как сигнал к снижению нагрузки, а не как шум для игнорирования.

Более детальный план действий см. в руководстве по обходу CAPTCHA при веб-скрапинге и руководстве по скрапингу JavaScript-страниц с Python. Если вы предпочитаете маршрутизировать собственный трафик через ротируемый пул вместо управляемого API, Smart AI Proxy (также называемый AI Proxy) предоставляет ту же ротацию резидентных IP как сменный прокси-эндпоинт.

Законно ли парсить App Store?

Разрешён ли скрапинг App Store, зависит от условий использования Apple, вашей юрисдикции и того, что вы делаете с данными. Условия Apple ограничивают автоматический доступ, поэтому скрапинг может нарушать эти условия независимо от того, насколько аккуратен ваш инструментарий. Ни один из приведённых здесь кодов это не изменяет; он просто делает техническую часть рабочей. Прочитайте Условия использования Apple и файл robots.txt App Store, и относитесь к обоим как к границе того, что вы собираете.

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

Для структурированных данных о приложениях предпочитайте официальные каналы Apple. App Store Connect API даёт первичный доступ к вашим собственным приложениям, а публичные iTunes Search API и RSS-каналы App Store возвращают метаданные приложений в JSON без скрапинга единой страницы. Когда официальный канал покрывает вашу потребность, он является правильным инструментом; скрапер из этого руководства предназначен для публичных данных листингов, которые каналы не предоставляют, и ничего больше.

Итоги

Ключевые выводы

  • Сначала рендерите, потом разбирайте. Листинги App Store используют JavaScript, поэтому обычный запрос может вернуть неполную разметку; Crawling API с JS-токеном сначала рендерит страницу.
  • Рендеринг и доверенный IP идут вместе. Один вызов Crawling API обрабатывает оба аспекта; ajax_wait и page_wait управляют временем ожидания позднего контента.
  • BeautifulSoup выполняет извлечение. Сопоставьте название, разработчика, рейтинг, количество отзывов, категорию и цену с текущими селекторами и ожидайте, что те будут меняться.
  • Масштабируйте с помощью цикла по URL с выдержкой темпа. Тот же парсер работает для каждого листинга, поэтому реальное задание, это список ссылок на приложения плюс небольшая пауза между запросами.
  • Предпочитайте официальные каналы для метаданных. iTunes Search API, RSS-каналы App Store и App Store Connect API возвращают структурированные данные без скрапинга; в остальном ограничивайтесь публичными данными листингов.

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

Почему обычный запрос возвращает неполные данные из App Store?

Потому что листинги App Store рендерят часть своего контента на стороне клиента с помощью JavaScript. Сырой HTTP-запрос может вернуть оболочку страницы без таких полей, как рейтинг или категория, поскольку они заполняются только после выполнения скриптов страницы в браузере. JS-токен Crawling API сначала рендерит страницу, поэтому поля присутствуют, когда BeautifulSoup их разбирает.

Какой токен нужен для App Store: обычный или JS?

Используйте JS-токен. Обычный токен получает статичный HTML, который в App Store может оставить некоторые поля листинга пустыми. JS-токен рендерит страницу в настоящем браузере перед возвратом HTML, поэтому название, разработчик, рейтинг, количество отзывов, категория и цена присутствуют при разборе.

Есть ли у Apple официальный API для данных приложений?

Да. Публичный iTunes Search API возвращает данные приложений в формате JSON (название, разработчик, средний рейтинг, количество оценок, категория, цена и др.), а RSS-каналы App Store публикуют рейтинговые списки лучших приложений. Для ваших собственных приложений App Store Connect API даёт первичный доступ к листингам и аналитике. Предпочитайте эти официальные каналы для структурированных метаданных и прибегайте к скрапингу только тогда, когда вам нужны публичные данные листингов, которые каналы не предоставляют.

Мои селекторы возвращают None. Что изменилось?

Почти наверняка разметка Apple. Маркеры we-rating-count, элементы product-header и строки information-list меняются без предупреждения, поэтому селекторы, которые работали в прошлом месяце, могут сломаться. Повторно осмотрите живой листинг в инструментах разработчика браузера и обновите селекторы. Периодическое обслуживание селекторов, норма для любого промышленного скрапера.

Можно ли парсить данные аккаунтов или персональные данные из App Store?

Нет, и это руководство не охватывает такой случай. Данные аккаунтов, история покупок и всё, что находится за логином, не являются публичными данными. Скрапинг контента за логином или обход аутентификации для его достижения выходит за рамки данного руководства и противоречит условиям Apple. Для первичных данных о ваших собственных приложениях правильным инструментом является App Store Connect API.

Как избежать блокировки при парсинге App Store?

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

Начать создавать

Обходите любой сайт в масштабе, без борьбы с инфраструктурой.

Crawlbase берёт на себя прокси, отпечатки и CAPTCHA, чтобы ваша команда выпускала конвейеры данных вместо поддержки обвязки краулинга. 1 000 запросов бесплатно, без карты.

Самообслуживание · Звонок отдела продаж не требуется · Доступны корпоративные объёмы краулинга