hartmannのゲームあれこれ

適当にやってるゲームのあれこれを偶に書きます

WoT CWE管理シート自動化の旅々 2.『プロヴィンス一覧の取得』※修正版

改訂2021/01/13: WG APIの糞仕様によりこのままだと後の処理が上手くいかなくなるため、解決するために「スクレイピング4(戦)」シートのE列に領地idを表示させるように変更しました。
ts-hartmann.hatenablog.com これの続き

やっと本題

 このシートには、多数の自動化方法があります。ひとくくりに自動化と言っても、簡単な計算を行うだけのいわゆるSUM関数などと呼ばれる関数から、スクレイピング、さらに複雑な処理とされている予定表の自動記入に分けられます。この自動化の証であるスクリプトを完成させ、その完成度の高さに満足し、その美しさと書式の輝きに処理さえも思わず重くなってしまうほどのシートを作ったのは誰でしょうか?そう、私です!

 実際はそこまで重い処理でもありませんし(当社比)、簡単なコードなのですが。

 今回はタイトルにもある通り、プロヴィンス情報の一覧をWargamingAPIからスクレイピングしてシートに出力していこうと思います。

プロヴィンス一覧をスクレイピングするための手順1. GAS側の記述

 プロヴィンス一覧を取得するためには、まず戦線の情報を取得する必要があります。戦線の情報取得は何もパラメーターを入れなくても出力されるのに対して、プロヴィンス一覧はfront_idのパラメーターを入れなくてはいけないからです。

 スクリプト書くのが上手い人は一括でこの処理をやってしまうのでしょうが、今回はfront_idを取得→取得した結果をシートに出力→シートに出力されたそれぞれのfront_idを取得→各frontのprovincesを取得という回りくどい順序で手順を組んでいこうと思います。

 まずは、以下にコードを記述します。

