LoginSignup
18
8

More than 1 year has passed since last update.

今回の記事も業務効率化です。
ホームページの更新を通知してもらうと共に、詳細を簡単に調べられるようにしたツールとなります。

月1回のルーティンだからこそ効率化する

 何度か私は経営戦略部(一般的な企業だと経営企画と言われることが多いと思います。)に所属していることをお話しているかと思います。経営企画の業務の中でもIR:Investor Relations(投資家向け広報)は私の担当範囲です。月1回の月次営業情報の更新など、高頻度に実施しているわけではありませんが、株主さまや投資家の方に自社の取り組みを周知する上で、必要不可欠と言えます。

 また、競争企業のIR情報をまとめておくことは、競争の戦略や業界全体のトレンドを把握した上で、自社の立ち位置を知ることができるため、これも重要な取り組みです。しかしながら、

  • 月に1回しか実施しないため、更新を失念する
  • 更新されていると思い、他社ホームページを見に行くと、まだ更新されていないことがある
  • 数ある企業のホームページを回り、数値をまとめることが手間

といった問題点があり、十分な実施状況とは言えず、改善が必要と考えました。

今回のプロダクト

スライド1.JPG

全体概要は図の通り

  1. integromatを用いて以下の作業を自動化
    1. RSSより目的企業のIR更新を取得
    2. 更新内容をGoogleスプレッドシートに記載
    3. 更新をLINE Notifyで通知
  2. Google Apps Script (GAS) を用いて以下の作業を自動化するLINE Botを構築
    1. 通知された企業名をLINE Botに入力
    2. Google Apps ScriptでGoogleスプレッドシートに記載されたURLを取得
    3. URLをリプライメッセージで通知

各ツールの選定理由

integromat
 IFTTT,Zapierと比較して拡張性が高く、細かいカスタマイズができます。今回はプロトタイプとして1企業分を実装しましたが、今後複数企業を実装することを視野に入れ選択しました。

LINE Messaging API
 今回の実装内容であれば、単純に更新URLをLINE Notifyで通知するだけでも可能ですが、今後、スプレッドシートに更新された経営数値を自動で記録するところまで実装することを考えています。同様にカスタマイズ性の高いリプライメッセージを送れるLINE Messaging APIをシステムの中に実装しました。

GAS
 常時更新を通知するために、サーバーのデプロイが必要と考えました。スプレッドシートとの連携がとりやすいことを考え、GASを用いて実装しました。

実際の仕様・動作

integromat部分

Watch RSS feed items とGoogle Sheetsを連携


実際の出力(retrive RSSを使用して疑似的に作成)
1行目に左から、更新内容、分類、URL、日時を入力しヘッダーとして使用
通知については後述


この後、LINE BotではGoogleシート上の情報を参照するため、シートが更新されたことを通知

LINE Bot部分

November 24, 2021 at 0553PM.gif
LINE Botに企業名を入力(今回は都合上、具体的な企業名を入力しておりません。実際はシート名を企業名とし、シート毎に管理する想定です。)。更新されたURLがリプライメッセージとして返ってきます。
URLから企業ページにアクセスして、数値をまとめます。


通知した更新情報はE列に"TRUE"が入力されます。ログとして活用しつつ、重複通知を防ぎます。

サンプルコード

詳細はこちら展開ください
const channelAccessToken = 'LINE Messaging APIより取得';

const ss = SpreadsheetApp.getActiveSpreadsheet();
console.log (ss.getName());


//LINE Messaging APIからPOST送信を受けたときに起動する
// e はJSON文字列
let doPost = (e) => {
  if (typeof e === "undefined"){
    //動作を終了する
    return;
  } else {
    //JSON文字列をパース(解析)し、変数jsonに格納する
    const json = JSON.parse(e.postData.getDataAsString());

    //変数jsonを関数replyに渡し実行
    reply(json)
  }
}

let reply = (data) => {
  const replyUrl = "https://api.line.me/v2/bot/message/reply";

  const reply_token = data.events[0].replyToken; //reply token
  const text = data.events[0].message.text; //ユーザーが送信した語句

  //返信語句を格納するための空配列を宣言する
  let replyTextList = [];

  const sheet = ss.getSheetByName(text);
  console.log (sheet.getName());
  const lastRaw = sheet.getLastRow();
  console.log(lastRaw);

  for(let i = 2 ; i < lastRaw + 1 ; i++){
    if(!sheet.getRange(i, 5).getValue()){
      let range = sheet.getRange(i, 3);
      console.log(range.getValue());
      replyTextList.push(range.getValue());  //通知していないURLをreplyTextにpushする
      sheet.getRange(i, 5).setValue(true); //今回通知したURLのシートにtrueを書き込む
    }
  }
   //全て通知済みの場合、関数を終了する ※
   if(replyTextList.length < 1) {
     return;
   //replyTextListのLengthが5より大きい場合、messageLengthを5にする※一度に最大5つの吹き出ししか返信できないため
   } else if(replyTextList.length > 5) {
     var messageLength = 5;
   } else {
    var messageLength = replyTextList.length;
  }
 //改善案あり※

  //"messages"に渡す配列を格納するための空配列を宣言する
  //[{"type": "text", "text": "返信語句その1"},{"type": "text", "text": "返信語句その2"}....]
  const messageArray = [];
    //replyTextListに格納されている返信語句を最大5つ、messageArrayにpushする
  for(let j = 0; j < messageLength; j++) {
    messageArray.push({"type": "text", "text": replyTextList[j]});
  }

  const headers = {
    "Content-Type": "application/json; charset=UTF-8",
    "Authorization": "Bearer " + channelAccessToken,
  };

  const postData = {
    "replyToken": reply_token,
    "messages": messageArray
  };

  const options = {
    "method" : "post",
    "headers" : headers,
    "payload" : JSON.stringify(postData)
  };

  //LINE Messaging APIにデータを送信する
  UrlFetchApp.fetch(replyUrl, options);
}

改善箇所
   //全て通知済みの場合、関数を終了する ※
   if(replyTextList.length < 1) {
     return;
   //replyTextListのLengthが5より大きい場合、messageLengthを5にする※一度に最大5つの吹き出ししか返信できないため
   } else if(replyTextList.length > 5) {
     var messageLength = 5;
   } else {
    var messageLength = replyTextList.length;
  }
 //改善案あり※

試せていないですが、var使わない方が良いので、以下のコードの方が良いと思います。

   //replyTextListのLengthが5より大きい場合に備え、別の変数で管理
  let messageLength;

   //全て通知済みの場合、関数を終了する ※
   if(replyTextList.length < 1) {
     return;

   } else if(replyTextList.length > 5) {
     messageLength = 5;
   } else {
     messageLength = replyTextList.length;
  }
 //改善案あり※

GASの実装過程

以下の記事を見ながら作成ください。

職場で実際に公表して

率直に驚かれました。
一生懸命作った甲斐があったと思います。
拡張性が高いことも伝わったので、継続的に発展させてほしいというコメントもいただけました。

しかし、これでもっと競争の分析を深められそうというコメントもいただくこととなり、自動化したはずなのに仕事は増えるんだよなあというジレンマも感じました。

結びに

ここ最近リテールテックにお熱です。

実はこんなアドベントカレンダー企画も推進しております。

  • 小売業以外の方からの、実はこんな技術が使えるのでは?という提案
  • 技術的な実装はできていないが、こんな企画を考えてみたという案

等々お待ちしています。
特に、企画案はカレンダーの前半に記載していただければ、私が後半に実装してみた記事を上げるかもしれません笑

18
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
18
8