【GAS】スプレッドシートにGmailからスクレイピング~GASでセルに関数を入れる~【第9回】
前回は、重複したデータが書き込まれないように対策しました。今回は、あらかじめ関数をいれてしまうとうまくGASが動かなくなる問題の対策をします。
目次
- 【GAS】スプレッドシートにGmailからスクレイピング~メールを検索して件名を表示~【第1回】
- 【GAS】スプレッドシートにGmailからスクレイピング~本文からデータを抜き出して表示~【第2回】
- 【GAS】スプレッドシートにGmailからスクレイピング~抜き出したデータの整理と関数化~【第3回】
- 【GAS】スプレッドシートにGmailからスクレイピング~日付データと配列化とソート~【第4回】
- 【GAS】スプレッドシートにGmailからスクレイピング~GmailIDと各データ取得~【第5回】
- 【GAS】スプレッドシートにGmailからスクレイピング~スプレッドシートの用意~【第6回】
- 【GAS】スプレッドシートにGmailからスクレイピング~スプレッドシートへの書き込み~【第7回】
- 【GAS】スプレッドシートにGmailからスクレイピング~重複しないようにする~【第8回】
- 【GAS】スプレッドシートにGmailからスクレイピング~GASでセルに関数を入れる~【第9回】
- 【GAS】スプレッドシートにGmailからスクレイピング~トリガー設定~【第10回】
今回やること
あらかじめ関数を入れてしまうと、GASがうまく動かなくなるので、GASで関数を入れてしまおうというのが今回の対策です。幸い、今回の関数の式には複雑なものがないので、サクッと入れてしまいましょう。
.setFormulaR1C1()
関数式を入れるメソッドです。getRangeしてから使います。RはRange、CはColumnを表します。例として連続日数を表す列の数式を入れる文を使います。例えば、C34に入れたい数式は以下です。
=IF(A34=(A33+1),C33+1,1)
.setFormulaR1C1では、基準となるセルからの行と列の移動数でセルを表します。ですので、C34から、A34は「RC[-2]」となり、C34からC33は「R[-1]C」と表現されます。ですので、上記の式は以下のようになります。
.setFormulaR1C1('=IF(RC[-2]=(R[-1]C[-2]+1),R[-1]C+1,1)')
GAS全体
function myFunction() {
const query ='さんの脳トレ記録をお届けします。';
const start = 0;
const max = 10;
const threads = GmailApp.search(query,start,max);
const st = SpreadsheetApp.openById('スプレッドシートID').getSheetByName('シート1');
const st2 = SpreadsheetApp.openById('スプレッドシートID').getSheetByName('シート2');
const fetchData = (str ,pre ,suf) =>{
const reg = new RegExp(pre + '.*?' + suf,'g');
const preg = new RegExp(pre,'g');
const sreg = new RegExp(suf,'g');
var data = str.match(reg);
var data1 = null;
if(data !== null){
data1 = data[0].replace(preg,'').replace(sreg,'');
}
return data1;
};
const fetchData1 = (str ,pre ,suf) =>{
const reg = new RegExp(pre + '*?' + suf,'g');
const preg = new RegExp(pre,'g');
const sreg = new RegExp(suf,'g');
var data = str.match(reg);
var data1 = null;
if(data !== null){
data1 = data[0].replace(preg,'').replace(sreg,'');
}
return data1;
};
const moment = (str1) =>{
const minute = str1.replace('分',':').replace('秒','.');
return minute;
};
var date10 = [['日付','経過日数','脳年齢','抑制力','処理速度','短期記憶','計算100','人数数え','ID']];
var calc1001 = null;
var people1 = null;
var calc250 = null;
var double_task1 = null;
var kanji1 = null;
var last_photo1 = null;
var finger_calc1 = null;
var finger_exe1 = null;
for(const thread of threads){
const messages = GmailApp.getMessagesForThread(thread);
for(const message of messages){
const plainBody = message.getPlainBody();
const id = message.getId();
const continuity = fetchData(plainBody,'脳トレ\\s','日目');
const date = fetchData(plainBody,'日目\\s','(');
const ba = fetchData(plainBody,'今回:脳年齢\\s','才');
const ba_suppression =fetchData(plainBody,'・抑制力\\s','才');
const ba_process = fetchData(plainBody,'・処理速度\\s','才');
const ba_memory = fetchData(plainBody,'・短期記憶\\s','才');
const calc100 = fetchData(plainBody,'計算100\\s・','(');
const calc25 = fetchData(plainBody,'計算25\\s・','(');
const ns_read =fetchData(plainBody,'新聞音読\\s・','音');
const song_perf = fetchData(plainBody,'名曲演奏\\s・','点(');
const people = fetchData(plainBody,'人数数え\\s・','/6問');
const kanji = fetchData(plainBody,'漢字合成\\s・','(')
const last_photo = fetchData(plainBody,'直前写真\\s・','(');
const ins_memory = fetchData(plainBody,'瞬間記憶\\s・','個(');
const finger_calc = fetchData(plainBody,'指計算\\s・','(');
const finger_exe = fetchData(plainBody,'指体操\\s・','(');
const double_task = fetchData(plainBody,'二重課題\\s・','(');
const sudoku_class = fetchData(plainBody,'数独(',')');
const sudoku_art = fetchData(plainBody,'・','問クリア');
const anecdote = fetchData1(plainBody,'川島教授の脳の小話\\s[\\s\\S]','\\s\\s\\s\\s')
if(calc25 !== null){
calc250 = moment(calc25);
}
else{calc250=null;}
if(calc100 !== null){
calc1001 = moment(calc100);
}
else{calc1001 = null;}
if(people !== null){
people1 = moment(people);
}
else{people1 = null;}
if(kanji !== null){
kanji1 = moment(kanji);
}
else{kanji1 = null;}
if(last_photo !== null){
last_photo1 = moment(last_photo);
}
else{last_photo1 = null;}
if(finger_calc !== null){
finger_calc1 = moment(finger_calc);
}
else{finger_calc1 = null;}
if(finger_exe !== null){
finger_exe1 = moment(finger_exe);
}
else{finger_exe1 = null;}
if(double_task !== null){
double_task1 = moment(double_task);
}
else{double_task1=null;}
date10.push([date,continuity,ba,ba_suppression,ba_process,ba_memory,calc1001,calc250,ns_read,song_perf,people1,kanji1,last_photo1,ins_memory,finger_calc1,finger_exe1,double_task1,sudoku_class,sudoku_art,id,anecdote]);
}
}
date10.sort(function(a,b){
return new Date(a[0]) - new Date(b[0]);
});
console.log(date10);
var j = date10.push();
console.log(j);
const hasId = id =>{
//getRange(行番号, 列番号, 行数, 列数)
const range = st.getRange(7,28,st.getLastRow()-6).getValues();
return range.flat().includes(id);
}
for(let k=1;k<j;k++){
const lastrow = st.getLastRow()+1;
if(hasId(date10[k][19])) continue;
//日付
st.getRange(lastrow,1).setValue(date10[k][0]);
//経過日数
st.getRange(lastrow,2).setValue(date10[k][1]);
//数式入れる
st.getRange(lastrow,3).setFormulaR1C1('=IF(RC[-2]=(R[-1]C[-2]+1),R[-1]C+1,1)');
//脳年齢
st.getRange(lastrow,4).setValue(date10[k][2]);
//脳年齢-抑制力-処理速度-短期記憶
st.getRange(lastrow,5).setValue(date10[k][3]);
st.getRange(lastrow,6).setValue(date10[k][4]);
st.getRange(lastrow,7).setValue(date10[k][5]);
//トレーニング結果-計算100-計算25-新聞音読-名曲演奏
st.getRange(lastrow,8).setFormulaR1C1('=IF(ISNUMBER(RC[1]),IF(RC[1]>1,IFERROR(("00:00:"&RC[1])*1),RC[1]),IFERROR(("00:"&RC[1])*1))');
st.getRange(lastrow,9).setValue(date10[k][6]);
st.getRange(lastrow,10).setFormulaR1C1('=IF(ISNUMBER(RC[1]),IF(RC[1]>1,IFERROR(("00:00:"&RC[1])*1),RC[1]),IFERROR(("00:"&RC[1])*1))');
st.getRange(lastrow,11).setValue(date10[k][7]);
st.getRange(lastrow,12).setValue(date10[k][8]);
st.getRange(lastrow,13).setValue(date10[k][9]);
//トレーニング-人数数え-漢字合成-直前写真-瞬間記憶
st.getRange(lastrow,14).setValue(date10[k][10]);
st.getRange(lastrow,15).setFormulaR1C1('=IF(ISNUMBER(RC[1]),IF(RC[1]>1,IFERROR(("00:00:"&RC[1])*1),RC[1]),IFERROR(("00:"&RC[1])*1))');
st.getRange(lastrow,16).setValue(date10[k][11]);
st.getRange(lastrow,17).setFormulaR1C1('=IF(ISNUMBER(RC[1]),IF(RC[1]>1,IFERROR(("00:00:"&RC[1])*1),RC[1]),IFERROR(("00:"&RC[1])*1))');
st.getRange(lastrow,18).setValue(date10[k][12]);
st.getRange(lastrow,20).setFormulaR1C1('=IF(ISNUMBER(RC[1]),IF(RC[1]>1,IFERROR(("00:00:"&RC[1])*1),RC[1]),IFERROR(("00:"&RC[1])*1))');
st.getRange(lastrow,19).setValue(date10[k][13]);
//トレーニング-指計算-指体操-二重課題-数独級-数独数-GmailID
st.getRange(lastrow,21).setValue(date10[k][14]);
st.getRange(lastrow,22).setFormulaR1C1('=IF(ISNUMBER(RC[1]),IF(RC[1]>1,IFERROR(("00:00:"&RC[1])*1),RC[1]),IFERROR(("00:"&RC[1])*1))');
st.getRange(lastrow,23).setValue(date10[k][15]);
st.getRange(lastrow,24).setFormulaR1C1('=IF(ISNUMBER(RC[1]),IF(RC[1]>1,IFERROR(("00:00:"&RC[1])*1),RC[1]),IFERROR(("00:"&RC[1])*1))');
st.getRange(lastrow,25).setValue(date10[k][16]);
st.getRange(lastrow,26).setValue(date10[k][17]);
st.getRange(lastrow,27).setValue(date10[k][18]);
st.getRange(lastrow,28).setValue(date10[k][19]);
const lastrow1 = st2.getLastRow()+1;
st2.getRange(lastrow1,1).setValue(date10[k][20])
}
}
実行結果
関数が書き込まれたので、連続記録が表示されるようになりました。また、この下は空白なので、何も書き込まれません。
最後に
今回は、関数をGASで書き込むことによって、GAS内の.getLastRowが正常に動き、スプレッドシートの中もきちんと書き込まれるようになりました。これで、GASとスプレッドシートは完成したので、次回はトリガーを設定して自分で実行しなくても、勝手に書き込まれるようにしていきたいと思います。
ディスカッション
コメント一覧
まだ、コメントがありません