Slack,Zapierに連携アプリが無くても大丈夫! LambdaでPuppeteerを動かせばいいのさ

f:id:tsukahara1991:20211209022736j:plain

みなさんこんにちは。M&Aクラウドでエンジニアをしています塚原(@AkitoTsukahara)です。 弊社のアドベントカレンダーの12日目を担当させてもらっています!

弊社では様々な業務を自動化する取り組みが活発です。エンジニアチームであれば、GitHubのPR通知やFigmaのメッセージ連携などSlackアプリやZapierを利用して、自動化しており、SlackアプリやZapierのお陰で自動化の幅はかなり広がっています。

f:id:tsukahara1991:20211208232252p:plain よく利用するSlackアプリ

一方で連携機能が提供されていないサービスは自動化し辛くなっています。 1つの例として、勤怠管理システムで考えていきましょう。弊社ではリモートワーク時に勤怠管理システムにログインして、出退勤のボタンを押す必要があります。ちょっとの手間ですが、ついつい忘れてしまったりして、月末に勤怠漏れ修正の報告依頼しないといけません。報告するだけで済めば良いのですが、修正報告は上長、コーポレート担当者の承認が必要です。1つの報告あたり1人1分かかるとして、全社員が数回打刻漏れしているとすれば、結構な時間を修正報告に時間を費やしていることになります。この非効率な作業を少しでも減らせるように、勤怠入力を自動化していきたいですね。

そこで今回はSlackやZapierで連携機能が提供されていないツールでも自動化する方法を紹介いたします🙋‍♂️

アーキテクチャ

f:id:tsukahara1991:20211209180814p:plain

  1. Slackの入力をトリガーにAWS Lambdaに実装されたAPIにPOSTリクエス
  2. AWS Lambdaではpuppeteerを利用して、ブラウザ操作して「出退勤」入力
  3. AWS Lambdaからのレスポンスデータを受け取り、Slackメッセージを送信

このアーキテクチャのポイントはAWS LambdaでZapierからのリクエストを受けて、Puppeteerを起動させているところになります。

※Puppeteer
PuppeteerはHeadlessChromeを利用して機械的にブラウザを操作できるNode.jsライブラリです。今回は「MF勤怠にログインして、出退勤ボタンを押す」という一連の操作を自動化しています。

AWS Lambda
AWS LambdaはAWSが提供するサーバレスコンピューティングサービスです。利用者はプログラムコードを準備し、Lambdaにアップロードするだけでプログラムを実行することができるようになります。今回はPuppeteerを利用するコードをLambdaにアップロードして、Slackから呼び出せるようにしています。

STEP1

エンジニアチームではメンバー同士の稼働状態を確認するために、出勤時に「SK」、退勤時に「TK」とSlackにメッセージするルールになっています。今回のMF勤怠入力のトリガーはこの「SK」、「TK」というワードがSlackにメッセージされることにしましょう。出退勤報告とMF勤怠入力が両方できてまさに一石二鳥ですね。

STEP1ではSlackでの入力を受けて、APIにリクエストできるようにZapierを設定しています。

まずはSlackの入力を検知します。 ZapierのSlack連携トリガー「New Message Posted to Channel in Slack」で出退勤報告するチャネルを指定し、 次のAction「Only continue if...」で自分のアカウントのみで実行されるようにSlackのUserIDが設定されています。 Action「Conditionally run...」では出勤と退勤処理を分けられるようになっています

f:id:tsukahara1991:20211209015709p:plain

次にAPIにリクエストできるようにします。 出勤(PathA)の処理を設定していきます。 ActionのPOSTに必要になるデータを入力します。 URLにはAWS Lambda APIのPATH、 Id,mail,passwordにはMF勤怠に必要なログインデータを入力します。

f:id:tsukahara1991:20211209015739p:plain

STEP2

Puppeteerを起動するAPIの設置場所にAWS Lambdaを利用しています。

Puppeteerを利用するにはchrome-aws-lambda をLambda Layerとして登録しておく必要があります。詳しくはこちら

Lambda上で実行されるコードは以下のものを用意しました。 「MF勤怠にログインして、出退勤ボタンを押す」という操作をコードに直したものになります。

