【プリチャン】ARコーデ管理アプリ作ってみた その2 ~GASでWeb Scraping編~
これは「プリッカソン Advent Calendar 2018」11日目の記事です。
前回のあらすじ
前回の記事ではVuforiaでコーデ画像をARマーカーとして使うことでカメラでプリチャンのコーデを認識することができるようになった。
コーデ認識をする本来の目的は持っているコーデと持っていないコーデを判別することなので、何かしらの手段で所持状態を記憶しておく必要がある。
スプレに根性で手入力してみた
端末に情報を記憶しておくというのも手だが、他の用途にも使えるかもしれないのでGoogle スプレッドシートにコーデの情報と所持状態を記録しておいて、アプリと連動するような仕組みにしておくと後々便利そうだ。
早速、Vuforiaの認識部分と連携できそうなデータを公式サイトのアイテム一覧をにらめっこしながらスプレに入力してみる。
第4弾の10月チャンネルを入力し終わるまで約30分。無理ではないけど意外と手間がかかる。データのラベルは以下のように設定した。
have:持っているかどうか(後から個数を追加したので実は不要)
possession_num:何個持っているか
id:コーデID。プリチケの下の方に印字されている
rarity:コーデのレアリティ。KR,PR,SR,R,N
name1:コーデ名の前半部分。同種は大抵同じ
name2:コーデ名の後半部分
image_num:画像番号。VuforiaのDBは番号が名前になっている
rating:Vuforiaの検出レート
database_name:VuforiaのDB名
group_name:コーデ一式を判別する
手入力を諦めてみた
手入力で30分とはいえ、新弾が追加されるたびに同様の作業を行わなくてはいけないのは結構めんどくさい。
前回行ったVuforiaへのコーデの画像追加は、1つずつAdd Targetで追加しなくてはいけないので(複数画像の一括入力に対応してほしい)かなり時間がかかってしまう。
アップデートの労力は最小限にしたいがVuforia側はどうしようもなさそうなので、せめてスプレ側の自動化を考えてみる。
GASでWeb Scrapingやってみた
GAS(Google Apps Script)はGoogleが提供しているJavaScriptベースの開発環境だ。無料でGoogleの提供するスプレッドシート等のサービスを操作できて超えもい。
スプレに自動入力をする際、どこから情報を得るのが良いかを考えると当然公式サイトを覗くのが一番簡単かつ安定する方法だろう。
手始めに公式サイトのアイテム一覧のページの中身を取得してみる。
//第5弾 11月チャンネルのURL
var url = 'https://prichan.jp/items/5th_12.html';
var html = UrlFetchApp.fetch(url).getContentText();//ページの内容ぜんぶ
htmlの中に対象ページのデータが入っているので、そこから自動入力に必要な情報を抜き取る。
今回はParserというGASのライブラリを使用して必要な情報を抜き出した。
var div = Parser.data(html).from('<div>').to('</div>').build();
var divs = Parser.data(html).from('<div>').to('</div>').iterate();
from().to()はfromとtoに指定された文字列に挟まれた部分を抽出する。build()は文字列、iterate()は抽出できる文字列の配列を返す。
抜き出す箇所を把握するために、取得したデータの中身を覗いてみよう。
コーデ情報が記述してある場所を探すと以下のような構造になっている。
<!-- InstanceBeginEditable name="mainAfter" -->
<div class="items-category-name-lv1 df-normal">
<span>
<ruby>第<rt>だい</rt></ruby>5<ruby>弾<rt>だん</rt></ruby>
(12<ruby>月<rt>がつ</rt></ruby>チャンネル)
</span>
</div>
<div class="coordinate-lists">
//この部分にコーデ情報が入っている
//あとで説明する&長いのでので省略
</div>
<!-- InstanceEndEditable -->
必要箇所だけ抜き取るのでfromを<div class="coordinate-lists">、toを</div>と指定すれば良さそうだが、Parserは最初に見つかった</div>までの文字列を返してしまうので、範囲を以下のように指定する。この範囲は1つしか存在しないのでbuild()で値を取得する。
var from_txt = '<div class="coordinate-lists">';
var to_text = '<!-- InstanceEndEditable -->';
var coordinateLists = Parser.data(html).from(from_txt).to(to_text).build();
Parserで抜き出した文字列coordinateListsの中身をさらに掘り下げて見てみると<div id="5-1" class="coordinate-list">の部分にコーデ一式の内容が含まれていることがわかる。
この場合、5-1の部分がスプレに入力したい値のgroup_nameに該当する。
<div id="5-1" class="coordinate-list">
<div class="-inner">
<div class="-outfit">
<img class="lazyload" data-src="/resources/images/items/outfits/5-1.png" alt="">
</div>
<ul class="-details">
<li class="-detail">
<a href="details/70500.html">
<div class="-category">ワンピース</div>
<div class="-shoulder">PCH5-01</div>
<div class="-thumb">
<img class="lazyload" data-src="/resources/images/items/details/70500.jpg" alt="">
</div>
<div class="-title">プレシャスミューズ<br>キラッとワンピ</div>
<div class="-status">
<div class="-rarity -kr">KR</div>
<div class="-like">1900</div>
</div>
</a>
</li>
//以下コーデ一式の繰り返し
</ul>
</div>
</div>
group_nameに使用する部分を残しつつコーデ一式単位の配列を得るために、fromとtoを以下のように設定する。
var from_txt = '<div id=';
var to_text = '</ul>';
var outfit = Parser.data(coordinateLists).from(from_txt).to(to_text).iterate();
outfit部分の取得ができたら配列をループして必要な値を取得する。
スプレへの入力は1度に行うので値を配列に入れておく。
var all_array = [];//スプレに書き込む値。2重配列
//ラベルを入力
var label_array = ["id","rarity","name1","name2","image_num",
"rating","database_name","group_name"];
all_array.push(label_array);//ラベル用の配列を追加
//コーデ1式のループ
for(var v = 0; v < outfit.length; v++){
//group_nameはコーデ1式で共通
var group_name = Parser.data(outfit[v])
.from('"')
.to('" class="coordinate-list">')
.build();
//パシャっとアイテムは空白なので「"」が返ってくる
if(group_name == '"')
group_name = 'PI';
//コーデ1式の配列を取得する
var lists = Parser.data(outfit[v])
.from('<li class="-detail">')
.to('</li>')
.iterate();
//コーデ1式に含まれる各コーデのループ
for(var i = 0; i < lists.length; i++){
var detail_array = [];
var id = Parser.data(lists[i])
.from('<div class="-shoulder">')
.to('</div>')
.build();
//レアリティによってclassが変化するのでちょっと工夫する
var rarity = Parser.data(lists[i])
.from('<div class="-rarity')
.to('</div>')
.build()
.split(">")[1];
//名前は<br>で区切られている
var name_split = Parser.data(lists[i])
.from('<div class="-title">')
.to('</div>').build()
.split("<br>");
var name1 = name_split[0];
var name2 = name_split[1];
//詳細ページへのリンクだが、画像番号と値は一致する
var image_num = Parser.data(lists[i])
.from('<a href="details/')
.to('.html">')
.build();
//Vuforiaによる値なので暫定的に0
var rating = 0;
//コーデIDは「-」以下が共通なのでこれをDB名にする
var database_name = id.split('-')[0];
detail_array.push(id);
detail_array.push(rarity);
detail_array.push(name1);
detail_array.push(name2);
detail_array.push(image_num);
detail_array.push(rating);
detail_array.push(database_name);
detail_array.push(group_name);
all_array.push(temp_array);
}
}
all_arrayに全ての値を入力したらそのままスプレに値を反映させる。
//今回はScrapingの対象のURLを名前にしてシートを新規作成する
var sheet = SpreadsheetApp.getActiveSpreadsheet().insertSheet(url);
//値をスプレに書き込む。
sheet.getRange(1,1,all_array.length,8).setValues(all_array);
Scriptを実行することで30分かかっていた作業がクリック1つでできるようになった。
サンプル公開してみた
スクリプトの実行には権限が必要なので、スプレッドシートのコピーを作成したあとに実行してください。
別の方法でも可能かもと思ってみた
ここまで記事を書いた段階でスプレのIMPORTXML使えばGASを使わないで同じことができるんじゃないかと思ってしまった。
興味がある人は挑戦して出来たら教えてください。
余談、少しだけ語ってみた
ちょっと記事にプリティー成分が足りていない雰囲気を感じたので、12/9に開催された『み~んなでキラッとプリティーライブ2018』の個人的えもえもポイントを紹介しようと思う。(関連作品の内容に言及したりしているので若干注意してね)
・阿澄佳奈さんのMC、『新しいお洋服でステージに立てて』
「お洋服」!!!「衣装」じゃなくて「お洋服」!!!
トークの緩さもあいまって完全に春音あいらでした。
・『Dear My Future ~未来の自分へ~』の背景映像
上段にアイドルタイム映像、下段にディアマイフューチャー映像、歌唱に大久保瑠美さん、華園みあのモーションに日下部美愛さん、「きらめきフューチャースター」の新旧同時再生というまさかの全部盛り…超えもい…
・ハピなるなら手をつなごう
「でーこー!」「遠ーくにー見ーえーてーるー!」の合唱ができる日が来るとは思わなんだ…映画の応援上映では何度か経験があるものの、あれだけ大きい会場だと格別にハピなる!
プリティーリズム・レイボーライブ34話「ハピなるなら手をつなごう!」の話の中に入り込んだ感覚は格別なのでまだ見てない人は今すぐプリティーリズムを見てください。あ、『隣の友達と手を繋いでみたら』のくだりで3人が手をつないでる振り付けめっちゃえもかったですね…
・Make it! -SAINTS & SoLaMiDressing ver.-
キャストの方々も触れていましたがこの9人が揃ってライブ出来ている事自体が奇跡…めっちゃえもいね。映像作品では『劇場版 プリパラ&キラッとプリ☆チャン きらきらメモリアルライブ』が記憶に新しいですがショートバージョンになっているので全部通して見たいときは『劇場版プリパラ み~んなあつまれ!プリズム☆ツアーズ』がオススメです。セインツのサイリウムチェンジがめっちゃえもいです。
思わず余談が長くなって主題から外れそうなのでプリリズ部分だけ抜粋しました。プリパラ民もプリチャン民もこの機会にプリティーリズムを見てください。
Session Continues... 次回は「データ連携編」です。
この記事が気に入ったらサポートをしてみませんか?