この記事でできること:
Steamの公式Web APIを使って、AppIDの解決→同時接続(CCU)→実績の到達率/スキーマ→ニュースまでを最小コードで確認します。
目的と合格基準(ゴール)を各サンプルの冒頭に明示し、出力の読み方もセットで解説します。
事前準備:Step1: AppIDを見つける|Web APIキーの取得と保管|全体像はSteamガイド
対象エンドポイントと認証の要点
| 目的 | エンドポイント | APIキー | メモ |
|---|---|---|---|
| 全アプリ一覧(AppID解決の起点) | ISteamApps/GetAppList | 不要 | レスポンスが大きい→キャッシュ推奨 |
| 同時接続(現在値) | ISteamUserStats/GetNumberOfCurrentPlayers | 不要 | スナップショット。履歴は自前収集 |
| 実績の到達率(グローバル) | ISteamUserStats/GetGlobalAchievementPercentagesForApp | 不要 | 各実績の解除率(%) |
| 実績スキーマ(名称/説明/アイコン) | ISteamUserStats/GetSchemaForGame | 必要 | キー必須の代表 |
| ニュース(パッチ/お知らせ) | ISteamNews/GetNewsForApp | 不要 | タイトル・URL 等 |
キーが必要な場面では ?key=YOUR_STEAM_WEB_API_KEY を付与(取得と安全な保管を参照)。
クイックスタート(Python最小クライアント)
目的: 任意タイトルのAppID→CCU→実績→ニュースを1本のスクリプトで取得できることを確認する。
合格基準: 実行すると以下が得られること。
① candidates: に目当てのタイトルと AppID が含まれる/② ccu: が整数/③ achv_rates(sample): が配列(空でも可)/④ achv_total: が整数(0も可)/⑤ ニュースのタイトル配列(空でも可)
コピペ用(requestsのみ・依存最小)
import os, json, time, difflib, requests, configparser
from pathlib import Path
BASE = "https://api.steampowered.com"
# --- APIキーの読込(環境変数 → config.ini の順で探す。既存方針と整合) ---
def load_steam_api_key(config_path=None):
key = os.getenv("STEAM_WEB_API_KEY")
if key and key.strip():
return key.strip()
# config.ini の候補パス(必要に応じて変更)
paths = [config_path] if config_path else [
r"D:\Python\config\config.ini",
"config.ini"
]
cfg = configparser.ConfigParser()
for p in paths:
if not p: continue
if cfg.read(p, encoding="utf-8"):
# 優先順:[steam]/API_KEY → [DEFAULT]/API_KEY → [DEFAULT]/STEAM_WEB_API_KEY
for sect, opt in [("steam","API_KEY"), ("DEFAULT","API_KEY"), ("DEFAULT","STEAM_WEB_API_KEY")]:
if cfg.has_option(sect, opt):
val = cfg.get(sect, opt).strip()
if val: return val
return None # キー不要APIのみ使うならNoneでも実行可
API_KEY = load_steam_api_key()
def _get(url, params=None, timeout=30):
"""共通HTTP: APIキー自動付与 + 簡易リトライ + エラー可視化"""
params = dict(params or {})
if API_KEY and "key" not in params:
params["key"] = API_KEY
last = None
for i in range(3):
try:
r = requests.get(url, params=params, timeout=timeout)
r.raise_for_status()
ct = (r.headers.get("Content-Type") or "").lower()
if "json" not in ct:
snip = (r.text or "")[:200].replace("\n"," ")
raise RuntimeError(f"Non-JSON response: {r.status_code} {ct} body[:200]={snip!r}")
return r.json()
except Exception as e:
last = e
if i == 2: raise
time.sleep(0.8*(i+1))
# 1) 全アプリ一覧(キャッシュ)
def get_applist(cache="applist.json", force_refresh=False):
p = Path(cache)
if not force_refresh and p.exists() and p.stat().st_size > 0:
return json.loads(p.read_text(encoding="utf-8"))
url = f"{BASE}/ISteamApps/GetAppList/v2/"
apps = _get(url)["applist"]["apps"]
p.write_text(json.dumps(apps, ensure_ascii=False), encoding="utf-8")
return apps
# 2) 名前→AppID(簡易あいまい一致:英語名に強い)
def resolve_appid_by_name(name, apps=None, n=5):
apps = apps or get_applist()
names = [a["name"] for a in apps if a.get("name")]
cands = difflib.get_close_matches(name, names, n=n, cutoff=0.6)
out = []
for c in cands:
appid = next(a["appid"] for a in apps if a.get("name")==c)
out.append((c, appid))
return out
# 3) 同時接続(現在のスナップショット)
def get_ccu(appid:int):
url = f"{BASE}/ISteamUserStats/GetNumberOfCurrentPlayers/v1/"
return _get(url, {"appid": appid}).get("response", {}).get("player_count")
# 4) 実績の到達率(グローバル%)
def get_global_achievement_rates(appid:int):
url = f"{BASE}/ISteamUserStats/GetGlobalAchievementPercentagesForApp/v2/"
return _get(url, {"gameid": appid}).get("achievementpercentages", {}).get("achievements", [])
# 5) 実績スキーマ(名称/説明/アイコンURL等)※キー必須
def get_schema_for_game(appid:int, lang="japanese"):
if not API_KEY:
raise RuntimeError("GetSchemaForGame には APIキーが必要です(/steam-web-api-key/ を参照)")
url = f"{BASE}/ISteamUserStats/GetSchemaForGame/v2/"
return _get(url, {"appid": appid, "l": lang}).get("game", {})
# 6) ニュース(最新見出し)
def get_news(appid:int, count=3, maxlength=300):
url = f"{BASE}/ISteamNews/GetNewsForApp/v2/"
return _get(url, {"appid": appid, "count": count, "maxlength": maxlength}).get("appnews", {}).get("newsitems", [])
if __name__ == "__main__":
# ① まず英語名で候補(AppID)を出す
apps = get_applist(force_refresh=True) # 初回は更新推奨
name = "HoloCure" # ← 例。日本語名は非対応
cands = resolve_appid_by_name(name, apps)
print("candidates:", cands[:3])
# ② 先頭候補のAppIDで主要指標を確認
if cands:
appid = cands[0][1]
print("ccu:", get_ccu(appid))
print("achv_rates(sample):", get_global_achievement_rates(appid)[:3])
schema = get_schema_for_game(appid)
total = len((schema.get("availableGameStats") or {}).get("achievements", []))
print("achv_total:", total)
news = get_news(appid)
print([n["title"] for n in news])
実行結果を確認
candidates: [('Holodrive', 370770), ('Colourise', 576820), ('ColorCube', 2066920)]
ccu: 2
achv_rates(sample): [{'name': 'PLAY_MATCH_1', 'percent': '43.2'}, {'name': 'ACTIVATE_POWERUP_5', 'percent': '23.3'}, {'name': 'ACTIVATE_POWERUP_20', 'percent': '12.6'}]
achv_total: 30
['Playtest our New Game - Atomic Picnic!', 'Haloween sale 50%!!!', 'White screen freeze bugfix is live! (Stuck on Game in Development screen)']
出力の読み方:
・candidates…(正式名, AppID) の候補。ここで目当てが見つかれば第一関門クリア。
・ccu…現在の同時接続(瞬間値)。0 でも異常ではありません。
・achv_rates…実績ごとの到達率(%)。サンプルとして先頭3件のみ表示。
・achv_total…そのタイトルの実績総数。0 なら「実績なし」。
・ニュース…最新タイトル一覧。空なら最近の配信が無いだけです。
ここまで揃えばキー設定・通信ともに正常と判断してOKです。
ユースケース別の実装パターン
A. CCUを複数タイトルで一括取得(瞬間スナップショット)
目的: 複数AppIDの現時点CCUを一括で取得し、のちの可視化・時系列化の素材にする。
合格基準: 各行に {"appid": ..., "ccu": 整数, "ts": UNIX時刻} が出力される。
APPIDS = [570, 730, 1172470] # 例:Dota2, CS2, Apex
rows = []
for aid in APPIDS:
rows.append({"appid": aid, "ccu": get_ccu(aid), "ts": int(time.time())})
print(rows)
実行結果を確認
[{'appid': 570, 'ccu': 657421, 'ts': 1760822633}, {'appid': 730, 'ccu': 1067554, 'ts': 1760822633}, {'appid': 1172470, 'ccu': 58024, 'ts': 1760822633}]
# 時系列化したい場合は定期的に同じ形式で保存していく必要があります。
import csv, time
APPIDS = [570, 730, 1172470]
rows = [{"appid": aid, "ccu": get_ccu(aid), "ts": int(time.time())} for aid in APPIDS]
with open("ccu_log.csv", "a", newline="", encoding="utf-8") as f:
w = csv.DictWriter(f, fieldnames=["ts","appid","ccu"])
if f.tell() == 0: # 新規ファイルならヘッダ
w.writeheader()
w.writerows(rows)
B. 実績の「解除率トップ3」で難易度の雰囲気を掴む
目的: プレイヤーの到達率が高い実績TOP3を見て、難易度の“匂い”を掴む。
合格基準: 3行の 実績内部名 percent が表示される(%は文字列)。
rates = get_global_achievement_rates(appid)
top3 = sorted(rates, key=lambda x: -float(x.get("percent", 0)))[:3]
for a in top3:
print(a["name"], a["percent"])
実行結果を確認
PLAY_MATCH_1 43.2
ACTIVATE_POWERUP_5 23.3
ACTIVATE_POWERUP_20 12.6
C. 実績スキーマからアイコンURLを取得(記事素材に)
目的: 表示名とアイコンURL(icon/icongray)を取り出し、記事やカードに使う。
合格基準: displayName と icon のURLが表示される(ゲームに実績が無ければ空)。
schema = get_schema_for_game(appid)
ach = (schema.get("availableGameStats") or {}).get("achievements", [])
if ach:
print(ach[0]["displayName"], ach[0]["icon"])
実行結果を確認
First https://steamcdn-a.akamaihd.net/steamcommunity/public/images/apps/370770/20d1285cfe2d3319aa2685e0423683345ac1c711.jpg
D. ニュースをカード表示用に整形
目的: タイトル・URL・公開時刻を配列にし、フロント側カードへ流し込む。
合格基準: [{"title": "...", "url": "...", "date": ...}, ...] の配列が取れる。
news = get_news(appid, count=5, maxlength=220)
cards = [{"title": n["title"], "url": n["url"], "date": n.get("date")} for n in news]
print(cards)
実行結果を確認
[{'title': 'Playtest our New Game - Atomic Picnic!', 'url': 'https://steamstore-a.akamaihd.net/news/externalpost/steam_community_announcements/5395938616813762561', 'date': 1702412705}, {'title': 'Haloween sale 50%!!!', 'url': 'https://steamstore-a.akamaihd.net/news/externalpost/steam_community_announcements/2403127338447603461', 'date': 1540917033}, {'title': 'White screen freeze bugfix is live! (Stuck on Game in Development screen)', 'url': 'https://steamstore-a.akamaihd.net/news/externalpost/steam_community_announcements/2447035533299200900', 'date': 1538770932}, {'title': 'Halloween is here!', 'url': 'https://steamstore-a.akamaihd.net/news/externalpost/steam_community_announcements/3167611029765269230', 'date': 1538507332}, {'title': "Free Rare Holopacks for All! It's BitCake's Birthday!", 'url': 'https://steamstore-a.akamaihd.net/news/externalpost/steam_community_announcements/2842216343267763090', 'date': 1529170408}]
つまずきやすいポイント(Q&A)
- JSONDecodeError / Non-JSON:
GetSchemaForGameにキーが付いていない可能性。キー取得と保管を再確認。 - 候補に目当てが出ない:
applist.jsonが古いか、英語名と表記が離れている可能性。AppIDの見つけ方(storesearchルート)を参照。 - CCUが0:異常ではありません。瞬間的にプレイヤーがいないだけ。履歴にしたい場合は自前で定期収集。
この先に進む(関連How-to)
- 【How-to】価格・タグ・発売情報を取る(Storefront appdetails)
- 【How-to】レビュー本文の取得と要約(appreviews)
- 【前提】Web APIキーの取得と安全な保管
入口に戻る:Steamガイド / 前の記事:AppIDを見つける5つの方法
免責:本記事は公開情報の整理を目的としています。仕様や挙動は予告なく変わる可能性があります。最新の利用規約をご確認のうえご利用ください。