【GAS】DeepLAPIを使って英文ブログを翻訳する(後半)
▼前回のおさらい
azumikan.hatenablog.com
いよいよGASで差分をとって、
ブログの英文をDeepLで翻訳します。
今回のスクリプトの流れ
1.スプレッドシートで更新を検知したらブログの文章を取り込む
↓
2.雑に1000文字ずつに区切って、バンバンAPIになげる
↓
3.返ってきた日本語を配列に格納して成形
↓
4.日本語をメールに流す
1.スプレッドシートで更新を検知したらブログの文章を取り込む
英語のブログ…MSの公式のブログを今回はとってくるのですが、
RSSからIMPORTFEED関数を使って
文章まで一気にとってきます。
▼取り方はこんな感じ。
更新があった際にGASを動かすようにします。
azumikan.hatenablog.com
トリガーは日次で発火します。
2.雑に1000文字ずつに区切って、バンバンAPIになげる
※API利用で注意すること
①APIの一度のリクエストは30kbまでなので、たくさん投げすぎるとエラーで翻訳できません。
②DeepLには一文ずつも投げられますが、一文ずつの場合1リクエストで50文まで。
③urlfetchappを使うのですが、連続でアクセスしすぎると、たまに止まるらしい。(ドキュメント記載なし)
最初一文ずつ投げないのかと行けないと思ったら雑に改行コードつきでも長文を投げられることが判明。
しかし、一気にAPIに放り込んで全部訳そうとしたら、キャパオーバーなのか死んだので
1000文字ずつくらいに区切るといい感じになります。
区切る際は良い感じの区切り部分(句読点、改行、感嘆符など)で区切るとさらにいい感じです。
ちなみに↓のコードはリクエストのエラー処理していない処理ですが、そこは許して…。
4.日本語をメールに流す
完成!
そしてDeepLから返ってきた日本語、長文は途中で文書が抜けたり、ダブったり
日本語はそれっぽいけど内容が怪しかったりもする…。
ので、完璧なに和訳ではないですが、ざっくり概要把握にはいいかも。
ところどころハードコーディングですが、
完成したコードがこちら:
// シートの新旧で更新を比較 // トリガーに設定するのはこの関数 // C1にFALSEの件数を反映させます。 function copySheet() { const ss = SpreadsheetApp.getActiveSpreadsheet(); const sheet_new = ss.getSheetByName('new'); const sheet_old = ss.getSheetByName('old'); const lastRow = sheet_new.getLastRow(); const lastColumn = sheet_new.getLastColumn(); const copyValue = sheet_new.getRange(1,1,lastRow,lastColumn).getValues(); sheet_old.getRange(1,1,lastRow,lastColumn).setValues(copyValue); const data = sheet_old.getDataRange().getValues(); // C1がFALSEだったら更新通知 if (data[0][2] > 0){ console.log("FALSEがあります"); sendMail(data); } } // メールを送るスクリプト // 引数はシートのセル情報 function sendMail(dt) { const strTo = "example@example.com"; const strSubject = "【自動送信】英語のブログに更新がありました"; // シートからとってきたブログURLやら文書やらを格納※ハードコーディングですみません const text = dt[5][5]; const translation = splitTxt(text); const strBody = "▼ブログURL:" + dt[5][3] + "\n" + "▼DeepL翻訳:" + "https://www.deepl.com/ja/translator"+ "\n" + "▼記事名:" + dt[5][1] + "\n" + translation; /* メールを送信 */ GmailApp.sendEmail( strTo, strSubject, strBody ); } // 英文を分割してAPIに送り出すところまでの関数 function splitTxt(str){ // パラグラフをセンテンスに分割 const array = str.replace(/(\.+|\:|\!|\?)(\"*|\'*|\)*|}*|]*)(\s|\n|\r|\r\n)/gm, "$1$2|").split("|"); // APIに投げる文字列を入れる配列 let apiArr = []; let countArr = []; let text = ''; for(let i = 0; i <= array.length; i++){ // 1000字までは配列に格納 if(text.length < 1000){ text = text + array[i]; }else{ // 1000字超えたら apiArr.push(text); countArr.push(i); text = ''; } } text = ''; // console.log(count[0]); // console.log(count.length); for(let i = countArr[countArr.length-1]; i <= array.length; i++){ text = text + array[i]; } apiArr.push(text); return DeepLTool(apiArr); } // APIに送り出して日本語にする関数 // 引数はブログの英語本文 function DeepLTool(transArr) { console.log(transArr); const DeepLURL = 'https://api-free.deepl.com/v2/translate?auth_key='; const authkey = 'APIのトークン'; let transresult = []; let fetchUrl = ''; let response = ''; let results = ''; for (const element of transArr) { // 必要に応じて設定変えるともっとましなのかもしれない… fetchUrl = DeepLURL + authkey + '&text=' + encodeURI(element) +'&target_lang=ja&source_lang=en&preserve_formatting=1'; response = UrlFetchApp.fetch(fetchUrl); results = JSON.parse(response.getContentText()); transresult.push(transJSON(results)); } return transresult.join(''); // return transJSON(results); } // 受け取ったJSONをテキスト化 function transJSON(JSONdt){ let results = JSON.parse(JSON.stringify(JSONdt)); let trans = results.translations[0].text; return trans }