App StoreとGoogle Playのレビューをスクレイピング: エンドポイント、制限、地域
アプリのレビューは、最も安価な製品調査です - ページネーションの制限、トークンの壁、国ごとのストアフロントを乗り越えられれば。ここに全体の地図があります。
アプリのレビューは、最も安価な顧客調査です: フィルタリングされていない機能リクエスト、特定のバージョンに関連するバグレポート、そしてカテゴリ内のすべての競合他社に対する感情の流れを読み取ることができます。問題はアクセスです。両方のストアはページに少数のレビューを表示し、残りはフィード、トークン、国ごとのストアフロントの背後に隠されています。このガイドは、App StoreとGoogle Playのレビューをスクレイピングする方法を示しています - 本当のエンドポイント、誰も警告しないページネーションの制限、そして数百行以上のパイプラインが生き残るかどうかを決める地域とレート制限の現実。
Apple、簡単な方法: RSSフィード
Appleはトークンを必要としない顧客レビューの公開JSONフィードを提供しています。これは最も速く始める方法で、クリーンで構造化されたレコードを返します - 評価、タイトル、本文、著者、アプリバージョン。制限は厳しい上限です: フィードは最大で約50レビューの10ページを提供するので、アプリごとにストアフロントあたり約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、深い方法: app-store APIとそのトークン
500を超えるためには、App Storeのウェブページが呼び出すのと同じエンドポイント(AMP / MZStore API)を使用します。これにより、より豊富なレコードが返されます - レビューID、編集フラグ、開発者の応答 - しかし、最初にアプリの公開ウェブページからスクレイピングしたベアラートークンを必要とし、それを再生します。レビューは約20件のバッチで届き、offsetでさらにページネーションします; offsetが大きいほど、レビューは古くなる傾向があります。なぜなら、Appleはこのエンドポイントで日付順にソートすることを直接許可していないからです。
ここでの本当の制約はレート制限であり、単一のIPからすぐに到達します。解決策は魔法ではなく、意図的な遅延と指数バックオフ、そしてIPをまたいでリクエストを分散させることです。両方を追加した実践者は、リミッターに引っかかることなく1つのアプリで約15,000件のレビューを引き出しました。そこで回転する住宅用プールが役立ちます: 各バッチは異なるクリーンな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

Google Play: HTMLではなく、ハイドレートされたJSON
PlayのレビューはページHTMLにありません。ストアは内部バッチエンドポイントを通じてそれらをロードし、ネストされたJSONを返し、ページ番号ではなく継続トークンでページネーションし、ソート順(最新、評価、役立ち度)でフィルタリングします。これらのリクエストを手動で再構築するのは面倒なので、ほとんどのチームはエンドポイントをラップし、countryとlangパラメータを公開する、よくメンテナンスされたオープンソースのgoogle-play-scraperライブラリ(NodeとPython)に頼っています。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としてレンダリングして返すことで、両方の問題を解消します - プロキシングとパースを担い、安定した形状を消費できます。プロキシを使用した大規模な製品レビューのスクレイピングに関して説明したのと同じトレードオフロジックがここに直接適用されます。
1つのフィールドペアが人々を引っ掛けます: 言語と国は同じノブではありません。ストアフロント(国)はどのレビューが存在するかを決定し、言語パラメータはどれを返すかを決定します。カナダやスイスのようなバイリンガル市場では、しばしば両方の言語が必要なので、国が単一の言語を意味すると仮定するのではなく、それらを独立して設定してください。Apple側では、より豊富なレコードが開発者の応答も公開します - レビューの下にベンダーが投稿する公開返信 - これは競合他社が苦情をどのようにトリアージし、どの問題に公開的に回答することを選ぶかの静かに価値のあるシグナルです。
地域ストアフロントが全てのポイント
両方のストアは国ごとのストアフロントで構成され、2文字のコードでキー付けされています。アプリの米国レビューは、ドイツ、日本、ブラジルでどのように受け入れられるかについて何も教えてくれません - 異なる言語、異なる苦情、異なる機能ギャップ。各ストアフロントを正直に読むには、その国の出口IPからリクエストします; 間違った地域のデータセンターIPは一貫性のないまたはブロックされた応答を得ます。200以上の国にわたる住宅用出口で、同じアプリをすべての市場にループさせ、国ごとの感情マップを構築できます - 真剣なASO作業の原材料。

レビューからASOシグナルへ
抽出は退屈な半分です。報酬はその上で計算するものです: レビューテキストを繰り返しテーマにクラスター化し、評価を落としたリリースを捕捉するためにアプリバージョンごとに感情を追跡し、製品がすでに回答している機能リクエストを競合他社のために監視し、ストアフロント間で苦情パターンを比較します。すべてのレビューをそのversionフィールドに結びつけると、分析ダッシュボードが提供しない回帰タイムラインを得ることができます。関連する評判の作業 - Trustpilotレビューのマイニング - は、アプリストアデータと並んで完全な顧客の声の絵を描きます。
よくある質問
PythonでApp Storeのレビューをスクレイピングするにはどうすればいいですか?
Appleの公開RSS顧客レビューJSONフィードから始めます - トークン不要、構造化出力、ただしアプリごとにストアフロントあたり約500の最近のレビューで制限されています。さらに深く行くには、アプリのウェブページからスクレイピングしたベアラートークンでAMP app-store APIを呼び出し、offsetでページネーションし、遅延とバックオフを追加します。各ストアフロントをその国の住宅用IPを通じてルートします。
公式のApp StoreレビューAPIはありますか?
Appleの公開RSSフィードは、公式のトークン不要のレビューソースに最も近いものですが、制限されています。より豊富なAMPエンドポイントは、ストアのウェブページが使用するもので、スクレイピングされたベアラートークンを必要とします。どちらも、大量のサードパーティレビュー収集のための文書化された開発者製品ではないので、レート制限と条件を注意深く扱ってください。
Google Playのレビューをスクレイピングするにはどうすればいいですか?
Playは内部バッチエンドポイントからネストされたJSONを返し、継続トークンでページネーションし、ソート順でフィルタリングします。メンテナンスされたオープンソースのgoogle-play-scraperライブラリがそれをラップし、countryとlangを公開します。両方を設定し、継続トークンをループしてボリュームを増やし、エンドポイントがアドレスごとにスロットルするので、IPをまたいでリクエストを分散させます。
なぜアプリレビューをスクレイピングするのにプロキシが必要なのですか?
2つの理由があります。レート制限: 両方のストアは単一のIPをすぐにスロットルするので、回転する住宅用出口はIPごとのカウンターを低く保ち、数千のレビューを引き出すことができます。地理: レビューはストアフロント固有であるため、国のレビューを正確に読むには、その国のIPからリクエストする必要があります。間違った地域のデータセンターIPは一貫性のないまたはブロックされた応答を得ます。
App-storeデータは、3つの単純な障害 - 制限、トークン、ストアフロント - によってゲートされた金鉱です。どのエンドポイントを叩くか、正しくページネーションし、クリーンなIPで適切な国から出るかを知れば、散在する星評価をバージョンごと、市場ごとの顧客の声のフィードに変えることができます。