[iOS]iTunes,Adsenseの情報を取得してslackに投げた

Posted on

今年はiOSやっていこうということで、これまで気が向いたときにpullしていた情報をslackに投げてもらうことにした

  • Adsense: GAS -> slack
  • iTunesのDL数とか: Reporterアプリ
  • iTunesのコメント: RSS
  • 行動履歴とか: analyticsちゃんとやろう。アプリに入れる必要があるので今後の課題

slackからの設定

  • ここからIncoming WebHooksを検索してIntegrationに追加
  • ここのsettingからチャンネルを選ぶとURLが発行される

Adsense

GAS -> slack - scriptはよそから拾ってきたものを改変 - このスクリプトはslack commandで反応する子なので、単にポストしてくれるように改変 - GASのトリガー設定でdailyとmonthlyに投げてもらうように設定 - 日次でpostDailyReport()を叩くように設定 - 月次でpostMonthlyReport()を叩くように設定

var slackURLMonthly = "[月次報告用チャネルに発行したURL]"
var slackURLDaily = "[日時報告用チャネルに発行したURL]";

function postMonthlyReport(){
  var textForSlack = "先月のadsense\n"+getAdsenseData("thismonth");
  postToSlack(textForSlack, slackURLMonthly)
}

function postDailyReport(){
  var textForSlack = "昨日のadsense\n"+getAdsenseData("yesterday");
  postToSlack(textForSlack, slackURLDaily)
}

function postToSlack(text, url) {
  var headers = {
    "Content-Type":"application/json"
  };

  var data = {
    "text": '\`\`\`'+text+'\`\`\`'
  };

  var payload = JSON.stringify(data);

   var options =
   {
     "method":"POST",
     "headers":headers,
     "payload":payload,
     "muteHttpExceptions":false
   };

  try{
    var res = UrlFetchApp.fetch(url, options)
  }catch(e){
    Logger.log("Failed to post"+e)
  }

}

function getAdsenseData (mode) {
  var slack_text = "";
  var today = new Date();
  var timezone = Session.getScriptTimeZone();
  var endDate = Utilities.formatDate(today, timezone, 'yyyy-MM-dd');

  if (mode == "yesterday"){
    var startDate = Utilities.formatDate(new Date(today.getYear(), today.getMonth(),today.getDate() -1), timezone, 'yyyy-MM-dd');
  }
  else if (mode == "thismonth"){
    var startDate = Utilities.formatDate(new Date(today.getYear(), today.getMonth() - 1,1), timezone, 'yyyy-MM-dd');
  }
  else {
    var startDate = Utilities.formatDate(new Date(today.getYear(), today.getMonth(),today.getDate() -1), timezone, 'yyyy-MM-dd');
  }

  var report = AdSense.Reports.generate(startDate, endDate, {
    metric: ['PAGE_VIEWS', 'AD_REQUESTS', 'CLICKS',
             'AD_REQUESTS_CTR', 'COST_PER_CLICK', 'AD_REQUESTS_RPM',
             'EARNINGS'],
  }).rows;

  if (report) {
    slack_text += "ページビュー数:" + report[0][0] + "\n広告リクエスト回数:" + report[0][1] + "\nクリック数:" + report[0][2] +"\nCTR:"+ report[0][3];
    slack_text += "\nCPC:" + report[0][4] + "\nRPM:" + report[0][5] + "\n見積もり収益:" + report[0][6] + ""

    return slack_text;
  }
  else {
    return;
  }
}

DL数とか

  • appleのReporterを使う

    • やり方ググったらjava -jar Reporter.jar p=Reporter.propertiesとかしてて、なんかのREST叩くだけなのにJavaとかwと思ったらapple公式のレポートツールらしい。API公開して
    • しかもtab区切りのファイルがzipで圧縮されて落ちてくる。JSONで返して
    • iTunesからtokenを取得して、propertyファイルに設定が必要
    • tokenの取得方法がわかりにくいので記載
    • 1. iTunes Connectにログイン
    • 2. 売上とトレンド
    • 3. 左側メニューの売上とトレンドのレポート
    • 4. 右上のレポートについての隣の?マーク
    • 5. Reporterトークンを生成 ※このtokenは半年毎にexpireするので更新が必要らしい
  • pythonからこのjarを叩いてファイルを取得、パースするスクリプトを書いた

    • きっとjarを読み解いて頑張ればできるのかもしれない?
#!/usr/bin/env python3

from datetime import datetime, timedelta
import os
import json
import requests

slackURLMonthly = [月次報告用チャネルに発行したURL]
slackURLDaily = [日次報告用チャネルに発行したURL]

# move to the path of this file
abspath = os.path.abspath(__file__)
dirname = os.path.dirname(abspath)
os.chdir(dirname)

vendorNo = [自身のベンダーID]
reportDir = "./reports"


def run():
    postDailyReport()

# 一ヶ月分の集計を送る機能をそのうち作りたいな.そのために過去のレポートファイルは保存しておく
# def postMonthlyReport():


