この記事でできること:Steamでデータ取得を始める前段として、AppID(数値)を確実に特定する方法をまとめます。URLからの即判定、名前からの公式APIによる照合、appdetails を使った最終確認、さらに Pythonでの一括解決(CSVバッチ) まで、実務フローで解説します。
このガイドは Steamガイド(入口ページ) の「Step1: AppID取得」に対応しています。
そもそもAppIDとは?
AppIDはSteamで各アプリ(ゲーム・DLC・ソフト等)に割り当てられた一意の数値IDです。レビュー取得(/appreviews)、ストア情報(/api/appdetails)、同時接続(GetNumberOfCurrentPlayers)など、ほぼすべての取得でキーとして使います。
- ゲーム本体:type=
game - DLC:type=
dlc - サウンドトラック等:type=
musicなど
注意:記事・分析の対象が「ゲーム本体」かどうかを、後述の appdetails で検証しましょう(DLC/バンドルを誤って選ばない)。
方法1:ストアURLから直取り(最短)
ストアURLが分かっていれば、https://store.steampowered.com/app/730/... の太字部分がAppIDです。記事からの引用や検索結果でURLを見つけたら、これが最速。 Pythonワンライナー(URL → AppID抽出)
import re
from urllib.parse import urlparse
def appid_from_url(url: str) -> int | None:
path = urlparse((url or "").strip()).path
# /app/<id>/ も /agecheck/app/<id>/ も許容
m = re.search(r"/(?:(?:agecheck|widget)/)?app/(\d+)(?:/|$)", path, flags=re.IGNORECASE)
return int(m.group(1)) if m else None
# --- URLを以下に入力 ---
url = "https://store.steampowered.com/app/2246340/_/"
appid = appid_from_url(url)
print("AppID:", appid) if appid else print("AppIDが見つかりませんでした")
実行結果を確認
AppID: 2246340
方法2:公式APIの全アプリ一覧(ISteamApps)から名前検索
ゲーム名しか分からないときは、公式の全アプリ一覧を取得してローカルで名前マッチさせます。スペル差や表記揺れに備えてあいまい一致が便利。 最小コード(名前 → 候補AppID)
import requests, difflib, unicodedata, re
def load_applist():
url = "https://api.steampowered.com/ISteamApps/GetAppList/v2/"
return requests.get(url, timeout=60).json()["applist"]["apps"]
def storesearch(query: str, cc="jp", lang="japanese", n=5):
r = requests.get(
"https://store.steampowered.com/api/storesearch/",
params={"term": query, "l": lang, "cc": cc},
timeout=30
).json()
items = r.get("items") or []
out = []
for it in items:
aid = it.get("id") or it.get("appid")
nm = it.get("name")
ty = it.get("type") # "app", "sub" など。必要なら "app" のみに絞る
if aid and nm and (ty in (None, "app")):
out.append((nm, int(aid)))
if len(out) >= n:
break
return out
def appdetails_type(appid: int, cc="jp", lang="japanese"):
r = requests.get(
"https://store.steampowered.com/api/appdetails",
params={"appids": appid, "cc": cc, "l": lang},
timeout=30
).json()
node = r.get(str(appid), {})
if node.get("success") and node.get("data"):
return node["data"].get("type")
return None
def find_appid_by_name(query: str, apps: list[dict], n=5):
# 日本語など非ASCIIが含まれるときは storesearch を優先
if re.search(r"[^\x00-\x7f]", query):
res = storesearch(query, n=n)
# 必要なら "game" のみ残す
filtered = []
for nm, aid in res:
ty = appdetails_type(aid)
if ty == "game":
filtered.append((nm, aid))
return filtered or res # 全滅したら未フィルタを返す
# ASCII なら従来どおり英語名にあいまい一致
name_map = {a["name"]: a["appid"] for a in apps if a.get("name")}
names = list(name_map.keys())
def _norm(s): return unicodedata.normalize("NFKC", s or "").casefold()
names_norm = [_norm(x) for x in names]
target = _norm(query)
cand_norms = difflib.get_close_matches(target, names_norm, n=n, cutoff=0.6)
if not cand_norms:
cand_norms = [nm for nm in names_norm if target in nm][:n]
out = []
for cn in cand_norms:
i = names_norm.index(cn)
formal = names[i]
out.append((formal, name_map[formal]))
return out
# --- ユーザーがここを書き換えるだけ ---
query = "モンスターハンター"
apps = load_applist() # 英語名用のフォールバックに使う
candidates = find_appid_by_name(query, apps, n=5)
for name, appid in candidates:
print(appid, "-", name)
# 期待例:
# 2246340 - モンスターハンター ワイルズ
# 582010 - Monster Hunter: World
# ...(環境により順序は前後します)
実行結果を確認
2246340 - モンスターハンターワイルズ
582010 - モンスターハンター:ワールド
1446780 - モンスターハンターライズ
2356560 - モンスターハンターストーリーズ
2852190 - モンスターハンターストーリーズ3 ~運命の双竜~
ポイント:正式名に近い候補を複数出す→ 次の「方法3」で型(game/dlc)や発売日を確認して確定。
方法3:appdetails で最終確認(型/発売日/価格など)
候補のAppIDは appdetails(非公開仕様のストアAPI)で型が game か、発売日、価格/無料、対応OS、タグ などを確認し、対象が本体かを見極めます。 最小コード(AppID → メタ確認)
import requests, json
def appdetails(appid: int, cc="jp", lang="japanese") -> dict:
"""Storefront appdetails を取得。success=False のときは空dictを返す。"""
url = "https://store.steampowered.com/api/appdetails"
r = requests.get(url, params={"appids": appid, "cc": cc, "l": lang}, timeout=30).json()
node = r.get(str(appid), {}) or {}
if not node.get("success"):
return {}
return node.get("data") or {}
# --- ユーザーはここだけ差し替えればOK ---
appid = 2246340 # モンスターハンター ワイルズ
meta = appdetails(appid)
if not meta:
print("データが取得できませんでした(地域/年齢制限・一時障害の可能性)。")
else:
# 基本情報
name = meta.get("name")
app_type = meta.get("type") # "game", "dlc", "software" など
release = (meta.get("release_date") or {}).get("date")
coming_soon = (meta.get("release_date") or {}).get("coming_soon")
price = meta.get("price_overview") or {}
print("タイトル:", name)
print("タイプ:", app_type)
print("発売日:", release, "(coming_soon:", coming_soon, ")")
print("price_overview:")
print(json.dumps(price, ensure_ascii=False, indent=2)) # 見やすく整形実行結果を確認
タイトル: モンスターハンターワイルズ
タイプ: game
発売日: 2025年2月27日 (coming_soon: False )
price_overview:
{
"currency": "JPY",
"initial": 899000,
"final": 899000,
"discount_percent": 0,
"initial_formatted": "",
"final_formatted": "¥ 8,990"
}
非公開仕様のため将来変更の可能性に注意。実装はタイムアウト・リトライ・バリデーションを入れるのが実務的です。
方法4:名前からの自動解決関数(あいまい一致 → appdetails検証)
方法2と3を統合し、名前→AppID→型検証を一発で返す関数にしておくと再利用が効きます。DLC/サントラの誤選択を防ぐため、type=="game" を既定でフィルタ。 コピペ用(Python)
import re, requests, difflib
def resolve_app(name: str | None = None,
appid: int | None = None,
require_game: bool = True,
cc: str = "jp",
lang: str = "japanese"):
def _details(aid: int):
r = requests.get("https://store.steampowered.com/api/appdetails",
params={"appids": aid, "cc": cc, "l": lang}, timeout=30).json()
node = r.get(str(aid), {}) or {}
return node.get("data") if node.get("success") else None
# 1) appid 優先
if appid:
d = _details(appid)
if not d: return appid, None
return (None, d) if (require_game and d.get("type")!="game") else (appid, d)
# 2) name から解決(日本語→storesearch、英語→GetAppList)
if not name: return None, None
# 日本語等(非ASCII)→ storesearch
if re.search(r"[^\x00-\x7f]", name):
s = requests.get("https://store.steampowered.com/api/storesearch/",
params={"term": name, "l": lang, "cc": cc}, timeout=30).json()
for it in (s.get("items") or []):
aid = it.get("id") or it.get("appid")
if not aid: continue
d = _details(int(aid)) or {}
if not require_game or d.get("type")=="game":
return int(aid), d
return None, None
# 英語系 → GetAppList + difflib
apps = requests.get("https://api.steampowered.com/ISteamApps/GetAppList/v2/", timeout=60).json()["applist"]["apps"]
names = [a["name"] for a in apps if a.get("name")]
cand = difflib.get_close_matches(name, names, n=1, cutoff=0.6)
if not cand: return None, None
aid = next(a["appid"] for a in apps if a.get("name")==cand[0])
d = _details(aid)
if not d: return aid, None
return (None, d) if (require_game and d.get("type")!="game") else (aid, d)
# --- ユーザーはここだけ差し替えればOK ---
appid = 2246340 # 例:モンスターハンター ワイルズ
name = None # appid を使うので None のままでOK
aid, meta = resolve_app(name=name, appid=appid)
if aid is None:
# type != "game" などのときはこちらに来る
print("ゲーム本体ではありませんでした:", meta and meta.get("type"))
elif not meta:
print("appdetails を取得できませんでした(地域/年齢制限・一時障害の可能性)。")
else:
print("AppID:", aid)
print("タイトル:", meta.get("name"))
print("type:", meta.get("type"))実行結果を確認
AppID: 2246340
タイトル: モンスターハンターワイルズ
type: game
方法5:複数タイトルを一括解決
タイトルリストをリストで一括解決するのが効率的です。
import requests, difflib, unicodedata, re, time
def resolve_list(queries: list[str],
require_game=True,
top_k=1,
sleep_each=0.35) -> list[dict]:
def _norm(s): return unicodedata.normalize("NFKC", s or "").casefold()
# 英語用の対応表(フォールバック)
apps = requests.get("https://api.steampowered.com/ISteamApps/GetAppList/v2/", timeout=60).json()["applist"]["apps"]
name_map = {a["name"]: a["appid"] for a in apps if a.get("name")}
names = list(name_map.keys())
names_norm= [_norm(x) for x in names]
def details(aid:int, cc="jp", lang="japanese"):
r = requests.get("https://store.steampowered.com/api/appdetails",
params={"appids": aid, "cc": cc, "l": lang}, timeout=30).json()
n = r.get(str(aid), {}) or {}
return n.get("data") if n.get("success") else {}
out = []
for q in queries:
q = (q or "").strip()
if not q: continue
cands = []
if re.search(r"[^\x00-\x7f]", q): # 日本語など
s = requests.get("https://store.steampowered.com/api/storesearch/",
params={"term": q, "l":"japanese", "cc":"jp"}, timeout=30).json()
for it in (s.get("items") or []):
aid = it.get("id") or it.get("appid")
nm = it.get("name")
ty = it.get("type")
if aid and nm and (ty in (None, "app")):
cands.append((nm, int(aid), 1.0, "storesearch"))
if len(cands) >= max(3, top_k): break
else:
t = _norm(q)
cand_norms = difflib.get_close_matches(t, names_norm, n=max(3, top_k), cutoff=0.6)
for cn in cand_norms:
i = names_norm.index(cn)
nm = names[i]; aid = name_map[nm]
score = difflib.SequenceMatcher(None, t, cn).ratio()
cands.append((nm, aid, score, "applist"))
if not cands:
out.append({"query": q}); continue
wrote = 0
for nm, aid, score, src in cands:
d = details(aid) or {}
ty = d.get("type")
if require_game and ty != "game":
time.sleep(sleep_each); continue
out.append({
"query": q, "matched_name": d.get("name") or nm, "appid": aid,
"type": ty, "release_date": (d.get("release_date") or {}).get("date"),
"match_score": round(float(score),3) if score is not None else None,
"source": src
})
wrote += 1
time.sleep(sleep_each)
if wrote >= top_k: break
if wrote==0:
nm, aid, score, src = cands[0]; d = details(aid) or {}
out.append({
"query": q, "matched_name": d.get("name") or nm, "appid": aid,
"type": d.get("type"),
"release_date": (d.get("release_date") or {}).get("date"),
"match_score": round(float(score),3) if score is not None else None,
"source": src
})
time.sleep(sleep_each)
return out
# 使い方
rows = resolve_list(["HoloCure", "Palworld", "モンスターハンター"])
for r in rows: print(r)
実行結果を確認
{'query': 'HoloCure', 'matched_name': 'LOCURA', 'appid': 2492990, 'type': 'game', 'release_date': '2023年9月6日', 'match_score': 0.714, 'source': 'applist'}
{'query': 'Palworld', 'matched_name': 'Palworld / パルワールド', 'appid': 1623730, 'type': 'game', 'release_date': '2024年1月18日', 'match_score': 1.0, 'source': 'applist'}
{'query': 'モンスターハンター', 'matched_name': 'モンスターハンターワイルズ', 'appid': 2246340, 'type': 'game', 'release_date': '2025年2月27日', 'match_score': 1.0, 'source': 'storesearch'}
よくある落とし穴と対処
- DLC/サントラを拾ってしまう:
appdetailsのtypeでgameを確認。記事テンプレでは game以外は除外。 - 表記揺れ:記号・サブタイトル違いで一致しない場合は、複数候補を出して人工確認。英語名で試すのも有効。
- 別プラットフォーム版:一部ツール/ソフトは
typeがsoftware。記事目的に合うか確認。 - レート制限:短時間に連打しない。タイムアウト・リトライ・スリープを実装。
- キャッシュ:
GetAppListはサイズが大きいのでローカルにキャッシュして再利用。
次のステップ
- 【How-to】公式Web APIの使い方(GetAppList / 同接 / 実績)
- 【How-to】appdetailsでストア情報を取る
- 【How-to】appreviewsでレビュー本文を取る
- 【How-to】同時接続の自前収集と可視化
- 【How-to】SteamSpyの推定値の扱い
入口に戻る:Steamガイド
免責とポリシー:appdetails/appreviews は公式ドキュメント外のエンドポイントを利用します。将来の仕様変更により挙動が変わる可能性があります。利用規約・法令・引用ルールを遵守の上でご利用ください。