'use strict'
const chromium = require('chrome-aws-lambda')
const puppeteer = require('puppeteer-core');

exports.handler = async (event, context) => {
  
  const stamp = event.stamp;
  const id = event.id;
  const mail = event.mail;
  const password = event.password;
  
  const browser = await puppeteer.launch({
    //headless: true,  // ブラウザが動く様子を確認する
    //slowMo: 300,  // 動作確認しやすいようにpuppeteerの操作を遅延させる
    args: chromium.args,
    defaultViewport: chromium.defaultViewport,
    executablePath: await chromium.executablePath,
    headless: chromium.headless,
  });
  const page = await browser.newPage();

  //chromeを開く
  await page.goto('https://attendance.moneyforward.com/employee_session/new');
  // ログイン情報を入力
  await page.type('#employee_session_form_office_account_name', id, { delay: 50 });
  await page.type('#employee_session_form_account_name_or_email', mail, { delay: 50 });
  await page.type('#employee_session_form_password', password, { delay: 50 });
  //ログイン
  await page.click('input[type="submit"]');

  // 2秒読み込みをまつ
  await page.waitForTimeout(2000);

  if (stamp === 'SK') {
      //「出勤」
      await clockIn(page);
  } else {
      //「退勤」
      await clockOut(page);
  }
  
  await browser.close();
  return context.succeed('OK');
};

const clockIn = async (page) => {
  await page.click('.attendance-card-time-stamp-clock-in');
};

const clockOut = async (page) => {
  await page.click('.attendance-card-time-stamp-clock-out');
};
コードをかけなくても大丈夫?

エンジニアでない方にはいきなり出てきたソースコードでびっくりさせてしまったかもしれませんね。。 でも「自分はコードは書けないから無理かな」と諦めるにはまだ早いですよ!

Google ChromeではWebブラウザ上の操作を記録、再実行、編集、保存さらにはPuppeteerスクリプトのエクスポートができる機能がリリース予定。この機能を活用すれば、ほとんどコードを書かずとも上記のコードと同じようなものを用意できるかもしれません。 リリース時期は2022年の1月頃となっています。期待してこの機能リリースを待ちましょう!

Chrome DevToolsドキュメント「Record, replay and measure user flows

STEP3

打刻に成功しているとAPIから”OK”とレスポンスが返ってくるので、それを受け取ってSlackに打刻完了しました。とメッセージを送信できるように設定しています。

f:id:tsukahara1991:20211209020122p:plain

以上がおおまかな設定方法と処理の流れとなっております。 今回のようにAWS LambdaにAPIを設置するとネットワーク経由で自動化のリクエストができるようになり、Puppeteerを利用してブラウザ操作を自動化することができます。この組み合わせを応用していけば、多くの業務が自動化できるのではないでしょうか。

補足

自動化しようと試行錯誤する前にやっておきたい事前確認

  • 業務データに関わることは関係者に自動化OKか
  • すでにSlackなどで連携機能が提供されていないか

自動化してみたものの利用できなかったり、同じようなものがあったりと無駄な作業が発生しないようにしましょう。 自分も社内メンバーに事前確認したり、連携機能がないか確認しました。 リリース当初からSlackアプリを検討していると記述がありましたが、その記事は2年前。。。 是非ともMoney ForwardさんにはSlackアプリを提供いただきたいです🙏

今回の勤怠入力自動化は自分個人しか利用できない形になっていますが、今後は仕様・機能を整備して社内メンバーが利用できるように拡張していこうと考えています。 そのために越えないといけない課題は

  • 打刻失敗時の検知方法
  • 複数人のSlack ID管理
  • MF勤怠のログインID・パスワードの管理 etc

もっと良い実装方法がないのか社内エンジニアにレビューしてもらって、機能拡張やっていきます💪

まとめ

いかがだったでしょうか? 連携アプリが提供されていなくてもAPIを自前で用意することができれば、ツール同士の連携・自動化が可能になります。 自動化したいけれど諦めたままになっている業務があれば、ぜひ今回の手法を応用して挑戦してみてください。

みなさんの業務自動化に少しでも力になれましたら幸いです🙇‍♂️

明日は中名生さんです!