# 2日前のレポートをslackに送る
def postDailyReport():
    targetDate = (datetime.today() - timedelta(days=2))
    filePath = getReport(targetDate.strftime('%Y%m%d'))
    reports = summarizeReport(filePath)
    text = makeNoticeTextForSlack(reports, targetDate.strftime('%Y-%m-%d')+"のレポート")
    postToSlack(slackURLDaily, text)

# get report from iTunes.
def getReport(targetDate):
    targetYear = targetDate[0:4]
    targetMonth = targetDate[4:6]
    targetDay = targetDate[6:8]
    saveDir = reportDir+"/"+targetYear+"/"+targetMonth
    filePath = saveDir+"/"+targetDay+".txt"
    if os.path.exists(filePath) == False:
        # it cannnot handle errors, but I allow it.
        downloadedFileName = "S_D_"+vendorNo+"_"+targetDate+".txt"
        os.system('mkdir -p '+saveDir)
        os.system('java -jar Reporter.jar p=Reporter.properties Sales.getReport '+vendorNo+', Sales, Summary, Daily, '+targetDate)
        os.system('gunzip '+downloadedFileName+".gz")
        os.system('mv '+downloadedFileName+" "+filePath)
    return filePath

class AppReportInfo:
    def __init__(self, name, numberOfDownloadAll, numberOfDownloadByVersion ,numberOfDownloadByCountry,numberOfDownloadByDevice, sales):
        self.name = name
        self.numberOfDownloadAll = numberOfDownloadAll
        self.numberOfDownloadByVersion = numberOfDownloadByVersion
        self.numberOfDownloadByCountry = numberOfDownloadByCountry
        self.numberOfDownloadByDevice = numberOfDownloadByDevice
        self.sales = sales

# summarizeReport returns dictionary of AppReportInfo. key: app name, value: AppReportInfo
def summarizeReport(filePath):
    reports = {}
    with open(filePath) as f:
        # first line is Column Name.
        f.readline()
        for line in f:
            line = line.replace('\n','')
            array = line.split("\t")
            appName = array[4]
            appVersion = array[5]
            appNumberOfDL = int(array[7])
            appCountry = array[12]
            appPrice = array[15]
            appSales = float(appPrice) * int(appNumberOfDL)
            appDevice = array[22]

            if appName in reports.keys():
                reports[appName].numberOfDownloadAll += appNumberOfDL
                if appVersion in reports[appName].numberOfDownloadByVersion.keys():
                    reports[appName].numberOfDownloadByVersion[appVersion] += appNumberOfDL
                else:
                    reports[appName].numberOfDownloadByVersion[appVersion] = appNumberOfDL

                if appCountry in reports[appName].numberOfDownloadByCountry.keys():
                    reports[appName].numberOfDownloadByCountry[appCountry] += appNumberOfDL
                else:
                    reports[appName].numberOfDownloadByCountry[appCountry] = appNumberOfDL

                if appCountry in reports[appName].numberOfDownloadByDevice.keys():
                    reports[appName].numberOfDownloadByDevice[appDevice] += appNumberOfDL
                else:
                    reports[appName].numberOfDownloadByDevice[appDevice] = appNumberOfDL

                reports[appName].sales += appSales
            else:
                report = AppReportInfo(appName, appNumberOfDL, {appVersion : appNumberOfDL}, {appCountry : appNumberOfDL}, {appDevice : appNumberOfDL}, appSales)
                reports[appName] = report
    return reports

# makeNoticeTextForSlack returns text from reports like below.
# こんなメッセージを作る
# ```
# アプリ名
#   売上:XX円
#   ダウンロード数:100
#     バージョン別: 1.1.1:xx 1.1.2:xx
#     国別:JP:xx Ch:xx
#     デバイス別: iPhone:xx iPad:xx
#
# アプリ名2
# ・・・・
# ```
def makeNoticeTextForSlack(reports, messageHead):
    text = messageHead + "\n"
    for reportKey in reports:
        text += "```\n"
        text += reports[reportKey].name+"\n"
        text += "  DL数: " + str(reports[reportKey].numberOfDownloadAll) + "\n"
        text += "    バージョン別 " + str(reports[reportKey].numberOfDownloadByVersion).replace('{','').replace('}','').replace("'",'') + "\n"
        text += "    国別 " + str(reports[reportKey].numberOfDownloadByCountry).replace('{','').replace('}','').replace("'",'') + "\n"
        text += "    デバイス別 " + str(reports[reportKey].numberOfDownloadByDevice).replace('{','').replace('}','').replace("'",'') + "\n"
        text += "  売上: " + str(reports[reportKey].sales) + "円\n"
        text += "```\n"

    return text

def postToSlack(url, text):
    headers = { "Content-Type":"application/json" }
    method = "POST"
    body = { "text": text }
    jsonBody = json.dumps(body).encode("utf-8")
    response = requests.post(url, data=jsonBody, headers = headers)
    print(response)

if __name__ == '__main__':

iTunesのコメント

slackのRSSのfeedインテグレーションを利用

slackの表示するチャンネルで
/feed https://itunes.apple.com/jp/rss/customerreviews/id=[アプリのApple Identifier]/sortBy=mostRecent/xml

で取得

完成

これで最低限の情報取得が設定できた。アプリ開発するよ