こんにちはこんにちは! エンジニア川端です。
プロダクトの開発ではなく、裏方的なことをやってます。
今日は、普段私が担当している、表に出てこないお話をさせてください。
iPhone アプリ開発者の方にはおなじみの「iTunes Connect」。
App Store で公開するアプリケーションを申請したり、公開日を設定したり、iPhone アプリに関する色んなことができるサイトですが、公開後のダウンロード数の確認などでアクセスすることが多いのではないでしょうか。
ログインして情報を得て、関係者に回覧して……毎日十数分の作業とはいえ、本来やるべきこと (情報を材料に、次の計画をたてる等) に注力したい。なんとかならないかな。
「やりましょう!」
やりたいことは、ダウンロード数等の日時集計レポート CSV をダウンロードすることです。
「Sales Report」をクリックするとダウンロードできるファイルを、1 日 1 回自動でダウンロードします。
perl get_itunesconnect_csvgz.pl 2011-06-01| zcat > 2011-06-01.csv
みたいな感じで保存できるようにしておけば、後は毎日寝てる間に実行しておくだけ。社内システムへの取り込みも自動化して、朝出社したら閲覧できる状態……なんですけどね。
iTunes Connect のサイトって、見た目はページ遷移しなくて、裏でバンバンリクエストが飛んで処理してる感じなんで、調査しながら、ちょっと泣きそうになりました。
まぁ、できあがったプログラム見てしまうとなんてこたぁないんですけど。
use utf8; use strict; use warnings; use Config::Pit; use WWW::Mechanize; $Config::Pit::verbose = 0; { my $date = shift || ''; die 'usage: ',$0,' YYYY-MM-DD' unless ($date and $date =~ /^\d{4}-\d{2}-\d{2}$/); my($y,$m,$d) = split /-/, $date; my $key = 'https://itunesconnect.apple.com/WebObjects/iTunesConnect.woa/'; my $common_url = 'https://reportingitc.apple.com/sales.faces'; pit_switch('itunes_connect'); my $conf = pit_get( $key ); my $w = WWW::Mechanize->new( cookie_jar => {} ); # login $w->get( $key ); $w->submit_form( form_name => 'appleConnectForm', fields => { theAccountName => $conf->{username}, theAccountPW => $conf->{password}, } ); my $view_state; # j_idxxxxx:j_idxxxxx my $default_vendor_page; # j_id_jsp_xxxxxxxxx_2 my $ajax_request; # j_id_jsp_xxxxxxxxx_? # view "Sales and Trends" dashboard $w->get('https://reportingitc.apple.com/'); ($view_state = $w->content()) =~ s|^.*id="javax.faces.ViewState" value="([^"]+)".*$|$1|s; ($default_vendor_page = $w->content() ) =~ s|^.*defaultVendorPage:(j_id_jsp_[^:"]+)".*$|$1|s; ($ajax_request = $default_vendor_page) =~ s|_2$|_0|; $w->post('https://reportingitc.apple.com/vendor_default.faces',{ 'AJAXREQUEST' => $ajax_request, 'defaultVendorPage' => 'defaultVendorPage', 'javax.faces.ViewState' => $view_state, 'defaultVendorPage:'.$default_vendor_page => 'defaultVendorPage:'.$default_vendor_page, } ); # select 'Sales' Tab my $common_query = { 'theForm' => 'theForm', 'theForm:xyz' => 'notnormal', 'theForm:vendorType' => 'Y', 'theForm:optInVar' => 'A', 'theForm:optInVarRender' => 'false', 'theForm:wklyBool' => 'false', 'theForm:datePickerSourceSelectElementSales' => $m.'/'.$d.'/'.$y, # 'theForm:weekPickerSourceSelectElement' => # その週の日曜日。デイリーレポート取得時は、いらないっぽい }; $w->get( $common_url ); ($view_state = $w->content()) =~ s|^.*id="javax.faces.ViewState" value="([^"]+)".*$|$1|s; ($default_vendor_page = $w->content() ) =~ s|^.*'theForm:(j_id_jsp_(?:\d)+_6)'.*$|$1|s; ($ajax_request = $default_vendor_page) =~ s|_6$|_2|; $w->post( $common_url, { %$common_query, 'AJAXREQUEST' => 'theForm:'.$ajax_request, 'javax.faces.ViewState' => $view_state, 'theForm:'.$default_vendor_page => 'theForm:'.$default_vendor_page, } ); # get csv file ($view_state = $w->content()) =~ s|^.*id="javax.faces.ViewState" value="([^"]+)".*$|$1|s; $w->post( $common_url, { %$common_query, 'javax.faces.ViewState' => $view_state, 'theForm:downloadLabel2' => 'theForm:downloadLabel2', 'dailyName' => 'dailyName' } ); print $w->content(); # gz } exit;
15 分の作業を 10 分に短縮するのは慣れれば自然とそうなるし、10 分を 5 分にするのも工夫すればなんとかなりそう。でも、5 分を 0 分にするのは難しい。
難しいけど、30 人の 5 分を 0 分にできれば。50 人の 5 分を 0 分にできれば。10000 人の 5 分を 0 分にできれば。
……というような事を考えながら、作業に勤しむ毎日です。
そんな地味なエンジニアも所属するフェンリル、これからも応援よろしくお願いします!