プログラマでありたい

おっさんになっても、プログラマでありつづけたい

Google PlayからAndroidアプリのランキングを取得する

 前回、手軽にAppStoreからiOSアプリのランキングを取得する方法を紹介しました。Androidの場合は、どうしたら良いのでしょう?幾つか方法を考えてみます。対象は売上トップのAndroidアプリとして、URLは次の通りです。
https://play.google.com/store/apps/collection/topgrossing?hl=ja

  1. import.io + Google スプレッドシートのあわせ技
  2. Google スプレッドシートのIMPORTXML関数で何とかする
  3. Google Apps Scriptで頑張る
  4. みんな大好きExcelを使う

import.io + Google スプレッドシートのあわせ技



 まず試すのが、import.ioとGoogle スプレッドシートのあわせ技です。これで実現できれば、一番ラクです。

import.ioでログインし、New ExtractorでURLを指定します。すると下記のように、自動的に項目を抽出してくれます。
f:id:dkfj:20161008101245p:plain

ただ、何か辺です。どう見ても日本のランキングには見えません。恐らくIPアドレスを元に実行元の国のランキングを出しているっぽいです。残念です。

 ちなみに、取得結果をGoogle スプレッドシートに吐き出すのは簡単です。作成したEcxtactorからIntegrateタグを選び、Google Sheetsを選ぶとImportData形式の関数を吐き出してくれます。それをスプレッドシートに貼るだけです。

f:id:dkfj:20161008101257p:plain

 簡単なので、国内のデータが取れないのが残念です。
※別解として、AWSのAPI Gatewayを日本に用意して、HTTP Proxyとして返すという手はあるかも。

Google スプレッドシートのIMPORTXML関数で何とかする


 それでは、次にGoogle スプレッドシートのImportXML関数です。先程の実行元IPがあるので、そもそもGoogle スプレッドシートがどこで実行されているか確認する必要があります。httpサーバーを立ててアクセスし、ログからIPアドレスを取得します。その結果を、IPアドレスの素性が解るサイトで検索します。

f:id:dkfj:20161008105657p:plain

 見事にアメリカのカリフォルニアからのアクセスです。残念ながら、何とかなりませんでした。こちらも、Proxy的なモノを用意してとかなら何とか出来るかもしれませんが、一般的では無くなるので、止めておきます。

Google Apps Scriptで頑張る


 次に、Google Apps Scriptで頑張れるか確認してみます。前回と同様に、IPアドレスの素性を調べます。

f:id:dkfj:20161008110017p:plain

 今度は、アメリカのヴァージニア州でした。こちらは、GAEで動いているんだなと、変に納得してしまいます。と言う事で、Google Apps Scriptでも頑張れませんでした。

みんな大好きExcelを使う



 クラウド上のサービスが駄目なら、ローカルから実行すれば良いじゃないか。ということで、みんな大好きなExcelを使ってみましょう。Excelから外部データを取得するには、大きく2つの手段があります。

1. WebService関数を使う
2. VBA+IEでスクレイピング機能

 まず簡単なWebService関数を使ってみましょう。この関数は、URLを指定するだけというお手軽な関数です。

f:id:dkfj:20161008113245p:plain

 エラーが出ています。この関数の弱点として、文字数制限があります。元々Excelのセルの制限に、32,767文字というものがあります。それに引きづられて、関数の取得できる文字列のMaxも32,767文字に制限されています。最近のHTMLだと、殆どの場合が超えてしまいます。RSSとか取得するには、良いんですけどね。今回は使えません。残念。

 仕方がないので、VBA+IEで行ってみましょう。処理の概要としては、VBAからInternetExplorerを立ち上げ、HTMLElementCollectionで必要な部分のHTML要素を抜き出すという方法です。この方法の詳細は、こちらをご参照ください。

Excel VBA+IEでのスクレイピング


 取得方法としては、"card no-rationale square-cover apps small"というclass名指定するとランキングのリストが取得します。そこから、子のオブジェクトを指定するという形になります。その結果をシートに保存します。面倒くさいですね。

Option Explicit
Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)

Private objIE As InternetExplorer

Sub main()
    Set objIE = New InternetExplorer
    Dim url
    Dim baseUrl
    
    baseUrl = "https://play.google.com"
    url = baseUrl & "/store/apps/collection/topgrossing?hl=ja"
    objIE.Visible = True
    objIE.Navigate2 (url)
    
    '読み込み完了待ち
    While objIE.readyState <> READYSTATE_COMPLETE Or objIE.Busy = True
        DoEvents
        Sleep 100
    Wend
    Sleep 100
    
    Dim objDoc As HTMLElementCollection
    Set objDoc = objIE.document
    Dim element As IHTMLElement
    Dim title
    Dim path
    Dim row
    row = 1
    
    For Each element In objDoc.getElementsByClassName("card no-rationale square-cover apps small")
        title = element.Children(0).Children(2).Children(1).innerText
        path = element.Children(0).Children(2).Children(1).getAttribute("href")
    
        Worksheets(1).Cells(row, 1) = title
        Worksheets(1).Cells(row, 2) = baseUrl & path
        
        row = row + 1
    Next element
    
    objIE.Quit
    Set objIE = Nothing
End Sub

取得結果は、次のような形になります。
f:id:dkfj:20161008132611p:plain

まとめ


 まさかのExcelを使う羽目になってしまいました。クラウド上のWebサービスは便利なのですが、実行元の制限ができません。クライアント側のIPアドレスによって、国を判別するという処理には極めて弱くなります。AWSのAPI GatewayのHTTP Proxyを使うとか、回避方法は色々あるのですが本筋ではないので省略します。とりあえずIPアドレスを元に判別という処理は、なくしてほしいですねと勝手な願いで終わりとさせて頂きます。

See Also:
AppStoreからiOSアプリのランキングを取得する
環境構築レスでAmazonの商品レビューを取得する
Google スプレッドシートの関数でWebからデータを取得する