App Store、Google Playにユーザーが書いたアプリのレビューを取得する方法を記述。
App Store上のiOSアプリのレビュー
RSSから取得できる。
手順
iTunes Connect でURLを確認
RSSのURLは形式が決まっている模様だが公式のドキュメントは見つからない。
一応iTunes ConnectでURLを確認できる。
- iTunes Connect からアプリを選択。
- アクティビティ を選択。
- 評価とレビュー を選択。
- RSSアイコンを選択し、RSSリンクをコピー。
URLの形式
https://itunes.apple.com/COUNTRYCODE/rss/customerreviews/id=APPID/sortBy=mostRecent/xml
- COUNTRYCODE: 国のコード。例:
jp
- APPID: アプリのID。例:
284882215
URL一例
例:FacebookアプリのレビューのRSSのURL:
https://itunes.apple.com/jp/rss/customerreviews/id=284882215/sortBy=mostRecent/xml
RSSの内容
Atom形式(XML)のRSSデータになっている。
先頭entry
はアプリ自体の情報が入っているので、2個目以降のentry
がレビュー内容になる。
<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:im="http://itunes.apple.com/rss" xml:lang="ja">
<id>https://itunes.apple.com/jp/rss/customerreviews/id=284882215/sortBy=mostRecent/xml</id>
<title>iTunes Store: カスタマーレビュー</title>
<updated>2017-02-28T23:11:37-07:00</updated>
<link rel="alternate" type="text/html" href="https://itunes.apple.com/WebObjects/MZStore.woa/wa/viewGrouping?cc=jp&id=1000" />
<link rel="self" href="https://itunes.apple.com/jp/rss/customerreviews/id=284882215/sortBy=mostRecent/xml" />
<link rel="first" href="https://itunes.apple.com/jp/rss/customerreviews/page=1/id=284882215/sortby=mostrecent/xml?urlDesc=/customerreviews/id=284882215/sortBy=mostRecent/xml" />
<link rel="last" href="https://itunes.apple.com/jp/rss/customerreviews/page=10/id=284882215/sortby=mostrecent/xml?urlDesc=/customerreviews/id=284882215/sortBy=mostRecent/xml" />
<link rel="previous" href="https://itunes.apple.com/jp/rss/customerreviews/page=1/id=284882215/sortby=mostrecent/xml?urlDesc=/customerreviews/id=284882215/sortBy=mostRecent/xml" />
<link rel="next" href="https://itunes.apple.com/jp/rss/customerreviews/page=2/id=284882215/sortby=mostrecent/xml?urlDesc=/customerreviews/id=284882215/sortBy=mostRecent/xml" />
<icon>http://itunes.apple.com/favicon.ico</icon>
<author>
<name>iTunes Store</name>
<uri>http://www.apple.com/jp/itunes/</uri>
</author>
<rights>Copyright 2008 Apple Inc.</rights>
<entry>
<updated>2017-02-28T23:11:37-07:00</updated>
<id im:id="284882215" im:bundleId="com.facebook.Facebook">https://itunes.apple.com/jp/app/facebook/id284882215?mt=8&uo=2</id>
<title>Facebook - Facebook, Inc.</title>
<im:name>Facebook</im:name>
<link rel="alternate" type="text/html" href="https://itunes.apple.com/jp/app/facebook/id284882215?mt=8&uo=2" />
<im:contentType term="Application" label="アプリケーション" />
<category im:id="6005" term="Social Networking" scheme="https://itunes.apple.com/jp/genre/ios-%E3%82%BD%E3%83%BC%E3%82%B7%E3%83%A3%E3%83%AB%E3%83%8D%E3%83%83%E3%83%88%E3%83%AF%E3%83%BC%E3%82%AD%E3%83%B3%E3%82%B0/id6005?mt=8&uo=2" label="ソーシャルネットワーキング" />
<im:artist href="https://itunes.apple.com/jp/developer/facebook-inc/id284882218?mt=8&uo=2">Facebook, Inc.</im:artist>
<im:price amount="0.00000" currency="JPY">入手</im:price>
<im:image height="53">http://is1.mzstatic.com/image/thumb/Purple122/v4/27/94/74/2794747d-f2f1-2efa-b128-9e7269279037/mzl.inxlxixd.png/53x53bb-85.png</im:image>
<im:image height="75">http://is5.mzstatic.com/image/thumb/Purple122/v4/27/94/74/2794747d-f2f1-2efa-b128-9e7269279037/mzl.inxlxixd.png/75x75bb-85.png</im:image>
<im:image height="100">http://is1.mzstatic.com/image/thumb/Purple122/v4/27/94/74/2794747d-f2f1-2efa-b128-9e7269279037/mzl.inxlxixd.png/100x100bb-85.png</im:image>
<rights>&#169; Facebook, Inc.</rights>
<im:releaseDate label="2008年7月11日 ">2008-07-11T00:00:00-07:00</im:releaseDate>
<content type="html">省略</content>
</entry>
<entry>
<updated>2017-02-28T00:47:00-07:00</updated>
<id>1554278848</id>
<title>はぁ?なめてんの?</title>
<content type="text">てかまず登録させてくれない。【エラー 現在、ユーザ登録が処理できません。しばらくしてからもう1度実行してください】…はぁ?そのまま6ヵ月待ってるんですけど? 速く登録させて ☆星一つも付けたくない👎🏻👎🏻</content>
<im:contentType term="Application" label="アプリケーション" />
<im:voteSum>0</im:voteSum>
<im:voteCount>0</im:voteCount>
<im:rating>1</im:rating>
<im:version>81.0</im:version>
<author>
<name>💞🍋Lemon🍋💞&❤️🍫Kitkat🍫❤️</name>
<uri>https://itunes.apple.com/jp/reviews/id539129390</uri>
</author>
<link rel="related" href="https://itunes.apple.com/jp/review?id=284882215&type=Purple%20Software" />
<content type="html">省略</content>
</entry>
<entry>
...レビューごと
</entry>
...
</feed>
サンプルスクリプト
PHPでレビューを取得する一例。
<?php
mb_regex_encoding("UTF-8");
date_default_timezone_set('Asia/Tokyo');
set_time_limit(1200);
define('APPSTORE_REVIEWS_UPDATE', 'update');
define('APPSTORE_REVIEWS_ENTRIES', 'entries');
define('APPSTORE_REVIEW_TITLE', 'title');
define('APPSTORE_REVIEW_ID', 'id');
define('APPSTORE_REVIEW_UPDATE', 'update');
define('APPSTORE_REVIEW_CONTENT', 'content');
define('APPSTORE_REVIEW_RATING', 'rating');
define('APPSTORE_REVIEW_VERSION', 'version');
define('APPSTORE_REVIEW_AUTHOR', 'author');
function appstore_get_reviews($countryCode, $appId)
{
$url = 'https://itunes.apple.com/' . $countryCode . '/rss/customerreviews/id=' . $appId . '/sortBy=mostRecent/xml';
$curl = curl_init($url);
curl_setopt($curl, CURLOPT_FRESH_CONNECT, TRUE);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 60);
$result = curl_exec($curl);
curl_close($curl);
if ($result === FALSE)
return NULL;
$reviews = [];
$entryArray = [];
$rootNode = new SimpleXMLElement($result);
$entriesNode = $rootNode->entry;
$entryCount = count($entriesNode);
for ($entryIndex = 1; $entryIndex < $entryCount; $entryIndex++)
{
$entryNode = $entriesNode[$entryIndex];
$entry = [];
$entry[APPSTORE_REVIEW_ID] = (string)$entryNode->id;
$entry[APPSTORE_REVIEW_UPDATE] = new DateTime((string)$entryNode->updated);
$entry[APPSTORE_REVIEW_TITLE] = (string)$entryNode->title;
$entry[APPSTORE_REVIEW_CONTENT] = '';
if (is_array($entryNode->content))
{
foreach ($entryNode->content as $contentNode)
{
if ($contentNode['type'] == 'text')
{
$entry[APPSTORE_REVIEW_CONTENT] = (string)$entryNode->content[0];
break;
}
}
}
else if ($entryNode->content['type'] == 'text')
{
$entry[APPSTORE_REVIEW_CONTENT] = (string)$entryNode->content;
}
$imNodes = $entryNode->children('im', TRUE);
$entry[APPSTORE_REVIEW_RATING] = (string)$imNodes->rating;
$entry[APPSTORE_REVIEW_VERSION] = (string)$imNodes->version;
$entry[APPSTORE_REVIEW_AUTHOR] = (string)$entryNode->author->name;
array_push($entryArray, $entry);
}
$reviews[APPSTORE_REVIEWS_UPDATE] = new DateTime((string)$rootNode->updated);
$reviews[APPSTORE_REVIEWS_ENTRIES] = $entryArray;
return $reviews;
}
Google Play上のAndroidアプリのレビュー
Developer Console からCSV形式の月次レポートが Google Cloud Storage に保存される。
記載されたレビューがこのレポートに反映されるのは1日〜2日後くらい。
このレポートをgsutil
でダウンロードできる。
手順
レポートのURI取得
Developer Console の レポート
> レビュー
にて、アプリを選択すると、そのアプリのURIが表示される。
例: gs://pubsite_prod_rev_123123123132123/reviews
gsutilをインストール
gsutil
は Google Cloud SDK に含まれている。
Google Cloud SDK はこちらからインストールできる:
https://cloud.google.com/sdk/downloads
インストール手順は
$ gcloud init
まで行えば使えるようになる。
Google Cloud SDK を展開したディレクトリに対してbin/gsutil
がgsutil
になるので、環境変数PATHにbin
の絶対パスを追加しておくと便利。
gsutilでレポートを取得
レポートの一覧を表示する
Google Cloud Storage に上がっているレポートの一覧はgsutil ls
でリスティングできる。
$ gsutil ls gs://pubsite_prod_rev_123123123132123/reviews
gs://pubsite_prod_rev_123123123132123/reviews/reviews_jp.runo.testapp_201605.csv
gs://pubsite_prod_rev_123123123132123/reviews/reviews_jp.runo.testapp_201606.csv
# (表略)
レポートをダウンロードする
Google Cloud Storage に上がっているレポートの一覧はgsutil cp
でコピーできる。
$ gsutil cp gs://pubsite_prod_rev_123123123132123/reviews/reviews_jp.runo.testapp_201605.csv /tmp/
レポートの形式はUTF16のCSV。
レポートの内容
Package Name,App Version Code,App Version Name,Reviewer Language,Device,Review Submit Date and Time,Review Submit Millis Since Epoch,Review Last Update Date and Time,Review Last Update Millis Since Epoch,Star Rating,Review Title,Review Text,Developer Reply Date and Time,Developer Reply Millis Since Epoch,Developer Reply Text,Review Link
jp.runo.testapp,33,1.11.5,ja,SH-04G,2016-07-31T05:29:36Z,2976903,2016-07-31T05:30:53Z,3053851,3,バグ,アプリがバグってます,,,,https://play.google.com/apps/publish?...
...
サンプルスクリプト
PHPでレビューを取得する一例。
<?php
mb_regex_encoding("UTF-8");
date_default_timezone_set('Asia/Tokyo');
set_time_limit(1200);
function gsutil_command($command)
{
$line = exec('$HOME/google-cloud-sdk/bin/gsutil ' . $command . ' 2>&1', $output, $exitcode);
if ($exitcode != 0)
{
echo("gsutil: returned $exitcode\n");
var_dump($output);
}
return $exitcode;
}
function googleplay_getreviews($bucketId, $packageName, $year, $month)
{
$inputPath = sprintf('gs://%s/reviews/reviews_%s_%s%02d.csv', $bucketId, $packageName, $year, $month);
$outputPath = tempnam("/tmp", "reviews");
if (gsutil_command('cp ' . $inputPath . ' ' . $outputPath) != 0)
return NULL;
$contentUtf16 = @file_get_contents($outputPath);
@unlink($outputPath);
$contentUtf8 = mb_convert_encoding($contentUtf16, 'UTF-8', 'UTF-16');
$outputPath = tempnam("/tmp", "reviews");
@file_put_contents($outputPath, $contentUtf8);
// 読み込む
$result = [];
$file = new SplFileObject($outputPath);
$file->setFlags(SplFileObject::READ_CSV);
$header = TRUE;
foreach ($file as $line)
{
if ($header) // 先頭行だけスキップ
{
$header = FALSE;
continue;
}
if (!isset($line[15])) // 不完全なデータ
continue;
array_unshift($result, $line);
}
@unlink($outputPath);
return $result;
}