Skip to content
困った時に思い出したい

[GAS]Google Apps Script がV8 Runtime に対応したので簡単なスクレイピング用コードを書き直してみる

javascript, google apps script1 min read

概要

仕事でもプライベートでもGoogle Apps Script (以下、GAS) を時々触るのだけど、GASは新しめのECMAScript構文は使えなくてコードがもっさりしがち。

それがどうやらこれまでのRhinoランタイムからV8ランタイムへ移行できるようになったようなので早速試してみた。

参考: V8 Runtime Overview | developers.google.com/

仕事でGASの簡単な解説記事をちょこちょこ書いており、そこに書いたコードをV8ランタイム用にリファクタリングしてみた。

元のコード

これはホームページの記事一覧から記事のタイトルとURLをスプレッドシートに転記するもの。あくまでもスクレイピングの入門的な内容。(社名に関連するところは置き換えてあるのでこのままでは動かないのはご了承願いたい)

※プログラムにまだそれほど馴染んでいないときに書いたものなので結構突っ込みどころは多い。

function scrapingSample() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('シート1');
var getUrl = 'http://www.example.com/page/1';
var content = UrlFetchApp.fetch(getUrl).getContentText('UTF-8');
var itemRegexp = new RegExp(/<a href=.*?" class="c\d{1,2}">/g);
var item = content.match(itemRegexp);
var items = [];
for (var i = 0; i < item.length; i++) {
var itemURL = item[i]
.replace('<a href=','')
.replace(/"/g,'')
.replace(/class=c\d{1,2}>/,'');
items.push([itemURL]);
}
var titleRegexp = new RegExp(/<title>.*?<\/title>/);
var titles = [];
for (var j = 0; j < items.length; j++) {
var itemCont = UrlFetchApp.fetch(items[j]).getContentText('UTF-8');
var title = itemCont.match(titleRegexp)[0]
.replace(/<\/*title>/g,'')
.replace(' | 株式会社hogehoge','');
titles.push([title]);
}
sheet.getRange(2, 1, titles.length, 1).setValues(titles);
sheet.getRange(2, 2, titles.length, 1).setValues(items);
}

V8ランタイムに移行する設定

公式ページのEnabling the V8 runtime に書いてある「メニュー」から切り替える方法が本記事執筆時点(2020-2-7)できないようだが、もう一方の方法として記載されているスクリプトマニフェストファイルを編集して移行ができた。

以下、公式ページの手順をGoogle翻訳したもの。

  1. Appsスクリプトエディターでスクリプトを開きます。
  2. [ 表示]> [ プロジェクトマニフェストを表示]を選択します。
  3. 結果のappsscript.jsonマニフェストファイルで、runtimeVersion フィールドをvalueに設定しますV8
  4. スクリプトを保存します

引用元: V8 Runtime Overview | developers.google.com/

マニフェストファイルの中身はこうなる。

“runtimeVersion”: “V8″を書き足す。

ちなみに”V8″の部分を”DEPRECATED_ES5″にすれば元に戻せる。

{
"timeZone": "Asia/Tokyo",
"dependencies": {
},
"webapp": {
"access": "ANYONE_ANONYMOUS",
"executeAs": "USER_DEPLOYING"
},
"exceptionLogging": "STACKDRIVER",
"runtimeVersion": "V8"
}

V8ランタイム用に書き直したGASのコード

function scrapSample() {
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('シート1');
const content = UrlFetchApp.fetch('http://www.example.com/page/1').getContentText('UTF-8');
const itemRegexp = new RegExp(/<a href=".*?" class="c\d{1,2}">/g);
const items = content.match(itemRegexp);
const itemList = items.map(item => [item.replace(/<a href="(.*?)" class="c\d{1,2}">/, '$1')] );
const titleRegexp = new RegExp(/<title>.*?<\/title>/);
const titleList = itemList.map(url => {
const itemCont = UrlFetchApp.fetch(url).getContentText('UTF-8');
return [itemCont.match(titleRegexp)[0].replace(/<title>(.*?) \| (.*?)<\/title>/,'$1')];
});
sheet.getRange(2, 1, titleList.length, 1).setValues(titleList);
sheet.getRange(2, 2, itemList.length, 1).setValues(itemList);
}

実行結果は同じだけど、だいぶスッキリした。

この内容の場合で大きく変わったのは、

  • 取得したaタグをreplaceしてURLだけを二次元配列に格納
  • 二次元配列内の各URLにフェッチしてタイトルタグの記事タイトル部分を別な二次元配列に格納

これをfor文でそれぞれ回していたのをmapに変えたことと、アロー関数も使ったので見た目はかなり簡潔になった。

※replace部分もスッキリさせたがここはV8には関係ないので割愛。

ちなみに実行時間が速くなるのではと期待したが、

  • そもそも時間のかからないスクリプトであった
  • mapはforよりもかなり遅い

といった理由によりそれほど大きくは変わらなかった。

もっと時間のかかるスクリプトなら結構差が出るのかもしれない。(未検証)

GASの使い勝手がさらに良くなるかもしれない

今回はさらっと試しただけなので使っていないが、クラスやテンプレートリテラルでだいぶ使い勝手が良くなりそう。

今度はもう少し大きなもので試してみよう。

© 2021 by 困った時に思い出したい. All rights reserved.
Theme by LekoArts