Steam Scraper Tutorial: Как собирать данные о публичных игровых магазинах
TL;DR
Методы Steam Web API, интерфейсы витрины и HTML магазина имеют разные контракты и условия доступа.
Этот проект сочетает в себе задокументированный пример новостного API с импортом отслеживателя цен для авторизованных данных.
Предоставленные цены на игры и идентификаторы приложений являются синтетическими фиктивными данными. Это не наблюдаемые предложения Steam.
Сравнивайте цены только в пределах одного и того же идентификатора приложения, региона, валюты, типа пакета и контекста наблюдения.
Отсутствие, недоступность, бесплатные и платные цены - это отдельные состояния; никогда не превращайте отсутствующую цену в ноль.
Что вы создадите: Парсер данных игры Steam
Вы создадите небольшой рабочий процесс с данными игры с двумя путями: получение новостей через задокументированный метод Steam Web API и нормализация разрешенного набора данных цен в CSV, JSON и SQLite.
Отслеживатель цен работает локально с синтетической фиктурой, поэтому весь путь парсинга и хранения воспроизводим без сканирования активной витрины. Для производственных цен подключите источник, доступ и условия использования данных которого охватывают ваш рабочий процесс. Это различие важно, поскольку доступный URL витрины не является автоматически поддерживаемым публичным API цен.
Источники данных Steam: API магазина, Steam Web API и HTML
Сбор данных Steam начинается с выбора интерфейса, который действительно предоставляет необходимые поля и разрешает предполагаемое использование.
Выбор правильного источника данных Steam
Источник
Подходящая цель
Важное ограничение
Задокументированный Steam Web API
Конкретные задокументированные методы, такие как новости приложений
Не все поля магазина или цены открыты
Одобренный интерфейс издателя/партнера
Данные в рамках прав разработчика
Доступ к учетным данным и приложениям может быть ограничен
Попробуйте Nstproxy Crawl - Начните Бесплатно Уже Сегодня
Лицензионный набор данных цен
История предложений по регионам по контракту
Объем покрытия и перераспределение зависят от лицензии
JSON, ориентированный на витрину
Потенциальная деталь реализации сайта
Доступность не является гарантией стабильности или разрешения
HTML магазина
Одобренное исследование на уровне страниц
Правила доступа, региональное состояние, разметка и возрастные ограничения
Обзор Web API от Valve описывает использование задокументированного API. Часто упоминаемый интерфейс appdetails магазина не должен представляться как общий API цен с теми же задокументированными гарантиями.
Понимание идентификаторов приложений Steam и регионального ценообразования
Идентификатор приложения (App ID) идентифицирует приложение, которое может быть игрой, DLC, демонстрацией или другим типом приложения. Предложение также может включать пакеты или бандлы, поэтому метка на уровне приложения не является полной коммерческой идентичностью.
Идентификатор магазина, тип предложения, регион, валюта, первоначальная и текущая сумма, состояние цены, источник и время наблюдения. Сохраняйте целые исходные суммы с явной конвенцией единиц. Не делите каждую валюту на 100, не проверив определение единицы источника.
Предварительные условия и настройка среды Python
Предоставленный отслеживатель использует стандартную библиотеку Python. Создайте каталог, содержащий steam_tracker.py и steam_prices_fixture.json, затем используйте виртуальную среду.
Фиктура содержит вымышленные названия игр и цены, включая платные, бесплатные и недоступные состояния. Она существует для проверки поведения; не используйте её как выборку рыночной истории.
Шаг 1: Получение деталей игры Steam
Получайте данные только через интерфейс, который охватывает запрашиваемые данные и использование. В качестве задокументированного, узкоспециализированного примера метод Valve's GetNewsForApp возвращает новости приложения с использованием App ID и ограниченного количества результатов.
Отслеживатель включает эту необязательную команду:
python steam_tracker.py --news570
Этот запрос, основанный на документации, не выполнялся как активный тест Steam для статьи. Он получает новости, а не цены, имена разработчиков или авторитетный каталог продуктов. Это различие предотвращает неправильную маркировку ответа на новости как полного метаданных магазина.
Для получения деталей игры и цен импортируйте ответ разрешенного источника через адаптер, который отображает схему ниже.
Шаг 2: Извлечение метаданных игры и цен
Нормализованная схема сохраняет неизвестные значения явно.
Для реальных данных также сохраняйте тип приложения, идентичность пакета, локализацию источника и определение единицы измерения провайдера. Имена разработчиков, даты выпуска и жанры должны оставаться нулевыми, когда отсутствуют. Строка с датой выпуска, отображаемая на экране, не всегда является сортируемой ISO-датой.
Парсер отвергает несоответствующие бесплатные цены и неизвестные состояния цен с числовыми значениями. Недоступное региональное предложение имеет нулевые цены, а не вымышленный ноль.
Шаг 3: Сбор нескольких игр Steam
Примените ограниченные практики сбора и используйте разрешённый список идентификаторов приложений, фиксируя каждый результат. Держите недействительные идентификаторы, предложения, недоступные по региону, ошибки источника и отсутствующие цены отдельно.
При использовании одобренного онлайн-источника делите один бюджет на ставки между работниками и кэшируйте стабильные метаданные. Не рассматривайте универсальную рекомендацию по параллелизму как разрешение превышать лимиты метода.
Пример обрабатывает три локальных записи. Увеличьте размер фикстуры, чтобы протестировать разбор и хранение перед добавлением адаптера живого получения.
Шаг 4: Экспорт данных Steam в CSV и JSON
CSV полезен для обзора; JSON более четко сохраняет нулевые значения и типы полей. SQLite поддерживает исторические наблюдения.
Полный сборщик записывает все три вывода:
"""Разобрать авторизованный/локальный источник цен; по желанию вызвать документированный публичный новостной API."""import argparse
import csv
import json
import sqlite3
import time
from datetime import datetime
from pathlib import Path
from urllib.parse import urlencode
from urllib.request import Request, urlopen
defnormalize(item): appid =int(item["appid"])if appid <=0:raise ValueError("Недействительный идентификатор приложения") observed = item["observed_at"]if datetime.fromisoformat(observed.replace("Z","+00:00")).utcoffset()isNone:raise ValueError("Время наблюдения должно включать часовой пояс") state = item["price_state"]if state notin("paid","free","unavailable","undisclosed"):raise ValueError("Неизвестное состояние цены") initial, final = item.get("initial_minor"), item.get("final_minor") currency, region = item.get("currency"), item["region"]if state in("paid","free"):ifnot currency orany(type(v)isnotintor v <0for v in(initial, final)):raise ValueError("Отсутствует сопоставимая цена")if state =="free"and(initial !=0or final !=0):raise ValueError("Цена должна быть нулевой для бесплатного")elif initial isnotNoneor final isnotNone:raise ValueError("Неизвестные цены должны оставаться нулевыми")returndict(appid=appid, name=item["name"], region=region, currency=currency, initial_minor=initial, final_minor=final, price_state=state, observed_at=observed, source=item["source"])defsave(rows, database):with sqlite3.connect(database)as db: db.execute("""CREATE TABLE IF NOT EXISTS prices(
appid INTEGER,name TEXT,region TEXT,currency TEXT,
initial_minor INTEGER,final_minor INTEGER,price_state TEXT,
observed_at TEXT,source TEXT,
PRIMARY KEY(appid,region,observed_at,source))""") columns =list(rows[0]) db.executemany("INSERT OR REPLACE INTO prices VALUES(?,?,?,?,?,?,?,?,?)",[tuple(row[k]for k in columns)for row in rows])defnews(appid): query = urlencode(dict(appid=appid, count=3, maxlength=200,format="json")) request = Request("https://api.steampowered.com/ISteamNews/GetNewsForApp/v2/?"+ query, headers={"User-Agent":"GameResearchDemo/1.0"})with urlopen(request, timeout=20)as response: payload = json.load(response) data = payload.get("appnews",{})ifint(data.get("appid",-1))!= appid:raise ValueError("Неожиданный ответ новостей")return data.get("newsitems",[])if __name__ =="__main__": parser = argparse.ArgumentParser() parser.add_argument("--fixture", default="steam_prices_fixture.json") parser.add_argument("--db", default="steam.sqlite") parser.add_argument("--news",type=int) args = parser.parse_args()if args.news:print(json.dumps(news(args.news), ensure_ascii=False, indent=2))else: rows =[normalize(item)for item in json.loads(Path(args.fixture).read_text())]ifnot rows:raise SystemExit("Нет записей") save(rows, args.db) Path("steam_prices.json").write_text(json.dumps(rows, indent=2))withopen("steam_prices.csv","w", newline="")as handle: writer = csv.DictWriter(handle, fieldnames=list(rows[0])) writer.writeheader() writer.writerows(rows)print(f"принятых_записей={len(rows)}")
Сохраняйте форматированные строки цен как необязательные значения для отображения. Используйте нормализованные числовые суммы и валюту для сравнений. Никогда не выводите валюту только на основе местоположения или языка пользователя.
Шаг 5: Добавление обработки ошибок и ограничения по частоте запросов
Обрабатывайте недействительные идентификаторы приложений, неподходящие JSON ответы, ошибки HTTP, тайм-ауты, недоступные регионы и отсутствующие поля как явные ошибки или состояния.
Пример делает один ограниченный запрос новостей и останавливается при ошибке. Одобренный источник адаптера в производстве должен добавить небольшой бюджет на повторные попытки для временных сбоев, уважать Retry-After и избегать повторных попыток при ошибках разрешения. Никакая скорость запросов не гарантируется приемлемой для всех интерфейсов Steam.
Шаг 6: Сбор данных со страниц магазина Steam, когда API недостаточно
Используйте HTML только в тех случаях, когда ваше соглашение о доступе это позволяет. Проверьте, присутствуют ли структурированные поля в документе, прежде чем запускать браузер.
Разработайте парсер на основе сохраненного авторизованного HTML и протестируйте случаи отсутствующих цен, бесплатных игр, DLC и регионально недоступных товаров. Не пытайтесь обойти проверку по возрасту, требования к входу или явный отказ. Если доступ к ценам не утвержден, используйте лицензированный набор данных или соответствующий интерфейс партнера вместо этого.
Запланируйте в соответствии с разрешениями и требованиями к свежести выбранного источника, используя задокументированную систему мониторинга цен. Ежедневная утвержденная лента может быть достаточной для исследовательской панели; она не предоставляет исполнение цен в момент транзакции.
Сохраняйте наблюдения с учетом времени UTC и идентификации источника. Рассматривайте изменение только между сопоставимыми предложениями. Подайте сигнал о неожиданном изменении валюты или отсутствии предложения, а не называйте это скидкой.
Пример скрипта Steam: Создайте трекер цен на игры
Запустите прилагаемую фикстуру, проверьте три нормализованных записи и подтвердите, что бесплатная запись остается равной нулю, а запись о недоступности остается пустой.
Чтобы обнаружить изменение цены, запросите последние два принятых наблюдения для одного и того же приложения, региона, валюты, источника и типа предложения. Сравнивайте окончательные суммы только в том случае, если обе имеют действительные состояния цен. Добавьте таблицу изменений, только для добавления, содержащую предыдущую сумму, новую сумму, временные метки и ссылки на доказательства.
Локальные проверки охватывают нормализацию, обработку пустых значений, экспорт и повторное хранение одного и того же снимка. Они не устанавливают точность цен Steam в реальном времени или текущие разрешения интерфейса.
Общие ошибки и исправления при сборе данных Steam
Симптом
Возможное объяснение
Правильное лечение
Нет цены
Бесплатно, недоступно, не раскрыто или не удалось извлечь
Сохраняйте различное состояние и рассматривайте доказательства
Разные суммы
Несоответствие региона/валюты/пакета
Сравните совпадающие идентификаторы
Отсутствует разработчик
Источник не предоставляет поле
Оставьте пустым; не выводите
Изменен язык
Изменилась локализация или сессия
Сохраняйте локализацию с наблюдением
Пустой ответ
Неверный идентификатор, проблема с методом или сбой источника
Оставьте сбой вне принятых наблюдений
Внезапная "бесплатная" игра
Пропущенное значение приведено к нулю
Исправьте валидацию и восстановите затронутые записи
Сбор данных Steam в больших масштабах: Архитектура и затраты
Для развертывания в производстве разделите обнаружение, стабильные метаданные, изменяющиеся предложения, нормализацию и отчетность. Кэшируйте стабильные поля, обновляйте только утвержденную группу предложений и сохраняйте неудавшиеся задания с ограниченным количеством повторов.
Бюджетируйте лицензированные данные, запросы, рендеринг при необходимости, хранение, обслуживание и обзор источника. Использование Nstdata Crawl для утвержденного пути страницы может предоставить инфраструктуру для приобретения; оно не предоставляет права на данные, специфичные для Steam, или гарантированную схему цен.
Подтвердите разрешение интерфейса, условия API, атрибуцию, кэширование, перераспределение и условия коммерческого использования перед развертыванием. Не расширяйте доступность метода до разрешения на сбор незадействованных данных пользователя.
Держите личные данные игроков вне проекта, связанного с ценами в магазине, если это явно не необходимо и не получено соответствующее разрешение. Исследование цен на продукты не требует профилей игроков или активности аккаунта.
Итоговый контрольный список проекта
Проверьте идентификаторы приложений и идентичности предложений, сохраните региональный контекст, различайте отсутствующие и бесплатные, протестируйте экспорт, подтвердите сохранность снимков и пересмотрите условия доступа. Подключите источник живых цен только после того, как локальный импортёр и соглашение о использовании данных будут оба проверены.
Проверьте разрешенный контент магазина
Сохраняйте утвержденное приобретение отдельно от парсинга, специфичного для игр, и прав на источник.
Да. Valve документирует методы Steam Web API, но это не означает поддержку общего конечного пункта цены для каждого использования.
В: Как я могу получить цены на игры в Steam?
Используйте одобренный интерфейс или лицензированный источник, который охватывает нужные вам поля, регионы и использование. Этот проект нормализует этот вход и тестирует его с помощью фикстуры.
В: Содержит ли образец фактические цены на игры?
Нет. Поставленные записи цен и идентификаторы приложений являются синтетическими, четко обозначенными тестовыми данными.
В: Могу ли я отслеживать скидки?
Да, если источник допускает мониторинг и доступны сопоставимые записи предложений. Сохраняйте валюту, регион, пакет и временные метки последовательными.
В: Почему appdetails не используется как контракт для живого учебника?
Конечная точка, ориентированная на торговую площадку, не должна представляться как полностью документированный, авторизованный общий API цен, только потому что к ней можно получить доступ.
В: Может ли задокументированный метод новостей заменить источник цен?
Нет. Новости и цены в магазине — это разные наборы данных, и они должны сохранять отдельные схемы и разрешения.
Lena Zhou
Oct. 19th 2026
Сканируйте целые сайты одним API-запросом
Успешность 99,8% с рендерингом JavaScript
Получайте чистые данные для LLM в разных форматах
Преобразуйте любой сайт в Markdown, HTML, JSON, ссылки, PDF и другие форматы без управления инфраструктурой сканирования.