function Scraping5() {


  //WoT Grobalmapの戦線を検索※WoTAPIを使用
 
  const URL1 = 'https://api.worldoftanks.asia/wot/globalmap/fronts/?application_id=#MYAPPLICATIONID&language=en';

  var response = UrlFetchApp.fetch(URL1);
 
  var id = "スプレッドシートのid";  
  var spreadSheet = SpreadsheetApp.openById(id);  
  var sheetName = "front1";
  var str = response;
  var str2 = str.toString();
  var rep = str2.replace(/"/g,"");
  var mat = rep.split("front_name:");

  var count = mat.length; //配列変数matの配列数を調べる
  
  Logger.log(count);
  
  spreadSheet.getSheetByName(sheetName).getRange("A1:D100").clearContent();//セル内のコンテンツ削除※値や数式
  
  for (var i = 0; i < count; i++) {
  spreadSheet.getSheetByName(sheetName).getRange(i + 1, 1).setValue(mat[i]); //配列変数matのi+1番目に格納されている値をセルAi+1に入力
  }
  
  Scraping6()

}

function Scraping6() {

  //各戦線のプロヴィンス情報を取得

  var id = "スプレッドシートのid";  
  var spreadSheet = SpreadsheetApp.openById(id);  
  var sheetName = "front2";
  var cell = spreadSheet.getSheetByName(sheetName).getRange("A2:A10").getValues();
  var result = cell.filter(function(value){return (value[0].length > 0)});//空白要素の配列を削除
  var count = result.length; //配列変数resultの配列数を調べる
  
  var mata = ["1","2","3","4","5"];
  var count2 = mata.length;
  var data = [];
  for ( var i = 0; i < count2; i++) {
  
  //URL、データ取得のループ処理※51行目まで 
   var ary = [];
   for ( var k = 0; k < count; k++) {
   var URL2 = 'https://api.worldoftanks.asia/wot/globalmap/provinces/?application_id=#MYAPPLICATIONID&front_id='+result[k]+'&language=en&&page_no='+mata[i];//Grobal Map for world of Tanks プロヴィンスのトナメ情報
   var response = UrlFetchApp.fetch(URL2);
   var response2 = response.toString();
   var rep = response2.replace(/"/g,"");
   
   ary.push(rep);
   }
   data.push(ary)
  }
   var ary2 = data.toString();
   var mat = ary2.split("active_battles:"); 
   var count3 = mat.length; //配列変数matの配列数を調べる
   Logger.log(count3);
   
   var sheetName2 = "Province1";
   
   spreadSheet.getSheetByName(sheetName2).getRange("A1:D1000").clearContent();//セル内のコンテンツ削除※値や数式
   
   for (var i = 0; i < count3; i++) {
   spreadSheet.getSheetByName(sheetName2).getRange(i + 1, 1).setValue(mat[i]); //配列変数matのi+1番目に格納されている値をセルAi+1に入力
   }
   
   
}

 変数名などがおかしいのはご愛嬌ということでよろしくお願いします。GAS側の記述はこのコードをコピペすればいいはずです。

 「#MYAPPLICATIONID」にはparameterに入っているapplication_idを(2か所)、「スプレッドシートのid」にはデータを出力するシートのidを(2か所)代入して置き換えてください。
 はい、GAS側の作業は終わりですね。

プロヴィンス一覧をスクレイピングするための手順2. スプレッドシート側の記述

1. 必要なシートの作成

 後は必要な情報を切り取る作業をスプレッドシート内で行います。
 「front1」「front2」「Province1」「Province参照」の計4つのシートを用意します。そして、「front2」のA2セルに=IFERROR(REGEXEXTRACT(front1!A2,"front_id:(\w+)}"))と記述して、下の行までオートフィルします(5,6行あればいいと思います)。2021/01\07追記: 使用する正規表現を.(任意の一文字)から\w(アルファベット・アンダーバー・数字)に変更しました。
 それぞれのシートの役割はこんな感じです。

  1. 「front1」: WargamingAPIから戦線の一覧が書かれたページをスクレイピングした内容が出力されてあります。
  2. 「front2」: 「front1」に書いてある内容から戦線名が書かれている所のみ抜き出す。
  3. 「Province1」: WargamingAPIから戦線に存在するプロヴィンスの一覧が書かれたページをスクレイピングした内容が出力されてあります。
  4. 「Province参照」: 「Province1」に書いてあるデータを使いやすい形に加工。


 はい、データ取得の手順は終わりです!!あとは、上のコードを実行するだけでプロヴィンス情報がずらっと出てくるはずです!!
 

f:id:TS_hartmann:20201210181717p:plain
「province1」を見るとこんな感じに出力されるはずです。この1行1行が1プロヴィンスの情報です。

 ......これで終わりだと置いてけぼりになった気がするので最後まで書きますよ……

2. 情報の切り取り

 最後に、手順2-1で出力したデータを使えるように加工します。
 このデータの中から抜き出せるかつ、あると便利な情報というと、プライムタイム・戦線名・領地名・戦闘マップ名くらいのものだと思います。「Province参照」を作ったのはこの情報を抜き取ったものを表示させるためです。それぞれの情報を抜き出すときは、

  1. A2セル(プライムタイム):=IFERROR(IF(REGEXEXTRACT(Province1!A2,"prime_time:(.+?),")="","",TEXT(REGEXEXTRACT(Province1!A2,"prime_time:(.+?),")+$F$1,"[h]:mm")))
  2. B2セル(戦線名):=IFERROR(REGEXEXTRACT(Province1!$A2,"front_name:(.+?),"))
  3. C2セル(領地名):=IFERROR(REGEXEXTRACT(Province1!$A2,"province_name:(.+?),"))
  4. D2セル(戦闘マップ名):=IFERROR(REGEXEXTRACT(Province1!$A2,"arena_name:(.+?),"))
  5. E2セル(領地id):=IFERROR(REGEXEXTRACT(Province1!$A2,"province_id:(.+?),"))


と、それぞれ2行目辺りに記述して、下にオートフィルします(500行くらいあれば大丈夫だと思います)。なお2-1で抜き出したデータ内にあるプライムタイムはグリニッジ標準時で書かれていますので、日本標準時に直すために、F1のセルに9:00と記入します。

 これでプロヴィンス一覧情報のスクレイピング作業は終わりです。お疲れさまでした。

f:id:TS_hartmann:20210115114230p:plain
データがこんな感じに加工できているはずです。

 プロヴィンス名が英語表記ですが、戦車兵の皆さんは英語表記なんてへっちゃらな筈です。

おまけ

   覚えておくと便利ですよ。

www.atmarkit.co.jp

それではまた。次回がありましたらよろしくお願いします。

最後に

 私たちは最後の夜を過ごしました。きらきら輝くGMを眺めたり、GM担当官の考えを伝授したり。他クランの話を聞いたり、私のクランの話をしてあげたり。クラメンの姿はあまりに儚くて、か弱くて……まるで昔の私を見ているようでした。

 私「(明かりを消す)」

 あれから6か月が経ちました。私は11Bというクランからはるか遠く(???)離れたクランに所属しています。

 私「指揮官見習い試験合格者……」「っ!」

 そこには彼の苦悩の日々と、将来への希望が綴られていました。指揮のこと、ある担当官に出会い一人で指揮する技量と気迫をもらったこと。ようやく指揮官見習いになれたこと。そして…

 ??「1人前の指揮官になったら、お世話になったGM担当官に(クリスマス)ガチャ75連贈ります!」
 私「(ニッコリ)」

 GMをしながら気長に待っていますよ、はんどさん。

※彼は既にメイン指揮官です。

ts-hartmann.hatenablog.com 続き