前回はいよいよスクレイピングを開始してみました。
単一な情報取得をし、それをセルに出力するという流れでしたが理解できたでしょうか?
で、前回の終わりで書いていたように今回は複数のテキスト(情報)を取り出す・処理する方法を探っていきたいと思います(*’ω’*)
追加したライブラリの内容をみてみる
手軽に使える素敵なライブラリであるParser。その作者のページでそのライブラリの内容が確認できます。
https://www.kutil.org/2016/01/easy-data-scrapping-with-google-apps.html
トップページで下にスクロールすると
Completed cpde of Paser library というリンク部分があるので、それをクリックすると内容がみられます。
コードが読める方はどういうことなのか見てみるのも面白いですよ~。
さて、ざっとみてみると「from」や「to」のほかにも何やらあるようですね。
そして今回使うのが…
この.iterateです。
whileがあることからもわかるように、繰り返しで取り出してくれます。
これを使うことで複数あるデータを抽出するのも楽々。。。となると思われますw
というわけで、コードを改良してみましょう。
h2タグの中身を全部出してみよう~
いきなりコードから。
buildがiterateに代わっているぐらいなので、前回の復習がてら確認してもらえばと思います。
var fetch = UrlFetchApp.fetch(“https://tks-kan.com/”);
var response = fetch.getContentText();
var searchResult = Parser.data(response)
.from(‘<h2>’)
.to(‘</h2>’)
.iterate();
Logger.log(searchResult);
確認はロガーを使用しています。
実行完了したらctrl+enterでみてみましょう。
みごとに取り出せてますね!
複数個でも簡単簡単…ということで、ここからさらにタイトル文字(テキスト)のみを取り出してみたいと思います。
繰り返し処理でサクッと
ここからはいわゆるJavascriptと同じ流れ。
取り出して入れておいたsearchResultの個数分をforで繰り返して、前回同様にテキスト部分をParserを使ってサクッと取り出して…って流れで行けそうかなと考えました。
ということで書いてみたコードがこちら。
for (var i=0; i<searchResult.length; i++) {
outputTitle[i] = Parser.data(searchResult[i])
.from(‘title=”‘)
.to(‘”>’)
.build();
}
outputTitleの方も配列タイプで宣言して代入するようにしています。
で、結果をログに出力して確認してみるので、
と変更、結果をみてみると…(ctrl+enter)
…gasばっかりですねw
ひとまず、これで目的のモノは取り出せてかなと思います(*’ω’*)
次はセルに出力!
まとめてセルに出してみる
ここでのポイントは「まとめて」という部分ですね。
1個1個出力していってもいいんですが、処理に時間がかかってしまうのでまとめて出力することで、時間短縮になる(らしいです)。
そもそもGAS自体が実行時間に制限があり、それを「6分の壁」というみたいです。
※ちなみにそれを回避するためのテクニック、調べれば色々と出てきます。
そのひとつでもあるのがまとめて出力だったりします(*’ω’*)
とはいえ、outputTitleを配列にしてあるのでこのままでも行けそうじゃんって思えるんですが…以下のコードをやってみると
「ArrayをObject[][]に変換できません。」とエラー表示が出て怒られてしまいます。
ちなみにコード上の変更点は
- getRange部分の第3番目にセルの範囲を指定するためにタイトルの数をlengthで
- setValueを複数であるsetValuesに変更
です、ご注意くだされ。
話は戻って…このエラーよくみると「[][]」と書かれていたりします。
これが示すものはたぶん2次元配列じゃないかと調べてみると…
https://qiita.com/ShishidoToru/items/0ab9de4ea281df9358f4
「【GAS】エラー「ArrayをObject[][]に変換できません。」に遭遇したら・・・」
とまさにドンピシャのページが。
で、みてみるとやはり2次元配列に入れなおして処理することでうまく行く様子。
(引用させていただいておりますm(__)m)
ということで、同じようにpushを使って2次元配列化してみてから、実行してみました。
var ary = [];
for (var i=0; i<outputTitle.length; i++) {
ary.push([outputTitle[i]]);
}
var s = SpreadsheetApp.getActiveSheet();
s.getRange(1,1, ary.length).setValues(ary);
こんな感じ。
すると…
イエーイ! バッチリできました(*’ω’*)
ついでなのでfunctionで呼び出す用に改善
ということで、頻繁に使う可能性がありそうなので別にして呼び出す形をとってみようかなと。
こんな感じのコードで書いてみました。
var ary = [];
for (var i=0; i<text.length; i++) {
ary.push([text[i]]);
}
sheet.getRange(col, row, ary.length).setValues(ary);
};
sheetには取得したシートを、textは出力したい1次元配列化してある文字列、col,rowはそれぞれ列と行に対応です
まとめ
複数の情報取り出しとそれを一発でセルに反映させることができました。
スクレイピングっぽくなってきましたよね!
最後に今回のコードをまとめて下に記載しますので、よかったら試してみてください。
何かの参考になれば幸いです~
今回のコード
function onOpen(){
var s = SpreadsheetApp.getActiveSpreadsheet();
var mylist = [
{
name : “html取得実行”,
functionName : “myFunc01”
}
];
s.addMenu(“スクリプト実行”, mylist);
};
function myFunc01(){
var fetch = UrlFetchApp.fetch(“https://tks-kan.com/”);
var response = fetch.getContentText();
var searchResult = Parser.data(response)
.from(‘<h2>’)
.to(‘</h2>’)
.iterate();
var outputTitle = [];
for (var i=0; i<searchResult.length; i++) {
outputTitle[i] = Parser.data(searchResult[i])
.from(‘title=”‘)
.to(‘”>’)
.build();
}
var s = SpreadsheetApp.getActiveSheet();
sheetSet(s, outputTitle, 1, 1);
// Logger.log(searchResult);
// Logger.log(outputTitle);
}
function sheetSet(sheet,text,col,raw) {
var ary = [];
for (var i=0; i<text.length; i++) {
ary.push([text[i]]);
}
sheet.getRange(col, raw, ary.length).setValues(ary);
};