Quantcast
Channel: いつも隣にITのお仕事
Viewing all 2074 articles
Browse latest View live

Windowsのポチポチ業務を爆速化するPowerShell、日付を操るDatetime型

$
0
0

みなさんこんにちは、テラド(@terashin1226)です!

PowerShellで西暦を和暦にサクッと変換する方法をお伝えしています。

前回はelseifステートメントで日付の元号を判定する方法をご説明しました。

Windowsのポチポチ業務を爆速化するPowerShell、elseifで日付の元号を判定する方法
Windowsのポチポチ業務(マウスを使った業務)を爆速化するPowerShell。今回はelseifステートメントを使って与えられた日付の元号を判定する方法をお伝えします!

今回はPowerShellで日付を扱うDatetime型についてお伝えします。Datetime型を使って日付から「年」だけを取り出し和暦を計算し、西暦を和暦に変換する関数を完成させますよ!

それではいってみましょう!

前回のおさらい

PowerShellをコンソール上からサクッと西暦を和暦に変換する方法を以下のステップでお伝えしています。

  • 関数を短い名前で呼び出せるエイリアスについて ← 説明済
  • 関数とエイリアスをいつでも呼び出し可能にするプロファイルについて ← 説明済
  • 西暦を和暦へ変換する関数を作成する ← 今回さらに説明
  • 完成した関数とそのエイリアスをプロファイルに登録する ← 今回説明

前回は複数条件の判定ができるelseifステートメントをご紹介し、元号の判定をするスクリプトが完成しました。

Function Ad-Conversion($indate){
 
    $ERA_MEIJI = "明治"
    $ERA_TAISYOU = "大正"
    $ERA_SYOUWA = "昭和"
    $ERA_HEISEI = "平成"
 
    $DATE_MEIJI = 18680908 
    $DATE_TAISYOU = 19120730
    $DATE_SYOUWA = 19261225
    $DATE_HEISEI = 19890108
 
    if($indate -lt $DATE_MEIJI){
 
        Write-Host("明治以前の日付には対応していません。")
 
    }elseif($indate -lt $DATE_TAISYOU){
 
        Write-Host("元号は" + $ERA_MEIJI + "です。")
 
    }elseif($indate -lt $DATE_SYOUWA){
 
        Write-Host("元号は" + $ERA_TAISYOU + "です。")
    
    }elseif($indate -lt $DATE_HEISEI){
 
        Write-Host("元号は" + $ERA_SYOUWA + "です。")
    
    }else{
 
        Write-Host("元号は" + $ERA_HEISEI + "です。")
 
    }
}

「明治より前?」(if)

→「いいえ。」

「じゃあ大正より前?」(elseif)

→「いいえ。」

「じゃあ昭和より前?」(elseif)

→「はい」

「じゃあ元号は大正だね!」

というようにelseifステートメントで複数の条件を判定し、元号を判定することができました。

このスクリプトでは、比較の際に日付を8桁の数字として扱いました。

$DATE_MEIJI = 18680908

今回はPowerShellで日付同士の大小比較ができるDatetime型という変数の型をご紹介します。Datetime型は日付から年・月・日を取り出すこともでき、日付を扱うのに非常に便利なんです!

変数の型とは

Datetime型の前に「変数の型」をご説明します。

変数はデータを一旦入れておく箱のような役割を持ちますが、変数の型はその箱にどんな種類のデータを入れられるかを示します。

これまで数値はそのまま代入、文字列はダブルコーテーションで囲って代入していましたよね。

$num1 = 1
$num2 = 5.5
$str = ”これは文字列です"

PowerShellでは代入した値によって「型」を自動で設定してくれる機能があります。

実際に型を確認してみましょう。

GetTypeで型を確認する

型を確認するにはGetTypeという機能を使います

変数の後にドット「.」をつけてGetType()と書けばOKです。

変数.GetType()

コンソールでの代入が終わったら

GetType()を実行します。

「Name」に表示された「Int32」「Double」「String」が変数の型です。代入した値によって変数の型が変わっていますね

変数の型には以下のような種類があります。

説明
Int32 整数
Double 実数(小数点を含む数)
String 文字列
Datetime 日付

Datetime型の変数を作成する

変数の型を理解したところで、Datetime型の変数を作ります。

Datetime型に値を代入するとき年・月・日の3つは必須です。3つを「/」(スラッシュ)か「-」(ハイフン)で区切り、「”」(ダブルコーテーション)で囲って代入します。

$date = "2019/5/5"

型の確認をしてみると…

あれ!文字列の型であるString型になってしまいました…

数値(整数と実数)や文字列と違い、Datetime型を使用するには、そのことを宣言する必要があります。

型を宣言する方法

[型名]を変数の前に書けば、型を宣言できます

[型名]$変数名 = 値

$dateという変数であれば以下のようになります。

[Datetime]$date = "2019/5/5"

コンソールで入力し、GetTypeを実行すると…

Datetime型になりました!

変数$dateをコンソールで入力すると…

日付の形式で表示されていますね!

でも、代入していない時刻「0:00:00」まで設定されています。Datetime型は年月日と時刻で成り立ちます。時刻を加えたい場合は日付の後ろに半角スペースを空けて「”yyyy/mm/dd 00:00:00″」形式で入力すればOKです。

Datetime型で「年」だけ取り出す

Datetime型の変数では、Year・Month・Day・Hourなど日付の必要な情報だけ取り出せます。

変数名の後ろにドット「.」を付けて「Year」と指定すると年だけを取り出せます

変数名.Year

月の場合は「Month」、日の場合は「Day」、時刻の場合は「Hour」を指定します。

変数$dateの「年」を取り出してみましょう。

$date.Year

コンソールで実行してみると…

年=「2019」だけが表示されました!

Datetime型を使って西暦を和暦に変換するスクリプト

Datetime型を使って前回のスクリプトを修正します!

Datetime型でスクリプトを書き換える

前回作成したスクリプトは以下の通りです。

Function Ad-Conversion($indate){

    $ERA_MEIJI = "明治"
    $ERA_TAISYOU = "大正"
    $ERA_SYOUWA = "昭和"
    $ERA_HEISEI = "平成"

    $DATE_MEIJI = 18680908 
    $DATE_TAISYOU = 19120730
    $DATE_SYOUWA = 19261225
    $DATE_HEISEI = 19890108

    if($indate -lt $DATE_MEIJI){

        Write-Host("明治以前の日付には対応していません。")

    }elseif($indate -lt $DATE_TAISYOU){

        Write-Host("元号は" + $ERA_MEIJI + "です。")

    }elseif($indate -lt $DATE_SYOUWA){

        Write-Host("元号は" + $ERA_TAISYOU + "です。")
    
    }elseif($indate -lt $DATE_HEISEI){

        Write-Host("元号は" + $ERA_SYOUWA + "です。")
    
    }else{

        Write-Host("元号は" + $ERA_HEISEI + "です。")
 
    }
}

1行目~11行目の引数$indateと元号の開始日をDatetime型に指定し、日付の形式のまま大小比較ができるようにします。

Function Ad-Conversion([Datetime]$indate){

    $ERA_MEIJI = "明治"
    $ERA_TAISYOU = "大正"
    $ERA_SYOUWA = "昭和"
    $ERA_HEISEI = "平成"

    [Datetime]$DATE_MEIJI = "1868/9/8"
    [Datetime]$DATE_TAISYOU = "1912/7/30"
    [Datetime]$DATE_SYOUWA = "1926/12/25"
    [Datetime]$DATE_HEISEI = "1989/1/8"

日付が「明治の開始日」より前の場合、15行目で「明治以前の日付には対応していません。」とメッセージを表示していますが、結果出力は不要なのでその後すぐにexitという命令で関数を強制終了します。

Write-Host("明治以前の日付には対応していません。")
        exit

元号が判定された後、日付から「年」だけ取り出し「(入力された日付の年) – (元号の開始日の年) + 1」と和暦を計算します。計算結果は$yearという変数に代入します。

元号が明治の場合は19行目を

$year = $indate.Year - $DATE_MEIJI.Year + 1

に書き換えます。

結果出力で使用するため、元号を変数$Eraに代入する処理を追加します。

$ERA = $ERA_MEIJI

それぞれの元号の場合(23,27,31行目)も同様に書き換えます。

最後にelseif内で判定した元号:$ERA、計算した和暦:$year、引数:$indateのMonth・Dayを使って「元号gg年mm月dd日」形式で結果を出力します。

Write-Host ($ERA + $year + "年" + $indate.Month +"月" + $indate.Day + "日")

最終的なスクリプトは以下の通りです。

function Ad-Conversion([Datetime]$indate){
    
    $ERA_MEIJI = "明治"
    $ERA_TAISYOU = "大正"
    $ERA_SYOUWA = "昭和"
    $ERA_HEISEI = "平成"

    [Datetime]$DATE_MEIJI = "1868/9/8" 
    [Datetime]$DATE_TAISYOU = "1912/7/30"
    [Datetime]$DATE_SYOUWA = "1926/12/25"
    [Datetime]$DATE_HEISEI = "1989/1/8"
    
    if($indate -lt $DATE_MEIJI){

        Write-Host("明治以前の日付には対応していません。")
        exit

    }elseif($indate -lt $DATE_TAISYOU){

        $ERA = $ERA_MEIJI
        $year = $indate.Year - $DATE_MEIJI.Year + 1

    }elseif($indate -lt $DATE_SYOUWA){

        $ERA = $ERA_TAISYOU
        $year = $indate.Year - $DATE_TAISYOU.Year + 1
    
    }elseif($indate -lt $DATE_HEISEI){

        $ERA = $ERA_SYOUWA
        $year = $indate.Year - $DATE_SYOUWA.Year + 1
    
    }else{

        $ERA = $ERA_HEISEI
        $year = $indate.Year - $DATE_HEISEI.Year + 1

    }

    Write-Host ($ERA + $year + "年" + $indate.Month +"月" + $indate.Day + "日")

}

New-Alias -Name "wareki" Ad-Conversion

最終行に関数「Ad-Conversion」にエイリアス「wareki」を設定しました。

エイリアスについては以下の記事をご参照ください。

Windowsのポチポチ業務を爆速化するPowerShell、短いワードでサッと関数を呼び出すエイリアスの使い方
Windowsのポチポチ業務(=マウスを使った業務)を爆速化するPowerShell。自作した関数をFunctionドライブというものに登録して、いつでも呼び出せるようにする方法をお伝えします!

プロファイルに関数を登録する

完成した関数「Ad-Conversion」とエイリアス「wareki」をプロファイルに登録します。

psedit $profile

とコンソールで入力するとISEでプロファイルが開きますので、完成したスクリプトを記載し保存します。

ISEを再起動し、以下のように関数を呼び出すと…

コンソールから西暦を和暦に変換することができました!

プロファイルについては以下の記事をご参照ください。

Windowsのポチポチ業務を爆速化するPowerShell、起動時に関数を自動登録するプロファイルの使い方
Windowsのポチポチ業務(マウスを使った業務)を爆速化するPowerShell。今回はPowerShell起動時に自動で実行されるプロファイルというスクリプトを使って、関数やエイリアスを登録する方法をお伝えします。

まとめ

PowerShellで日付を操るに便利なDatetime型についてお伝えしました!Datetime型では日付同士の比較ができます。またYear・Month・Day・Hourを指定すれば、必要な情報だけ取り出すことができます

これで西暦を和暦に変換する関数が完成しました!Datetime型の変数やプロファイル・エイリアスを活用し、みなさんも自作関数を作ってみてください!

それでは、最後までお読みいただきありがとうございました!

連載目次:Windowsのポチポチ業務を爆速化するPowerShell

Windowsのポチポチ業務(マウスを使った業務)を爆速化するために、PowerShellを使った効率化の方法をお伝えしています。
  1. Windowsのポチポチ業務を爆速化するPowerShell、はじめのハードルぐーーんと下げてみます!
  2. Windowsのポチポチ業務を爆速化するPowerShell、キーボードを使わずササっと起動する方法
  3. Windowsのポチポチ操作を爆速化するPowerShellの絶対条件!ディレクトリとその移動をマスターしよう!
  4. Windowsのポチポチ業務を爆速化するPowerShell、コマンドレットを腹の底から理解する!
  5. Windowsのポチポチ業務を爆速化するPowerShell、オンラインヘルプでコマンドレットを使い倒す!
  6. Windowsのポチポチ業務を爆速化するPowerShell、統合開発環境ISEを紹介します!
  7. Windowsのポチポチ業務を爆速化するPowerShell、スクリプトを実行するための準備
  8. Windowsのポチポチ業務を爆速化するPowerShell、フォルダを作るスクリプトの作り方
  9. Windowsのポチポチ業務を爆速化するPowerShell、if文を使いフォルダの有無で処理を分岐させる方法
  10. Windowsのポチポチ業務を爆速化するPowerShell、ForEach-Objectで配列の全要素を処理する方法
  11. Windowsのポチポチ業務を爆速化するPowerShell、パイプラインを使いコマンドレット間で値を引き渡す方法
  12. Windowsのポチポチ業務を爆速化するPowerShell、ファイルを別フォルダにコピーし名称を変更する方法
  13. Windowsのポチポチ業務を爆速化するPowerShell、ファイル名を変更する方法
  14. Windowsのポチポチ業務を爆速化するPowerShell、正規表現で複雑なファイル名変更をする方法
  15. Windowsのポチポチ業務を爆速化するPowerShell、タスクスケジューラでスクリプトを決まった日時に起動する方法
  16. Windowsのポチポチ業務を爆速化するPowerShell、ファイルをバックアップするスクリプトの作り方
  17. Windowsのポチポチ業務を爆速化するPowerShell、関数を作ってスクリプトから呼び出す方法
  18. Windowsのポチポチ業務を爆速化するPowerShell、関数をコンソールで登録して呼び出す方法
  19. Windowsのポチポチ業務を爆速化するPowerShell、短いワードでサッと関数を呼び出すエイリアスの使い方
  20. Windowsのポチポチ業務を爆速化するPowerShell、関数やエイリアス保存場所のドライブを紹介します
  21. Windowsのポチポチ業務を爆速化するPowerShell、elseifで日付の元号を判定する方法

Google Apps Scriptでフォーム送信時にメッセージを送るスクリプトの作り方

$
0
0
paper-airplane

photo credit: hgz09 paper airplane via photopin (license)

みなさん、こんにちは!
タカハシ(@ntakahashi0505)です。

Google Apps Scriptで備品購入申請を題材にワークフローを作る方法をお伝えしております。

前回の記事はこちら。

備品購入申請フォームをGoogleフォームで作成する方法
Google Apps Scriptを使って簡単なワークフローを作るシリーズです。今回は備品購入申請のフォームをGoogleフォームで作成して設定をしその送信結果をスプレッドシートで確認していきます。

Googleフォームで備品購入申請のフォームを作成する方法をお伝えしました。

それで、フォームから送信があったら、その事実を承認者に知らせたいですよね。

GASでは、そんなときに便利な「フォーム送信時」のトリガーという機能があります。

ということで、今回はGoogle Apps Scriptでフォーム送信時にメッセージを送る方法です。

では、行ってみましょう!

前回のおさらい

前回はGASには触ってなくてですね、フォームを作っただけでしたね。

以下のようなフォームです。

Googleフォームによる備品購入申請

このフォームを「送信」などから公開すれば申請を受け付けることができます。

それで、フォームからの送信があった場合は、以下のように連携するスプレッドシートに自動でデータが入力されるわけですね。

フォームから送信したデータをスプレッドシートで確認

ここまでは、GASではなくて、フォームの機能だけで実現可能です。

次の段取りとしては、このフォームの送信があったときに、申請があったことを承認者に伝えたいですよね。

今回はその方法を解説していきますよ。

Gmailで申請があったことを通知する

承認者には、Gmailによるメールにより、申請があったことを伝えたいと思います。

まずは、その部分のスクリプトを作っておきましょう。

GASでGmailからメールを送信するには、GmailAppオブジェクトのsendEmailメソッドでしたね。

GmailApp.sendEmail(送信先アドレス, 件名, 本文, オプション)

オプションにはCCやBCC、添付ファイルなどをオブジェクト形式で設定できますが、必要がなければ省略できます。

ということで、フォームから送信されたデータが蓄積されるスプレッドシートのコンテナバインドスクリプトに、以下のようなスクリプトsendMessageを作りました。

function sendMessage() {
  
  var recipient = 'hogehoge@example.com'; //送信先メールアドレス
  var subject = '備品購入申請のお知らせ';
  var body = '';
  body += '備品購入申請がありましたので\n';
  body += '以下URLからスプレッドシートをご覧ください\n';
  body += 'https://docs.google.com/spreadsheets/d/~'; //スプレッドシートのURL    
  GmailApp.sendEmail(recipient, subject, body);
  
}

実行すると、以下のようなメッセージが届きます。

GASのトリガーによる送信を確認

ひとまずメール送信の部分はOKですね。

「フォーム送信時」のトリガーとは

それで、先ほど作ったスクリプトsendMessageを実行するわけですが、担当者がスプレッドシートに張り付いて、追加されたのを目でみてスクリプトエディタで「▶」ボタンをクリック…というわけにはいきません。

ここは、GASで用意されている「フォーム送信時」のトリガーという機能を使うことができます。

これは、フォームの送信が行われたときに、自動でスクリプトを実行させることができる機能です。

トリガーを設定さえすれば、我々は眠ってても大丈夫。

トリガーがフォームの送信を待ち構えていて、その際にはスクリプトを動作してくれます。

トリガーの設置方法

では、トリガーの設置方法を見ていきましょう。

まず、スクリプトエディタのツールバーから以下マークの「現在のプロジェクトのトリガー」をクリックします。

現在のプロジェクトのトリガー

すると、別タブで「G Suite Developer Hub」というページが開きますので、「+ トリガーを追加」をクリックします。

現在のプロジェクトのトリガー

「備品購入申請のトリガーを追加」というダイアログが表示されるので、以下のように設定して「保存」します。

  • 実行する関数を選択:sendMessage
  • イベントのソースを選択:スプレッドシートから
  • イベントの種類を選択:フォーム送信時

G Suite Developer Hubでトリガーを追加する

承認に関するダイアログが表示されることもあると思いますので、承認してあげてください。

これでトリガーの設置が完了です。

他にもトリガーの種類はたくさんありますので、「イベントのソース」や「イベントの種類」について覗いてみてくださいね。

トリガーの動作を確認する

では、確認してみましょう。

備品購入申請フォームから送信しましょう。

スプレッドシートに書き込まれるとともに、「フォームの送信」トリガーが発火して、スクリプトsendMessageが実行。

ちゃんとメッセージが到着しているはずです。

まとめ

以上、Google Apps Scriptでフォーム送信時にメッセージを送るスクリプトの作り方をお伝えしました。

「フォーム送信時のトリガー」がポイントですね。

さて、メッセージの内容に、申請内容入れたいですよね。

次回は、その部分を進めていきます。

Google Apps Scriptでフォーム送信した内容を含んだメッセージをGmailで送るスクリプト
Google Apps Scriptで備品購入申請を題材にワークフローを作っております。今回はGASでフォーム送信した内容をイベントオブジェクトから取り出してそれを含めたメッセージをGmailで送る方法です。

どうぞお楽しみに!

連載目次:初心者でも作れるGASによる簡単ワークフロー

スプレッドシート、Gmail、フォーム…Google Apps Scriptで操作できるアプリケーションはまさに「ワークフロー」を作成する上で必要なものが揃っています。ということで、このシリーズでは初心者でも簡単に作れるワークフローの作り方について解説をしていきます。
  1. 備品購入申請フォームをGoogleフォームで作成する方法
  2. Google Apps Scriptでフォーム送信時にメッセージを送るスクリプトの作り方
  3. Google Apps Scriptでフォーム送信した内容を含んだメッセージをGmailで送るスクリプト
  4. Google Apps Scriptで特定のURLを踏んだらスクリプトを動作させるdoGet関数の使い方
  5. GASでURLを踏んでスクリプトを動作させたときにパラメータを渡す方法
  6. 【GASで作るワークフロー】URLクリックで「承認」とするスクリプトの作り方
  7. GASで送信するGmailのメッセージをプレーンでもHTMLでも送れるようにする
  8. GASのワークフローでURLのパラメータで承認・否認を切り替える方法

Google Apps Scriptでフォーム送信した内容を含んだメッセージをGmailで送るスクリプト

$
0
0
box

photo credit: kenwalton Untitled via photopin (license)

みなさん、こんにちは!
タカハシ(@ntakahashi0505)です。

Google Apps Scriptで備品購入申請を題材にワークフローを作っております。

前回の記事はこちらです。

Google Apps Scriptでフォーム送信時にメッセージを送るスクリプトの作り方
Google Apps Scriptで備品購入申請を題材にワークフローを作る方法をお伝えしております。今回はGASのトリガーという機能を使って、フォーム送信時にメッセージを送るスクリプトを作っていきます。

フォーム送信時にトリガーでメッセージを送る方法をお伝えしました。

さて、メッセージを送るのは良いのですが、その中にフォームで送信した内容を反映したくないですか??

ということで、今回はGoogle Apps Scriptでフォーム送信した内容を含んだメッセージをGmailで送るスクリプトを紹介します。

フォーム送信時のイベントオブジェクトを使いますよ。

では、行ってみましょう!

前回のおさらい

さて、これまでのおさらいをしておきましょう。

このシリーズでは備品購入申請のワークフローを作っておりまして、申請をするのは以下のGoogleフォームを使用します。

Googleフォームによる備品購入申請

Googleフォームから送信した内容は、連携している以下のスプレッドシートに蓄積されます。

フォームから送信したデータをスプレッドシートで確認

さらに、このスプレッドシートには「フォーム送信時」のトリガーで動作するスクリプトが仕込まれておりまして、それがこちらです。

function sendMessage() {
  
  var recipient = 'hogehoge@example.com'; //送信先メールアドレス
  var subject = '備品購入申請のお知らせ';
  var body = '';
  body += '備品購入申請がありましたので\n';
  body += '以下URLからスプレッドシートをご覧ください\n';
  body += 'https://docs.google.com/spreadsheets/d/~'; //スプレッドシートのURL    
  GmailApp.sendEmail(recipient, subject, body);
  
}

つまり、備品購入申請のフォーム送信が行われると、承認者であるhogehogeさんにメールが送られるという仕組みです。

さて、そのメールのメッセージですが、フォーム送信の内容を含めたくないですか…?

ということで、その方法をお伝えしていきます。

フォーム送信時のイベントオブジェクト

Google Apps Scriptでは何らかのイベントでトリガーを発動させてスクリプトを動作させたとき、そのスクリプトはイベントに関する特別なオブジェクトを受け取ることができます。

それをイベントオブジェクトといいます。

イベントオブジェクトはトリガーの種類に応じてその内容が変わるのですが、今回使用している「フォーム送信時」イベントの場合は以下のような内容が含まれます。

プロパティ 内容
range 編集されたRangeオブジェクト
values 送信される値の配列

values…この値を取り出せば、フォームから送信された値を取得できますね!

フォーム送信時のイベントオブジェクトのプロパティvaluesは、スプレッドシートに書き込まれる順に値が格納されている配列になっています。

つまり、今回の場合は以下のような内容になっています。

インデックス 内容
0 タイムスタンプ
1 購買先
2 品名
3 個数
4 数量
5 Memo(URLなど)
6 メールアドレス

これらから値を取り出して、メールの本文に組み込んであげればOKです。

フォーム送信の内容を含んだメッセージを送る

以上をもとに、フォーム送信の内容を含んだメッセージをGmailで送るスクリプトを作りました。

こちらです。

function sendMessage(e) {

  var shop = e.values[1];
  var item = e.values[2];
  var price = e.values[3];
  var amount = e.values[4];
  var total = price * amount;

  var recipient = 'hogehoge@example.com'; //送信先メールアドレス
  var subject = '備品購入申請のお知らせ';
  var body = '';
  body += '備品購入申請がありました。\n\n';
  body += '・購買先: ' + shop + '\n';
  body += '・品名: ' + item + '\n';
  body += '・単価: ' + price + ' 円\n';
  body += '・数量: ' + amount + '\n';
  body += '・総額: ' + total + ' 円\n\n';  
  body += '以下URLからスプレッドシートをご覧ください\n';
  body += 'https://docs.google.com/spreadsheets/d/~'; //スプレッドシートのURL    

  GmailApp.sendEmail(recipient, subject, body);
  
}

イベントオブジェクトはトリガーで動作するスクリプトの引数に指定します。

1行目をご覧いただければわかりますが、よく「e」という仮引数を使います。

あとはe.valuesの配列からゴリゴリ値を取り出して、メッセージ本文bodyにゴリゴリ追加していけばOKというわけです。

実行すると、以下のようなメールが送信されますよ。

フォーム送信の内容を含むGmailメッセージ

徐々に優しくなってきましたね。

まとめ

以上、Google Apps Scriptでフォーム送信した内容を含んだメッセージをGmailで送るスクリプトについてお伝えしました。

なんと言っても、フォーム送信時イベントのイベントオブジェクトがポイントですね。

これ知らないと困るやつです。

次回は、送信したメールのURLからスクリプトを起動する方法をお伝えします。

Google Apps Scriptで特定のURLを踏んだらスクリプトを動作させるdoGet関数の使い方
Google Apps Scriptで備品購入申請を題材としてワークフローを作る方法についてシリーズでお伝えしてます。今回は、GASでで特定のURLを踏んだらスクリプトを動作させるdoGet関数の使い方です。

どうぞお楽しみに!

連載目次:初心者でも作れるGASによる簡単ワークフロー

スプレッドシート、Gmail、フォーム…Google Apps Scriptで操作できるアプリケーションはまさに「ワークフロー」を作成する上で必要なものが揃っています。ということで、このシリーズでは初心者でも簡単に作れるワークフローの作り方について解説をしていきます。
  1. 備品購入申請フォームをGoogleフォームで作成する方法
  2. Google Apps Scriptでフォーム送信時にメッセージを送るスクリプトの作り方
  3. Google Apps Scriptでフォーム送信した内容を含んだメッセージをGmailで送るスクリプト
  4. Google Apps Scriptで特定のURLを踏んだらスクリプトを動作させるdoGet関数の使い方
  5. GASでURLを踏んでスクリプトを動作させたときにパラメータを渡す方法
  6. 【GASで作るワークフロー】URLクリックで「承認」とするスクリプトの作り方
  7. GASで送信するGmailのメッセージをプレーンでもHTMLでも送れるようにする
  8. GASのワークフローでURLのパラメータで承認・否認を切り替える方法

Google Apps Scriptで特定のURLを踏んだらスクリプトを動作させるdoGet関数の使い方

$
0
0
request

photo credit: mikecogh Alyssum In Between via photopin (license)

みなさん、こんにちは!
タカハシ(@ntakahashi0505)です。

Google Apps Scriptで備品購入申請を題材としてワークフローを作る方法についてシリーズでお伝えしております。

前回の記事はこちら。

Google Apps Scriptでフォーム送信した内容を含んだメッセージをGmailで送るスクリプト
Google Apps Scriptで備品購入申請を題材にワークフローを作っております。今回はGASでフォーム送信した内容をイベントオブジェクトから取り出してそれを含めたメッセージをGmailで送る方法です。

フォームから送信した内容を含んだメールをGmailで送る方法をお伝えしました。

これで、承認者に備品購入申請の内容をメールで送ることができたわけですが、メールから直接承認できたら便利ですよね。

それを目指していろいろやっていきましょう。

まずは、Google Apps Scriptで特定のURLを踏んだらスクリプトを動作させる方法です。

doGet関数というものを使いますよ。

では、行ってみましょう!

前回のおさらい

まずは前回のおさらいからです。

このシリーズでは備品購入申請のワークフローをGASで作成しております。

申請を行うのはGoogleフォームからで、以下のようなものです。

Googleフォームによる備品購入申請

これを使って申請を行うと、連携するスプレッドシートに以下のように蓄積されます。

フォームから送信したデータをスプレッドシートで確認

スプレッドシートがフォーム送信を受け取ると、「フォーム送信時」のトリガーにより、以下のsendMessageが動作します。

function sendMessage(e) {

  var shop = e.values[1];
  var item = e.values[2];
  var price = e.values[3];
  var amount = e.values[4];
  var total = price * amount;

  var recipient = 'hogehoge@example.com'; //送信先メールアドレス
  var subject = '備品購入申請のお知らせ';
  var body = '';
  body += '備品購入申請がありました。\n\n';
  body += '・購買先: ' + shop + '\n';
  body += '・品名: ' + item + '\n';
  body += '・単価: ' + price + ' 円\n';
  body += '・数量: ' + amount + '\n';
  body += '・総額: ' + total + ' 円\n\n';  
  body += '以下URLからスプレッドシートをご覧ください\n';
  body += 'https://docs.google.com/spreadsheets/d/~'; //スプレッドシートのURL    

  GmailApp.sendEmail(recipient, subject, body);
  
}

それで、結果として承認者宛に以下のようなメッセージが届くというところまで進めました。

フォーム送信の内容を含むGmailメッセージ

承認者が受け取ったメッセージからは、スプレッドシートへのリンクが挿入されています。

実は、メールに仕込むURLを「ウェブアプリケーションのURL」に変更をすると、そのアクセスを受けてスクリプトを動作させることができます。

今回は、その方法を紹介していきますよ!

シンプルトリガーとは

「フォーム送信時」のトリガーは、G Suite Developer Hubで設定しましたが、そこで設定するのはインストーラブルトリガーという種類のトリガーです。

GASにはもう一種類別のトリガーがとして、シンプルトリガーという種類のトリガーがあります。

シンプルトリガーは、function名を固定にするだけで特定のイベントに応答して動作する関数を作れるという、その名の通りシンプルなものです。

例としては、スプレッドシートやドキュメントを開いたときに動作するonOpen関数や、スプレッドシートを編集したときに動作するonEdit関数などがあります。

doGet関数とは

今回主役となるのはdoGet関数という関数です。

doGet関数はシンプルトリガーの一種で、ウェブアプリケーションにアクセスがあったときに動作する関数です。

(専門的にいうと、指定したURLにGETリクエストがあったときに動作するものです。)

要は誰かが何らかのWebページや、メール内からURLリンクを踏んだら動作させることができるというわけですね。

それで、以下のように名前を「doGet」にして関数を記述することで作成できます。

function doGet() {
 ’処理
}

それに加えて、以下のルールがあります。

  • TextOutputオブジェクトかHtmlOutputオブジェクトをリターンする
  • プロジェクトをウェブアプリケーションとして公開してアクセスを受けるためのURLを発行する

んー…ちょっと難し目ですね。

一つずつ見ていきましょう。

doGet関数を作成する

doGet関数のスクリプト

まず、doGet関数から作っていきましょう。

こちらです。

function doGet() {
  var html = '';
  html += '

備品購入申請のお知らせ

'; html += '<p>あなたは備品購入申請のメールのリンクを踏みました'; return HtmlService.createHtmlOutput(html); }

変数htmlには、いわゆるHTML文を文字列で構成して代入しています。

見出しを表すh1タグと、段落を表すpタグだけのとてもシンプルな内容です。

それで、5行目のreturn文ですね。

これが「HtmlOutputオブジェクトをリターンする」という部分です。

createHtmlOutputメソッドとHtmlOutputオブジェクト

HtmlServiceサービスのcreateHtmlOutputメソッドは、引数として指定したHTML文からHtmlOutputというオブジェクトを生成するメソッドです。

HtmlService.createHtmlOutput(HTML)

それで、doGet関数からそのHtmlOutputオブジェクトをリターンすることで、URLを踏んだ人に、そのHTMLの内容を反映したWebページを返して見てもらうことができるというものです。

これでdoGet関数の準備はOKです。

ウェブアプリケーションとして公開する

続きまして、「ウェブアプリケーションとして公開」する方法を見ていきましょう。

なにせ、踏むURLがなければアクセスできませんからね。

公開してURLを発行しましょう。

doGet関数を書いたら、スクリプトエディタの「公開」メニューから「ウェブアプリケーションとして導入」を選択します。

スクリプトエディタからウェブアプリケーションとして導入
すると「ウェブアプリケーションとして導入」ダイアログが開きます。

「プロジェクトバージョン」にはバージョン名を適当に入力して、「アプリケーションにアクセスでいるユーザー」は今回は社内ツールを想定して「[ドメイン名]の全員」としました。

「ウェブアプリケーションとして導入」ダイアログ

「導入」をクリックすると、次の画面で「現在のウェブアプリケーションのURL」が表示されます。

これが目的のURLですので、コピーしておきましょう。

GASで公開したウェブアプリケーションのURL

ためしに、そのURLにアクセスしてみると、以下のようなWebページが表示されます。

公開したウェブアプリケーションのページ

送るメッセージに公開したウェブアプリケーションのURLを含める

では、冒頭のsendMessageを以下のように変更します。

function sendMessage(e) {

  var shop = e.values[1];
  var item = e.values[2];
  var price = e.values[3];
  var amount = e.values[4];
  var total = price * amount;

  var recipient = 'hogehoge@example.com'; //送信先メールアドレス
  var subject = '備品購入申請のお知らせ';
  var body = '';
  body += '備品購入申請がありました。\n\n';
  body += '・購買先: ' + shop + '\n';
  body += '・品名: ' + item + '\n';
  body += '・単価: ' + price + ' 円\n';
  body += '・数量: ' + amount + '\n';
  body += '・総額: ' + total + ' 円\n\n';  
  body += '以下URLをクリックしてみてください\n';
  body += 'https://script.google.com/a/~exec'; //公開したウェブアプリケーションのURL    

  GmailApp.sendEmail(recipient, subject, body);
  
}

19行目を公開したウェブアプリケーションのURLに変更し、それに合わせて18行目の文言も変更しました。

フォーム送信からの流れで確認してみましょう。

受信したメールの中のURLをクリックすると、先ほどと同じWebページが表示されるはずです。

まとめ

以上、Google Apps Scriptで特定のURLを踏んだらスクリプトを動作させる方法をお伝えしました。

doGet関数の役割と使い方について、バッチリ理解いただけたでしょうか?

さて、今回はただの静的ページを表示しただけですが、doGet関数でフォーム送信で追加されたスプレッドシートの行数などの情報をパラメータとして受け取ることができたりします。

その部分を次回以降で紹介していきます。

GASでURLを踏んでスクリプトを動作させたときにパラメータを渡す方法
Google Apps Scriptで備品購入申請を題材にワークフローを作る方法をお伝えしています。今回は、GASでURLを踏んでスクリプトを動作させたときにパラメータを渡す方法をお伝えします。

どうぞお楽しみに!

連載目次:初心者でも作れるGASによる簡単ワークフロー

スプレッドシート、Gmail、フォーム…Google Apps Scriptで操作できるアプリケーションはまさに「ワークフロー」を作成する上で必要なものが揃っています。ということで、このシリーズでは初心者でも簡単に作れるワークフローの作り方について解説をしていきます。
  1. 備品購入申請フォームをGoogleフォームで作成する方法
  2. Google Apps Scriptでフォーム送信時にメッセージを送るスクリプトの作り方
  3. Google Apps Scriptでフォーム送信した内容を含んだメッセージをGmailで送るスクリプト
  4. Google Apps Scriptで特定のURLを踏んだらスクリプトを動作させるdoGet関数の使い方
  5. GASでURLを踏んでスクリプトを動作させたときにパラメータを渡す方法
  6. 【GASで作るワークフロー】URLクリックで「承認」とするスクリプトの作り方
  7. GASで送信するGmailのメッセージをプレーンでもHTMLでも送れるようにする
  8. GASのワークフローでURLのパラメータで承認・否認を切り替える方法

【QUERY関数】where句でand,orを使用して複数条件を指定する方法

$
0
0

QUERY関数7アイキャッチ

みなさんこんにちは!
もり(@moripro3)です。

GoogleスプレッドシートQUERY関数の使い方をシリーズでお届けしています!

前回はwhere句の条件に「時刻」を指定する方法を紹介しました。

【QUERY関数】where句で時刻データを条件にして行を抽出する
GoogleスプレッドシートのQUERY関数を紹介するシリーズ。第六回目は、where句の条件に時刻を指定する方法です。指定の時刻以前・以降のデータを抽出する方法、現在時刻を基準としてデータ抽出する方法を紹介しています。

これまでシリーズを通して紹介してきた抽出は、すべて「単一条件の指定」でした。

会社の実務では、1つの条件だけでなく、複数の条件を組み合わせる必要があると思います。この記事では、where句に複数の条件を指定する方法を紹介します。

それではみていきましょう!

単一条件と複数条件とは

まずは用語の確認からしていきましょう。

  1. 単一条件
  2. 複数条件

「単一条件」とは「条件が1つだけ」という意味です。たとえば、このようなシンプルな指定です。

  • 価格が1,000円以上の商品
  • ○○さんが購入した商品

それに対して、「複数条件」とは、「2つ以上の条件」のことです。

  • ○○さんが購入した1,000円以上の商品

QUERY関数のwhere句で複数条件を指定するための、2つの新しい「論理演算子」を紹介します。

  1. or … AまたはB(いずれかの条件に合致する)
  2. and … AかつB(すべての条件に合致する)

この or と and は、スプレッドシートの他の関数で使っている方もいるでしょう。

それでは、この備品購入リストを使用して、複数条件のデータ抽出方法を紹介します。

query7-1

orを使用した複数条件の指定

where句の条件を or で結合すると、いずれかの条件に合致する行のみを抽出できます。

where 条件1 or 条件2 or 条件3…

or を使用して、備品購入リストから、モリとテラドが購入した備品一覧を抽出してみます。条件はこの2つです。

  • 条件1:E列購入者が「モリ」
  • 条件2:E列購入者が「テラド」

条件1 と 条件2 を or結合 する書き方がこちらです。

=query('備品購入リスト'!A:E,"select * where E = 'モリ' or E = 'テラド'",1)

query7-4

ポイントは、同じ列(ここではE列)の条件を指定する場合でも、列名を省略せずに、条件ごとに記述することです。

where E = ‘モリ’ or E = ‘テラド’
where E = ‘モリ’ or ‘テラド’

andを使用した複数条件の指定

where句の条件を and で結合すると、複数条件のすべてに合致する行のみを抽出できます。

where 条件1 and 条件2 and 条件3…
モリが購入した1,000円以上の備品一覧を抽出してみます。条件はこの2つです。
  • 条件1:E列購入者が「モリ」
  • 条件2:D列単価が1,000円以上

条件1 と 条件2 を and結合 します。

=query('備品購入リスト'!A:E,"select * where E = 'モリ' and D >= 1000",1)

query7-2

 

条件は、3つ以上を組み合わせることも可能です。条件3を加えてみます。

  • 条件1:E列購入者が「モリ」
  • 条件2:D列単価が1,000円以上
  • 条件3:D列単価が10,000円未満

query7-3

これで、モリが購入した1,000円以上10,000円未満の一覧を取得できました。

and と or を組み合わせた複数条件の指定

ここまでの知識を組み合わせて、実務を想定した、高度な抽出を2つ紹介します!

and と or の組み合わせ・その1

「モリまたはテラドが購入した1,000円以上の備品」の一覧を抽出してみます。

まずは条件を整理します。

  • 条件1:購入者が「モリ」または「テラド」
  • 条件2:単価が1,000円以上

QUERY関数の書き方がこちらです。

=query('備品購入リスト'!A:E,"select * where (E = 'モリ' or E = 'テラド') and D >= 1000",1)

【解説】条件1を or結合 で作成し、条件1 と 条件2 を and結合します。

  • 条件1:E列が「モリ」または「テラド」
    • (E = ‘モリ’ or E = ‘テラド’)
  • 条件2:D列が1,000円以上
    • D >= 1000

query7-6

and と or の組み合わせ・その2

「すべてのOA機器」と「1,000円以上の事務用品」の一覧を抽出してみましょう。
水色(5行)と緑色(2行)の、計7行が抽出できれば正解です。

query7-7

条件を整理します。

  • 条件1:区分が「OA機器」… 水色の行
  • 条件2:区分が「事務用品」、かつ、単価が1,000円以上 … 緑色の行

QUERY関数の書き方がこちらです。

=query('備品購入リスト'!A:E,"select * where B = 'OA機器' or (B = '事務用品' and D >= 1000)",1)

【解説】条件2を and結合 で作成し、条件1 と 条件2 を or結合します。

  • 条件1:B列 が「OA機器」
    • B = ‘OA機器’
  • 条件2:区分が「事務用品」、かつ、単価が1,000円以上
    • (B = ‘事務用品’ and D >= 1000)

query7-5

まとめ

今回の記事では、where句で複数条件を指定する方法をお伝えしました。

and, or の考え方は、VBA・GASなどのプログラミングでも大いに役立ちますよ!ワンランク上の事務職を目指す方は、ぜひ覚えておきたいですね。

頭の中で考えて混乱しそうな時は、条件を紙に書き出して整理してみるのもオススメです。

さて、ここまでのシリーズを通して、QUERY関数の基本であるselect句とwhere句を紹介してきました。

  • select句で列の抽出をする方法
  • where句で行の抽出をする方法

次回からはQUERY関数で「データの集計」をする方法を紹介していきます。

どうぞお楽しみに!

連載目次:GoogleスプレッドシートQUERY関数をマスターしよう

スプレッドシートのQUERY関数を使って、データ抽出・集計を効率化する方法を紹介しています。

  1. スプレッドシートのQUERY関数を使う最初の一歩!クエリを理解する
  2. QUERY関数の基本!別シートのデータからselect句で列を取得する方法
  3. 【QUERY関数】where句と比較演算子を使って単一条件に一致した行を抽出する
  4. 【QUERY関数】where句とlike演算子を使用して指定の文字を含む行を抽出する
  5. 【QUERY関数】where句で日付データを条件にして行を抽出する
  6. 【QUERY関数】where句で時刻データを条件にして行を抽出する
  7. 【QUERY関数】where句でand,orを使用して複数条件を指定する

【Outlook VBA】登録済みの予定を日付で検索して取得する方法

$
0
0

outlook,vba,getappointment

皆様こんにちは、ノグチです。

以前の記事では、Outlookの予定を登録する方法をご紹介しました。

【はじめてのOutlook VBA】Outlookの予定を登録する方法
Outlook VBAでコーディングするためのVBEの準備と、VBAで予定を登録する方法をご紹介しています。1件の予定登録の手間は大したことがなくても、複数登録する必要が出てくると面倒臭い...本稿では複数の予定をOutlookにまとめて登録するための第一歩として、単体の予定をVBAで登録する方法をご紹介します。

登録した予定はOutlookのカレンダーを見れば一目瞭然ですが、ボタン一つでチェックできれば更に便利ですよね。

Outlook VBAならできるかもしれませんよ。

ということで今回は、Outlookに登録されている予定を取得してメッセージで表示する方法をご紹介します!

Outlookの予定を取得する

GetDefaultFolderメソッドで予定表フォルダにアクセス

以前の記事で、受信メールフォルダにアクセスする方法をご紹介しました。

【エクセルVBA】GetNamespaceメソッドでOutlookのデータフォルダにアクセスする方法
GetNameSpaceメソッドでOutlookのデータフォルダにアクセスする方法をご紹介しています。このメソッドでOutlookのNameSpaceオブジェクトを取得すれば、メール、連絡先、予定表などのデータフォルダにアクセスして、更にその中のデータを読込んだり、エクセルシートに書き出したりすることができますよ。

予定についても、考え方は受信メールフォルダにアクセスする場合とほぼ同じ。

GetDefaultFolderメソッドの引数に、予定表のフォルダを表す定数olFolderCalendorを指定すればOKです。

こんな風に。

Namespaceオブジェクト.GetDefaultFolder(olFolderCalendar)

これで、予定表のFolderオブジェクトが取得できます。

Itemsメソッドとプロパティで予定の内容を取得

予定表のFolderオブジェクトが取得できたら、Itemsメソッドで予定を取得して、更にプロパティで予定の情報を取得しましょう。

Itemsメソッド記述方法と各プロパティは、下記記事でご紹介していますので、こちらをご覧ください。

【はじめてのOutlook VBA】Outlookの予定を登録する方法
Outlook VBAでコーディングするためのVBEの準備と、VBAで予定を登録する方法をご紹介しています。1件の予定登録の手間は大したことがなくても、複数登録する必要が出てくると面倒臭い...本稿では複数の予定をOutlookにまとめて登録するための第一歩として、単体の予定をVBAで登録する方法をご紹介します。

たとえば、予定の件名と開始時間を取得したいとしたら、ItemsメソッドのSubjectプロパティとStartプロパティを使って、こんな風に記述します。

Private Sub GetAppointment()
Dim myNamespace     As NameSpace
Dim myFolder        As Object

Set myNamespace = GetNamespace("MAPI")
Set myFolder = myNamespace.GetDefaultFolder(olFolderCalendar)

MsgBox myFolder.Items(1).Start & vbCrLf & myFolder.Items(1).Subject

End Sub

このコードを実行してみると…

outlook,vba,予定,メッセージ

この通り、予定の内容を取得して、メッセージで表示できていますね。

日時を指定して登録済みの予定を取得する

さて、上でご紹介したコードに更に手を加えて、今度は指定した日付の予定が取得できるようにしてみましょう。

上のコードのままでは、実用的とは言えませんからね。

何も難しいことはなく、For Each文とIf文を使って、予定フォルダー内の各予定が指定条件にマッチするかを見てあげればよいだけです。

上のコードに、For Each文で予定フォルダ内の予定を1件ずつ取得する処理と、取得した予定が条件にマッチしているか?をIf文でチェックする処理を入れてみましょう。

こんなコードになります。

Private Sub GetAppointment()
Dim myNamespace     As NameSpace
Dim myFolder        As Object
Dim ObjAppo         As Object
Dim strMsg          As String

Set myNamespace = GetNamespace("MAPI")
Set myFolder = myNamespace.GetDefaultFolder(olFolderCalendar)

For Each ObjAppo In myFolder.Items
    
    If Format(ObjAppo.Start, "yyyy/mm/dd") = Format("2019/03/20", "yyyy/mm/dd") Then
        With ObjAppo
            strMsg = strMsg & Format(.Start, "hh:mm") & Space(3) & _
                    ObjAppo.Subject & vbCrLf
        End With
    End If
Next ObjAppo

MsgBox strMsg

End Sub

そして実行してみると…

outlook,vba,指定日,予定

この通り、3月20日に登録された予定を全て取得してくれていますね。

Date関数で今日日付の予定を取得する

上のコードの、If文の条件にDate関数をセットすれば、本日日付の予定を取得することができますよ。

 このIf文を…

 If Format(ObjAppo.Start, "yyyy/mm/dd") = Format("2019/03/20", "yyyy/mm/dd") Then

このように記述すればOKです。

If Format(ObjAppo.Start, "yyyy/mm/dd") = Date Then

これなら、カレンダーを見なくてもマクロを実行すれば、今日の予定を確認できますね。

最後に

今回は、Outlookのに登録された予定を取得する方法をご紹介しました。

Outlookには色々なイベントプロシージャが用意されていますので、イベントと組み合わせて使ってみるとより便利に使えるかもしれませんね。

それでは、最後までお読みいただきありがとうございました!

【GASで作るワークフロー】URLクリックで「承認」とするスクリプトの作り方

$
0
0
arrow

photo credit: www.ralfpreuss.de Arrows via photopin (license)

みなさん、こんにちは!
タカハシ(@ntakahashi0505)です。

Google Apps Scriptで備品購入申請を題材にワークフローを作成する方法をお伝えしています。

前回の記事はこちら。

GASでURLを踏んでスクリプトを動作させたときにパラメータを渡す方法
Google Apps Scriptで備品購入申請を題材にワークフローを作る方法をお伝えしています。今回は、GASでURLを踏んでスクリプトを動作させたときにパラメータを渡す方法をお伝えします。

URLを踏んでdoGet関数を呼び出すときにパラメータを渡す方法をお伝えしました。

今回は、URLを踏んだら「承認」としたことにするようにスクリプトを修正していきます。

ということで、【GASで作るワークフロー】URLクリックで「承認」とするスクリプトの作り方をお伝えします。

では、行ってみましょう!

前回のおさらい

前回までのおさらいからいきますね。

まず、備品購入申請は以下のGoogleフォームから行います。

Googleフォームによる備品購入申請

フォーム送信を行うと連携する以下のスプレッドシートに申請内容が蓄積されます。

フォームから送信したデータをスプレッドシートで確認

その際、フォーム送信時のトリガーで以下のスクリプトsendMessageが動作します。

function sendMessage(e) {

  var shop = e.values[1];
  var item = e.values[2];
  var price = e.values[3];
  var amount = e.values[4];
  var total = price * amount;

  var row = e.range.getRow();

  var recipient = 'hogehoge@example.com'; //送信先メールアドレス
  var subject = '備品購入申請のお知らせ';
  var body = '';
  body += '備品購入申請がありました。\n\n';
  body += '・購買先: ' + shop + '\n';
  body += '・品名: ' + item + '\n';
  body += '・単価: ' + price + ' 円\n';
  body += '・数量: ' + amount + '\n';
  body += '・総額: ' + total + ' 円\n\n';  
  body += '以下URLをクリックしてみてください\n';
  body += 'https://script.google.com/a/~exec'; //公開したウェブアプリケーションのURL    
  body += '?row=' + row;

  GmailApp.sendEmail(recipient, subject, body);
  
}

承認者宛に申請があったことを知らせるために、以下のようなメールを送るものです。

スクリプトを呼び出すURLを含むGmailのメッセージ

このメッセージ内のURLはウェブアプリケーションを公開して取得したもので、クリックすると、以下のdoGet関数を起動します。

function doGet(e) {

  var html = '';
  html += '

備品購入申請のお知らせ

'; html += '<p>あなたは備品購入申請のメールのリンクを踏みました'; html += '<p>パラメータrow: ' + e.parameter.row + ''; return HtmlService.createHtmlOutput(html); }

doGet関数はメッセージ内のURLから引き回してきたパラメータ「row」を反映させつつ、以下のようなウェブページを表示します。

公開したウェブアプリケーションのページでパラメータを表示

…とここまで作りました。

今回は、メッセージ内のURLをクリックしたら「申請を承認したことにする」ように修正をしていきたいと思います。

フォーム送信時のスクリプトを変更する

まずスクリプトsendMessageを変更していきます。

function sendMessage(e) {

  var shop = e.values[1];
  var item = e.values[2];
  var price = e.values[3];
  var amount = e.values[4];
  var total = price * amount;

  var row = e.range.getRow();
  var sheet = e.range.getSheet();
  sheet.getRange(row, 8).setValue('確認中');

  var recipient = 'hogehoge@example.com'; //送信先メールアドレス
  var subject = '備品購入申請のお知らせ';
  var body = '';
  body += '備品購入申請がありました。\n\n';
  body += '・購買先: ' + shop + '\n';
  body += '・品名: ' + item + '\n';
  body += '・単価: ' + price + ' 円\n';
  body += '・数量: ' + amount + '\n';
  body += '・総額: ' + total + ' 円\n\n';  
  body += '承認する場合は、以下URLをクリックしてください\n';
  body += 'https://script.google.com/a/~exec'; //公開したウェブアプリケーションのURL    
  body += '?row=' + row;

  GmailApp.sendEmail(recipient, subject, body);
  
}

Rangeオブジェクトの属するSheetオブジェクトを取得

まず、変更箇所は10行目と11行目ですね。

Rangeオブジェクトから、getSheetメソッドを使うことで、そのRangeオブジェクトが属するSheetオブジェクトを取得することができます。

Rangeオブジェクト.getSheet()

それで、スプレッドシートの8列目(H列)を「ステータス」として、そこに「確認中」と記入するようにしました。

フォームの送信を受け取ったときに、以下のように入力されます。

スプレッドシートにステータスが追加

メッセージのURLをクリックすると承認

あと22行目ですが、「承認する場合は、以下URLをクリックしてください」と変更しました。

以下のようなメッセージになります。

承認者向けのGmailメッセージ

doGet関数のスクリプトを変更する

doGet関数は以下のように修正しました。

function doGet(e) {
  
  var row = e.parameter.row;
  var sheet = SpreadsheetApp.getActiveSheet();
  var values = sheet.getRange(row, 1, 1, 8).getValues()[0];

  var shop = values[1];
  var item = values[2];
  var price = values[3];
  var amount = values[4];
  var total = price * amount;
  
  sheet.getRange(row, 8).setValue('承認');

  var recipient = values[6];
  var subject = '備品購入申請承認のお知らせ';
  var body = '';
  body += '以下の備品購入申請が承認されました。\n\n';
  body += '・購買先: ' + shop + '\n';
  body += '・品名: ' + item + '\n';
  body += '・単価: ' + price + ' 円\n';
  body += '・数量: ' + amount + '\n';
  body += '・総額: ' + total + ' 円\n\n';  
  
  GmailApp.sendEmail(recipient, subject, body);
  
  var html = '';
  html += '

備品購入申請のお知らせ

'; html += '<p>あなたは以下の備品購入申請を承認しました'; html += '
    '; html += '
  • 購買先: ' + shop + '
  • '; html += '
  • 品名: ' + item + '
  • '; html += '
  • 単価: ' + price + '
  • '; html += '
  • 数量: ' + amount + '
  • '; html += '
  • 総額: ' + total + '
  • '; html += '
'; return HtmlService.createHtmlOutput(html); }

だいぶ長くなりました…!

スプレッドシートからデータを取得し「承認する」

まず3行目~13行目は、スプレッドシートから該当の申請に関する行を配列として取得しているところです。

5行目ですが、getValuesメソッドは二次元配列なのですが、今回は一行分のデータだけなので、インデックス0の要素を取り出すことで、一次元配列としています。

それで、13行目でステータスを「承認」に変更しています。

スプレッドシートのステータスが承認

申請者に承認を通知するメッセージを送る

スプレッドシートのG列には、申請者のメールアドレスをとっておいてありますので、これを使って「承認されたよメール」を送ることができます。

その部分が、15~25行目ですね。

ちょっと、seneMessageと同じような表現があって冗長ですが、以降の記事で整理していきます(多分)。

申請者に送信されるGmailメッセージはこちらです。

Gmailメッセージで承認のお知らせ

Webページに承認内容を表示する

調子に乗って、承認者がURLを踏んだあとに表示されるWebページの表示も変更しました。

27~37行目です。

承認内容を箇条書きで表示するようにしました。

これで、以下のような表示になります。

承認後に表示されるWebページ

まとめ

以上、URLクリックで「承認」とするGASのスクリプトの作り方についてお伝えしました。

シンプルではありますが、これで一連の流れはできましたね。

ただ、各スクリプトで冗長な部分が散見されますので、そのあたりを修正したいですね。

また、「承認」だけでなく「否認」もできるようにしたいですよね。

次回以降、対応をしていきたいと思います。

GASで送信するGmailのメッセージをプレーンでもHTMLでも送れるようにする
Google Apps Scriptで備品購入申請を題材にワークフローを作成する方法をお伝えしています。今回は、GASで送るGmailメッセージをプレーンでもHTMLでも送れるようにする方法についてです。

どうぞお楽しみに!

連載目次:初心者でも作れるGASによる簡単ワークフロー

スプレッドシート、Gmail、フォーム…Google Apps Scriptで操作できるアプリケーションはまさに「ワークフロー」を作成する上で必要なものが揃っています。ということで、このシリーズでは初心者でも簡単に作れるワークフローの作り方について解説をしていきます。
  1. 備品購入申請フォームをGoogleフォームで作成する方法
  2. Google Apps Scriptでフォーム送信時にメッセージを送るスクリプトの作り方
  3. Google Apps Scriptでフォーム送信した内容を含んだメッセージをGmailで送るスクリプト
  4. Google Apps Scriptで特定のURLを踏んだらスクリプトを動作させるdoGet関数の使い方
  5. GASでURLを踏んでスクリプトを動作させたときにパラメータを渡す方法
  6. 【GASで作るワークフロー】URLクリックで「承認」とするスクリプトの作り方
  7. GASで送信するGmailのメッセージをプレーンでもHTMLでも送れるようにする
  8. GASのワークフローでURLのパラメータで承認・否認を切り替える方法

GASで送信するGmailのメッセージをプレーンでもHTMLでも送れるようにする

$
0
0
mailbox

photo credit: Hindrik S Hurrying to get there via photopin (license)

みなさん、こんにちは!
タカハシ(@ntakahashi0505)です。

Google Apps Scriptで備品購入申請を題材にワークフローを作成する方法をお伝えしています。

前回の記事はこちら。

【GASで作るワークフロー】URLクリックで「承認」とするスクリプトの作り方
Google Apps Scriptで備品購入申請を題材にワークフローを作成する方法をお伝えしています。今回は、承認者に送られたGmail内のURLクリックで「承認」とするスクリプトの作り方をお伝えします。

メール内のURLをクリックすることでワークフローの承認ができるようにスクリプトを作成しました。

今回は、Gmailで送るメッセージをHTMLメールでも送れるようにしていきたいと思います。

ということで、GASでGmailで送るメッセージをプレーンでもHTMLでも送れるようにする方法です。

では、行ってみましょう!

前回のおさらい

前回までのおさらいを順を追って解説しますね。

Googleフォームで備品購入申請を送信

以下のような備品購入申請のフォームをGoogleフォームで作りました。

Googleフォームによる備品購入申請

こちら申請内容を入力して送信をすると、連携するスプレッドシートに、送信したデータが蓄積されます。

スプレッドシートに追加された申請データ

承認者にGmailでメッセージが届く

それとともに、承認者に以下のようなメッセージがGmailで届きます。

承認者向けのGmailメッセージ

これは、フォーム送信時のトリガーによって、以下のスクリプトsendMessageが動作することによるものです。

function sendMessage(e) {

  var shop = e.values[1];
  var item = e.values[2];
  var price = e.values[3];
  var amount = e.values[4];
  var total = price * amount;

  var row = e.range.getRow();
  var sheet = e.range.getSheet();
  sheet.getRange(row, 8).setValue('確認中');

  var recipient = 'hogehoge@example.com'; //送信先メールアドレス
  var subject = '備品購入申請のお知らせ';
  var body = '';
  body += '備品購入申請がありました。\n\n';
  body += '・購買先: ' + shop + '\n';
  body += '・品名: ' + item + '\n';
  body += '・単価: ' + price + ' 円\n';
  body += '・数量: ' + amount + '\n';
  body += '・総額: ' + total + ' 円\n\n';  
  body += '承認する場合は、以下URLをクリックしてください\n';
  body += 'https://script.google.com/a/~exec'; //公開したウェブアプリケーションのURL    
  body += '?row=' + row;

  GmailApp.sendEmail(recipient, subject, body);
  
}

URLクリックで承認の処理を行う

承認者がGmail内のURLは公開しているWebアプリケーションのもので、クリックすると以下のdoGet関数が動作します。

function doGet(e) {
  
  var row = e.parameter.row;
  var sheet = SpreadsheetApp.getActiveSheet();
  var values = sheet.getRange(row, 1, 1, 8).getValues()[0];

  var shop = values[1];
  var item = values[2];
  var price = values[3];
  var amount = values[4];
  var total = price * amount;
  
  sheet.getRange(row, 8).setValue('承認');

  var recipient = values[6];
  var subject = '備品購入申請承認のお知らせ';
  var body = '';
  body += '以下の備品購入申請が承認されました。\n\n';
  body += '・購買先: ' + shop + '\n';
  body += '・品名: ' + item + '\n';
  body += '・単価: ' + price + ' 円\n';
  body += '・数量: ' + amount + '\n';
  body += '・総額: ' + total + ' 円\n\n';  
  
  GmailApp.sendEmail(recipient, subject, body);
  
  var html = '';
  html += '

備品購入申請のお知らせ

'; html += '<p>あなたは以下の備品購入申請を承認しました'; html += '
    '; html += '
  • 購買先: ' + shop + '
  • '; html += '
  • 品名: ' + item + '
  • '; html += '
  • 単価: ' + price + '
  • '; html += '
  • 数量: ' + amount + '
  • '; html += '
  • 総額: ' + total + '
  • '; html += '
'; return HtmlService.createHtmlOutput(html); }

これにより、承認者には以下のWebページが表示されます。

承認後に表示されるWebページ

また、申請者にはGmailにより以下のメッセージが送信されます。

Gmailメッセージで承認のお知らせ

プレーン版とHTML版の箇条書きテキストを返す関数

さて、上記のスクリプトをご覧いただいて、かなり冗長な部分がありますよね。

まず、スクリプトsendMessageの3~7行目および17~21行目あたり、doGet関数の7~11行目、19~23行目および30~36行目あたりです。

メール本文だったり、HTMLだったりするのですが、似たようなことをしているので統一しちゃいたいですよね…

で、どうするかというと、プレーンもHTMLも作る関数を作って、好きなほうを都度チョイスできるようにしていきましょう。

以下のような関数generateBodiesという関数を作りました。

function generateBodies(values){
  var shop = values[1];
  var item = values[2];
  var price = values[3];
  var amount = values[4];
  var total = price * amount;
  
  var plane = '';
  plane += '・購買先: ' + shop + '\n';
  plane += '・品名: ' + item + '\n';
  plane += '・単価: ' + price + ' 円\n';
  plane += '・数量: ' + amount + '\n';
  plane += '・総額: ' + total + ' 円\n\n';  

  var html = '
    '; html += '
  • 購買先: ' + shop + '
  • '; html += '
  • 品名: ' + item + '
  • '; html += '
  • 単価: ' + price + '
  • '; html += '
  • 数量: ' + amount + '
  • '; html += '
  • 総額: ' + total + '
  • '; html += '
'; return { plane: plane, html: html }; }

備品購入申請の一行分のデータを配列で受け取って、その内容をプレーン版とHTML版の箇条書きにして返します。

オブジェクトで返せば、複数の値も返せますもんね。

GmailでHTMLメールを送る

せっかくHTML版の箇条書きを作ったので、Gmailで送るメッセージもHTMLメールにしちゃいましょう。

GmailAppのsendEmailメソッドですが、第4引数にはオブジェクト形式で様々なオプションを設定できます。

GmailApp.sendEmail(送信先アドレス, 件名, 本文, オプション)

このオプションに、htmlBodyというプロパティ名でHTML文字列を与えてあげればOK。

相手先のメーラーがHTMLに対応していればHTML表示に、そうでなければ「本文」で指定したプレーンな文字列が表示されます。

ワークフローのスクリプトを整理

以上を踏まえて、スクリプトsendMessageと、doGet関数を整理しました。

申請の通知メールをHTMLメール化

まずはスクリプトsendMessageから。

function sendMessage(e) {

  var row = e.range.getRow();
  var sheet = e.range.getSheet();
  sheet.getRange(row, 8).setValue('確認中');
  var bodies = generateBodies(e.values);

  var url = 'https://script.google.com/a/~exec'; //公開したウェブアプリケーションのURL
  url += '?row=' + row;

  var recipient = 'hogehoge@example.com'; //送信先メールアドレス
  var subject = '備品購入申請のお知らせ';
    
  var body = '';
  body += '以下の備品購入申請がありました。\n\n';
  body += bodies.plane;
  body += '承認する場合は、以下URLをクリックしてください\n';
  body += url

  var html = '';
  html += '

備品購入申請のお知らせ

'; html += '<p>以下の備品購入申請がありました。'; html += bodies.html; html += '<p>承認する場合は、こちらをクリックしてください'; GmailApp.sendEmail(recipient, subject, body, { htmlBody: html }); }

プレーン版とHTML版の両方の本文を作っているわりには、若干スッキリできたかなと思います。

6行目でgenerateBodies関数を呼び出しています。

また、HTMLメールが送れるようになったので、24行目の部分ですが、URLを剥き出しにせずに「こちら」にリンクを加えることができるようになりました。

実際のメッセージの表示はこちらです。

備品購入申請のお知らせのHTMLメール

承認の通知をHTMLメール化

続いてdoGet関数です。

function doGet(e) {
  
  var row = e.parameter.row;
  var sheet = SpreadsheetApp.getActiveSheet();
  var values = sheet.getRange(row, 1, 1, 8).getValues()[0];
  var bodies = generateBodies(values);
  
  sheet.getRange(row, 8).setValue('承認');
  
  var recipient = values[6];
  var subject = '備品購入申請承認のお知らせ';
  
  var body = '';
  body += '以下の備品購入申請が承認されました。\n\n';
  body += bodies.plane;
  
  var html = '';
  html += '

備品購入承認のお知らせ

'; html += '<p>以下の備品購入申請が承認されました。'; html += bodies.html; GmailApp.sendEmail(recipient, subject, body, { htmlBody: html }); var html = ''; html += '

備品購入申請の承認

'; html += '<p>あなたは以下の備品購入申請を承認しました'; html += bodies.html; return HtmlService.createHtmlOutput(html); }

こちらも、6行目にgenerateBodies関数を呼び出して、送信するメッセージをHTMLメールに変更しています。

結果はこちらです。

HTMLメールで備品購入承認のお知らせ

まとめ

以上、GASでGmailで送るメッセージをプレーンでもHTMLでも送れるようにする方法をお伝えしました。

今回、スクリプトを整理をしつつ、HTMLメールにも対応するようにしました。

以降のシリーズで、ボタンでクリックできるようにしたいので、その布石でもありますね。

次回ですが、URLを二つ用意して申請の「否認」もできるようにしていきたいと思います。

GASのワークフローでURLのパラメータで承認・否認を切り替える方法
Google Apps Scriptで備品購入申請を題材にワークフローを作るシリーズをお送りしております。今回はGASのワークフローでURLのパラメータで承認・否認を切り替える方法をお伝えします。

どうぞお楽しみに!

連載目次:初心者でも作れるGASによる簡単ワークフロー

スプレッドシート、Gmail、フォーム…Google Apps Scriptで操作できるアプリケーションはまさに「ワークフロー」を作成する上で必要なものが揃っています。ということで、このシリーズでは初心者でも簡単に作れるワークフローの作り方について解説をしていきます。
  1. 備品購入申請フォームをGoogleフォームで作成する方法
  2. Google Apps Scriptでフォーム送信時にメッセージを送るスクリプトの作り方
  3. Google Apps Scriptでフォーム送信した内容を含んだメッセージをGmailで送るスクリプト
  4. Google Apps Scriptで特定のURLを踏んだらスクリプトを動作させるdoGet関数の使い方
  5. GASでURLを踏んでスクリプトを動作させたときにパラメータを渡す方法
  6. 【GASで作るワークフロー】URLクリックで「承認」とするスクリプトの作り方
  7. GASで送信するGmailのメッセージをプレーンでもHTMLでも送れるようにする
  8. GASのワークフローでURLのパラメータで承認・否認を切り替える方法

GASのワークフローでURLのパラメータで承認・否認を切り替える方法

$
0
0
no

photo credit: byronv2 No via photopin (license)

みなさん、こんにちは!
タカハシ(@ntakahashi0505)です。

Google Apps Scriptで備品購入申請を題材にワークフローを作るシリーズをお送りしております。

前回の記事はこちら。

GASで送信するGmailのメッセージをプレーンでもHTMLでも送れるようにする
Google Apps Scriptで備品購入申請を題材にワークフローを作成する方法をお伝えしています。今回は、GASで送るGmailメッセージをプレーンでもHTMLでも送れるようにする方法についてです。

GmailのメッセージをプレーンとHTMLとの両方を作るルーチンを作成しました。

ただ、これまでの内容ですと、承認者は「承認」しかできません。

NG出したいときもありますもんね。

ということで、今回はGASのワークフローでURLのパラメータで承認・否認を切り替える方法です。

では、行ってみましょう!

前回のおさらい

まず、前回のおさらいからです。

Googleフォームで備品購入申請

備品購入申請をする際には、以下のGoogleフォームから申請をします。

Googleフォームによる備品購入申請

送信すると、連携している以下のスプレッドシートにその申請内容が蓄積されます。

スプレッドシートに追加された申請データ

Gmailで承認者にメッセージを送信

と、同時に「フォーム送信時」のトリガーが発火して、以下のスクリプトsendMessageが動作します。

function sendMessage(e) {

  var row = e.range.getRow();
  var sheet = e.range.getSheet();
  sheet.getRange(row, 8).setValue('確認中');
  var bodies = generateBodies(e.values);

  var url = 'https://script.google.com/a/~exec'; //公開したウェブアプリケーションのURL
  url += '?row=' + row;

  var recipient = 'hogehoge@example.com'; //送信先メールアドレス
  var subject = '備品購入申請のお知らせ';
    
  var body = '';
  body += '以下の備品購入申請がありました。\n\n';
  body += bodies.plane;
  body += '承認する場合は、以下URLをクリックしてください\n';
  body += url

  var html = '';
  html += '

備品購入申請のお知らせ

'; html += '<p>以下の備品購入申請がありました。'; html += bodies.html; html += '<p>承認する場合は、こちらをクリックしてください'; GmailApp.sendEmail(recipient, subject, body, { htmlBody: html }); }

このスクリプトは、承認者に以下のようなGmailメッセージを送るものです。

備品購入申請のお知らせのHTMLメール

画像はHTMLメールですが、HTMLメールに対応していないメーラーを使っている場合は、プレーンな内容のメールが送られます。

以下のgenerateBodies関数がそれらの文字列の生成を担当しています。

function generateBodies(values){
  var shop = values[1];
  var item = values[2];
  var price = values[3];
  var amount = values[4];
  var total = price * amount;
  
  var plane = '';
  plane += '・購買先: ' + shop + '\n';
  plane += '・品名: ' + item + '\n';
  plane += '・単価: ' + price + ' 円\n';
  plane += '・数量: ' + amount + '\n';
  plane += '・総額: ' + total + ' 円\n\n';  

  var html = '
    '; html += '
  • 購買先: ' + shop + '
  • '; html += '
  • 品名: ' + item + '
  • '; html += '
  • 単価: ' + price + '
  • '; html += '
  • 数量: ' + amount + '
  • '; html += '
  • 総額: ' + total + '
  • '; html += '
'; return { plane: plane, html: html }; }

doGet関数で承認処理をする

承認者が承認をするためにメール内の「こちら」をクリックします。

このURLはGASのウェブアプリケーション公開をして発行したURLで、踏むことで以下のdoGet関数が動作します。

function doGet(e) {
  
  var row = e.parameter.row;
  var sheet = SpreadsheetApp.getActiveSheet();
  var values = sheet.getRange(row, 1, 1, 8).getValues()[0];
  var bodies = generateBodies(values);
  
  sheet.getRange(row, 8).setValue('承認');
  
  var recipient = values[6];
  var subject = '備品購入申請承認のお知らせ';
  
  var body = '';
  body += '以下の備品購入申請が承認されました。\n\n';
  body += bodies.plane;
  
  var html = '';
  html += '

備品購入承認のお知らせ

'; html += '<p>以下の備品購入申請が承認されました。'; html += bodies.html; GmailApp.sendEmail(recipient, subject, body, { htmlBody: html }); var html = ''; html += '

備品購入申請の承認

'; html += '<p>あなたは以下の備品購入申請を承認しました'; html += bodies.html; return HtmlService.createHtmlOutput(html); }

doGet関数は承認者には「承認しました」のWebページを表示するとともに、申請者には「承認されました」のメッセージをGmailに送ります。

また、スプレッドシートの該当のレコードについて、ステータスを「承認」に変更します。

ワークフローに「否認」のフローを追加する

現在の備品購入申請では、承認者は「承認」しかできませんので、「否認」のフローを追加していきたいと思います。

どのように実現するかというと、以下のようにします。

  • 公開URLに「answer」というパラメータを付与し「ok」と「ng」のパラメータを持つ2つのリンクを用意する
    • 「answer=ok」ならば承認処理(現状存在している処理)
    • 「answer=ng」ならば否認処理

つまり、以下のように2つのURLを用意して、承認者に望む方を踏んでいただくということですね。

https://script.google.com/macros/s/{…}/exec?row=2&answer=ok
https://script.google.com/macros/s/{…}/exec?row=2&answer=ng

Gmailで承認用と否認用の2つのURLを送る

まず、スクリプトsendMessageのほうです。

こちらは、Gmailで承認者へ備品購入申請があった旨のメッセージを送る処理が含まれますので、「承認用」と「否認用」の2つのURLを送るように変更する必要がありますね。

修正したのがこちらです。

function sendMessage(e) {

  var row = e.range.getRow();
  var sheet = e.range.getSheet();
  sheet.getRange(row, 8).setValue('確認中');
  var bodies = generateBodies(e.values);

  var url = 'https://script.google.com/a/~exec'; //公開したウェブアプリケーションのURL
  url += '?row=' + row + '&answer=';

  var recipient = 'hogehoge@example.com'; //送信先メールアドレス
  var subject = '備品購入申請のお知らせ';
    
  var body = '';
  body += '以下の備品購入申請がありました。\n\n';
  body += bodies.plane;
  body += '承認する場合は、以下URLをクリックしてください\n';
  body += url + 'ok';
  body += '否認する場合は、以下URLをクリックしてください\n';
  body += url + 'ng';

  var html = '';
  html += '

備品購入申請のお知らせ

'; html += '<p>以下の備品購入申請がありました。'; html += bodies.html; html += '<p>承認する場合は、[承認]をクリックしてください'; html += '<p>否認する場合は、[否認]をクリックしてください'; GmailApp.sendEmail(recipient, subject, body, { htmlBody: html }); }

9行目で、URLにパラメータ「answer」を追加しています。

加えて、プレーン用は17~19行目、HTML用は26,27行目に承認用URLと否認用URLを仕込んでます。

変更後に実行すると、以下のようなメッセージが送信されますよ。

承認者に送られるGmailメッセージ

doGet関数で受け取ったパラメータにより処理を変える

続いて、doGet関数です。

受け取ったパラメータをイベントオブジェクトから取り出して、if文で分岐処理して…とするとちょっと面倒そうです。

ですが、もうちょっと簡単に対応できますよ。

こちらです。

function doGet(e) {
  
  var row = e.parameter.row;
  var sheet = SpreadsheetApp.getActiveSheet();
  var values = sheet.getRange(row, 1, 1, 8).getValues()[0];
  var bodies = generateBodies(values);

  var answer = e.parameter.answer;
  var result = {
    ok: '承認',
    ng: '否認'
  };
  
  if(answer){
    sheet.getRange(row, 8).setValue(result[answer]);
    
    var recipient = values[6];
    var subject = '備品購入申請' + result[answer] + 'のお知らせ';
    
    var body = '';
    body += '以下の備品購入申請が' + result[answer] + 'されました。\n\n';
    body += bodies.plane;
    
    var html = '';
    html += '

備品購入' + result[answer] + 'のお知らせ

'; html += '<p>以下の備品購入申請が' + result[answer] + 'されました。'; html += bodies.html; GmailApp.sendEmail(recipient, subject, body, { htmlBody: html }); var html = ''; html += '

備品購入申請の' + result[answer] + '

'; html += '<p>あなたは以下の備品購入申請を' + result[answer] + 'しました'; html += bodies.html; return HtmlService.createHtmlOutput(html); } }

ポイントは9~12行目のオブジェクトresultですね。

プロパティokに「承認」、ngに「否認」という文字列を格納しています。

つまり、GmailメッセージやWebページで掲載する文言を、このプロパティがどちらかだけを見てオブジェクトのキー指定で内容を切り替えてしまおうという作戦です。

Webアプリケーションのバージョンを上げて、動作を確認します。

否認の場合は、以下のようなWebページが表示されます。

申請が否認された場合のWebページ

Gmailのメッセージも「備品購入申請否認のお知らせ」になっていますので確認してみてください。

まとめ

以上、GASのワークフローでURLのパラメータで承認・否認を切り替える方法をお伝えしました。

非常に簡易的ではありますが、Googleフォーム、スプレッドシート、Gmail、そしてGASを使用してワークフローを作る方法をお伝えしてきました。

今回は、Gmailを使いましたが、代わりにChatworkやSlackを使うこともできますね。

ぜひ、トライしてみてくださいね。

このシリーズはこれで以上となります。

また、便利そうなツールがありましたら、その作り方を紹介していきますね。

どうぞお楽しみに!

連載目次:初心者でも作れるGASによる簡単ワークフロー

スプレッドシート、Gmail、フォーム…Google Apps Scriptで操作できるアプリケーションはまさに「ワークフロー」を作成する上で必要なものが揃っています。ということで、このシリーズでは初心者でも簡単に作れるワークフローの作り方について解説をしていきます。
  1. 備品購入申請フォームをGoogleフォームで作成する方法
  2. Google Apps Scriptでフォーム送信時にメッセージを送るスクリプトの作り方
  3. Google Apps Scriptでフォーム送信した内容を含んだメッセージをGmailで送るスクリプト
  4. Google Apps Scriptで特定のURLを踏んだらスクリプトを動作させるdoGet関数の使い方
  5. GASでURLを踏んでスクリプトを動作させたときにパラメータを渡す方法
  6. 【GASで作るワークフロー】URLクリックで「承認」とするスクリプトの作り方
  7. GASで送信するGmailのメッセージをプレーンでもHTMLでも送れるようにする
  8. GASのワークフローでURLのパラメータで承認・否認を切り替える方法

【Outlook VBA】イベントApplication_Startupで起動時に今日の予定を表示する方法

$
0
0

eyecatch,outlook,application_startup

皆様こんにちは、ノグチです。

Outlookの予定、便利ですよね。

カレンダー形式で予定を把握しやすいし、予定の時刻前になるとアラートを出してくれたり…

でも、予定をすっかり忘れていたりして、予定直前にアラートが表示されて慌ててしまったりすること、ありませんか?

毎日お仕事を開始するとき、そう、例えばPCを開いてOutlookを起動したときに、今日の予定がまとめて表示出来れば…

それ、Outlook VBAなら、できるかもしれませんよ。

ということで今回は、前回ご紹介した登録済みの予定を取得する方法と、Outlook起動時イベントを組み合わせて、Outlook起動時に本日の予定をダイアログで表示する方法をご紹介します!

イベントプロシージャのコーディング準備

まず、イベントプロシージャのコーディング準備をしましょう。

イベントプロシージャのコーディングをしたい場合は、Microsoft Outlook Object内のモジュールに処理を書いていく必要があります。

まずOutlookでVBEを開いて、画面左側に表示されている、「This Outlook Session」をダブルクリックします。

outlook,vba,VBE

すると、標準モジュールなどと同じように、コーディングの画面が右側に現れます。

そして画像のように、左側のドロップダウンリストから「Application」を選択します。

outlook,vba,VBE,リスト

すると、右側にイベントプロシージャのリストが表示されますので、この中から使いたいイベントプロシージャを選択すると…
outlook,vba,VBE,リスト,エディター

このように、イベントプロシージャがエディター部分に表示されます。

イベントに処理を追加するには、このエディター部分に表示されたプロシージャ内にコードを書いていきます。

標準モジュール内にイベントプロシージャを書き込んでも意味がないのでご注意を!!

Outlook起動時のApplication_Startup

Excel同様に、Outlookにも色々なイベントプロシージャがあります。

今回ご紹介するのは、Outlook起動時に実行される、Application_Startupというイベントプロシージャ。

Outlookを起動したときにメッセージを表示させるなどの処理をさせたいならば、このイベントプロシージャApplication_Startup内に処理を書き込めばOKなのです。

Application_StartupでOutlook起動時の処理を差し込む

試しに、このイベントプロシージャ内にメッセージを表示させる処理を差し込んでみましょう。

コードはこちら。
Private Sub Application_Startup()

MsgBox "こんにちは!"

End Sub

とっても単純ですね。

そしてOutlookを起動してみると…

outlook,vba,起動時

この通り、Outlook起動と同時にメッセージが表示されますね。

登録済みの予定をメッセージで表示させる

さて、起動時のメッセージが表示出来たら、お次は前回ご紹介した、Outlookの予定を取得する方法と組み合わせてみましょう。

まず、前回の記事はコチラ。

【Outlook VBA】登録済みの予定を日付で検索して取得する方法
Outlook VBAで、Outlookに登録した予定を取得してメッセージ表示する方法をご紹介しています。この方法と、Outlookに用意されているイベントと組み合わせて使えば、Outlookを更に使い勝手良く使うことができますよ。

実は、前回記事でご紹介したコードをまるまるそっくりもってくればOK。

前回記事のコードとの違いは、プロシージャ名がイベントプロシージャ名に変わったくらいです。

組み合わせたコードがこちら。

Private Sub Application_Startup()
Dim myNamespace     As NameSpace
Dim myFolder        As Object
Dim ObjAppo         As Object
Dim strMsg          As String

Set myNamespace = GetNamespace("MAPI")
Set myFolder = myNamespace.GetDefaultFolder(olFolderCalendar)

For Each ObjAppo In myFolder.Items
    
    If Format(ObjAppo.Start, "yyyy/mm/dd") = Format(Date "yyyy/mm/dd") Then
        With ObjAppo
            strMsg = strMsg & Format(.Start, "hh:mm") & Space(3) & _
                    ObjAppo.Subject & vbCrLf
        End With
    End If
Next ObjAppo

MsgBox strMsg

End Sub

上のコードを保存したら、今日の日付で予定をいくつか登録しておきましょう。
outlook,予定
こんな感じでいくつか予定を登録したら、Outlookを再起動させてみます。
すると…
outlook,vba,今日の予定
この通り、Outlookの起動と同時に、今日の予定がダイアログで表示されましたね。

最後に

今回は、Outlookに登録済みの予定を取得する方法と、Outlook起動時イベントを組み合わせて、Outlook起動時に今日の予定をダイアログで表示させる方法をご紹介しました。

仕事の予定などは、毎日仕事を始めるタイミングで手帳を見たり、Outlookの予定を見たりして確認するのですが、たまに抜けてしまうこともあったり…

でも、この方法を使えばそんな予定の把握もぐっと楽になりますよ。

予定以外にもToDoやタスクリストの取得と組み合わせても便利かもしれませんね。

そもそもOutlookに予定を登録し忘れる!という場合は…別の方法を考えてみましょう。

それでは、最後までお読みいただきありがとうございました!

【QUERY関数】order by句で抽出結果を昇順・降順ソートする

$
0
0

QUERY関数8アイキャッチ

みなさんこんにちは!
もり(@moripro3)です。

GoogleスプレッドシートQUERY関数の使い方をシリーズでお届けしています!

前回はwhere句とand,orを使用して複数条件を指定する方法を紹介しました。

【QUERY関数】where句でand,orを使用して複数条件を指定する方法
GoogleスプレッドシートのQUERY関数を紹介するシリーズ。第七回目は、where句とand,orを使用した複数条件での抽出です。andとorを組み合わせた3つ以上の条件指定の方法も紹介しています。

これまでシリーズを通して紹介してきたselect句・where句は、データ抽出をする句です。

QUERY関数で抽出したデータに対して、なんらかの加工ができたらもっと便利ですよね。
たとえば、抽出結果を並び替える、特定の列で集計する、などです。

今回は、抽出結果の並び替えができる order by句の使い方を紹介します。それではみていきましょう!

QUERY関数で並び替えをするメリット

「データの並び替え」と聞くと、スプレッドシートの並び替え機能を思い浮かべる方もいるでしょう。

スプレッドシートの並び替え機能を使うと、元データの並び順そのものが変わってしまいます。さらに、データの値が変わったり、行が追加された場合、再度、手作業で並び替えをしなおす必要があります。

それに対して、QUERY関数で並び替えをするメリットは2つあります。

  • 元データとは別シートに並び替え結果を表示できるため、元データの並び順を維持できる
  • 元データに変更・追加が発生した場合も、自動で並び替えされる

データの並び替えの方法には昇順・降順の2通りがあります。2つの違いを詳しくみていきましょう。

昇順ソート・降順ソートとは

データの並び替えをする方法は下記の2通りあります。

ソート方法 英語表記 説明
降順ソート descending(ディセンディング) 大きい順に並べる 9,7,5,3,1
昇順ソート ascending(アセンディング) 小さい順に並べる 1,3,5,7,9

今回使用するのはこちらの備品購入リストです。D列の「単価」の数字を基準にして、行の並び替えをしてみます。

query8-1

行を並び替えるorder by句

order by句とは、指定された列の値で行を並び替える句です。

order by 列 [ソート方法]

[ソート方法]の部分には下記のいずれかを指定します。

  1. desc(降順)
  2. asc(昇順)

それでは、descとascを使って、次の項から2通りのソートをしていきます。

大きい順に並べる降順ソート(desc)

order by句のソート方法に desc を指定すると降順ソートができます。

order by 列 desc

select句に続けて、order by句を書きます。D列を大きい順に並べる書き方がこちらです。

=query('備品購入リスト'!A:E,"select * order by D desc",1)

query8-2

D列が大きい順、つまり、単価が高い順にソートすることができました。

小さい順に並べる昇順ソート(asc)

order by 句のソート方法に asc を指定すると昇順ソートができます。

order by 列 asc

D列価格の小さい順(安い順)にソートしてみると・・・

ヘッダー行だけは正しく取得できていますが、肝心のデータが表示されません。さて、いったい何がおきているのでしょうか。

=query('備品購入リスト'!A:E,"select * order by D asc",1)

query8-3

スプレッドシートの最終行までスクロールすると、シートの末尾に昇順ソートの結果が並んでいます。

query8-4

元データの範囲をA列~E列の「列全体」としているため、データなしの空白行も含めて、昇順で並び替えられているためです。つまり、数字の100よりも、データなしの方が小さいと判定されるため、空白行が上に寄っている状態です。

これでは困ってしまいますね。対処方法を2つ紹介します。

方法1 元データの範囲を絞る(非推奨)

QUERY関数・第1引数のデータ範囲を絞る方法です。データ範囲を、列全体ではなく、A1セル ~ E12セルと指定すれば、(データが存在する行のみを指定すれば)、空白行が混在することはありません。

query8-5

 

ただ、この方法はオススメしません。非推奨の方法をあえて紹介しているのは、この方法のデメリットをお伝えするためです。

「A1セル ~ E12セル」と範囲を固定すると、元データの13行目以降に行を追加しても、並び替え結果に反映されません。

行を追加するたびにQUERY関数のデータ範囲を設定しなおすのでは、QUERY関数のメリットが台無しですね。データ範囲を固定するのはやめておきましょう。

query8-6

方法2 データが存在する行のみをソート対象にする(推奨)

A列~E列のうち、データが存在する行のみをソート対象とする方法です。

  • 【変更前】A列~E列の、すべての行を並び替える
  • 【変更後】A列~E列の、データが存在する行を並び替える

order by句は、シリーズで紹介してきたwhere句と合わせて使うことが可能です。そこで、where句を使用して「データが存在する行」を抽出します。

「データが存在する行」を抽出する書き方がこちらです。

where 列 is not null

null(ヌル)とは「データがない・空っぽである」という意味です。nullをnotで反転させると、nullではない行、つまり「なんらかのデータがある行」が抽出できます。

「なんらかのデータがある行」に対して、order by句で昇順ソートします。

=query('備品購入リスト'!A:E,"select * where D is not null order by D asc",1)

このようにしておけば、元データの行が増えても、データ範囲を変更する必要がないので、QUERY関数のメリットを活かすことができます。

order by句に複数条件を指定する

order by句は、複数列を指定することが可能です。カンマ区切りで列挙します。

order by 列 [ソート方法], 列 [ソート方法], 列 [ソート方法] …

下記は、前述の項で紹介した降順ソート(desc)の結果です。D列単価が同じ金額の行があります(1,000円と300円がそれぞれ2行ずつ)

同じ値が存在する場合は、元データの並び順がそのまま保たれます。

query8-8

ここで、「D列が同じ金額の場合は、日付の古い順に並べる」というルールを設定します。

日付はシリアル値なので、日付が古い=日付が小さい、となります。つまり、日付を昇順ソートすれば、古い順に並びます。

D列の降順ソートのあとに、カンマ区切りで、A列を昇順ソートする条件を記述します。

=query('備品購入リスト'!A:E,"select * order by D desc, A asc",1)

query8-9

まとめ

今回の記事では、order by 句を使用して、指定の列を条件にして行を並び替える方法を紹介しました。

  • 大きい順に並べる降順ソート(desc)
  • 小さい順に並べる昇順ソート(asc)

また、列全体をソートするときは「空白行」に注意が必要です。where句と is not null で空白行を除外する方法も覚えておきましょう!

スプレッドシートの並び替え機能よりも、QUERY関数の方が、元データの並び順を維持できたり、元データが追加された場合も自動でソートされる、などのメリットが大きいので、ぜひ使ってみてください。

    さて次回は、QUERY関数でデータをグループ化・集計する方法を紹介します。どうぞお楽しみに!

    連載目次:GoogleスプレッドシートQUERY関数をマスターしよう

    スプレッドシートのQUERY関数を使って、データ抽出・集計を効率化する方法を紹介しています。

    1. スプレッドシートのQUERY関数を使う最初の一歩!クエリを理解する
    2. QUERY関数の基本!別シートのデータからselect句で列を取得する方法
    3. 【QUERY関数】where句と比較演算子を使って単一条件に一致した行を抽出する
    4. 【QUERY関数】where句とlike演算子を使用して指定の文字を含む行を抽出する
    5. 【QUERY関数】where句で日付データを条件にして行を抽出する
    6. 【QUERY関数】where句で時刻データを条件にして行を抽出する
    7. 【QUERY関数】where句でand,orを使用して複数条件を指定する

    スプレッドシートの処理が重い…を改善するARRAYFOMURA関数の使い方

    $
    0
    0

    みなさんこんにちは!
    テラド(@terashin1226)です!

    Googleスプレッドシートで関数の量が多くなってくると

    スプレッドシートの処理が重い…

    そんな時、ありますよね?

    本記事では1セルに書くだけで、複数のセルに関数の計算結果を反映するARRAYFOMURA関数を使い、Googleスプレッドシートの処理を速くする方法をお伝えします。

    ARRAYFOMURA関数を使えばスプレッドシートの関数の量が少なくなり、処理スピードとメンテンナンス性が向上します。

    Excelにない関数なので、意外と知らない方が多いかもしれませんが、超便利な関数なのでばっちり使いこなしちゃいましょう。

    それではいってみましょう!

    ARRAYFOMURA関数とIF関数を合わせて使ってみる

    ARRAYFOMURA関数は実際に使った方がイメージが湧きやすいため、条件判定ができるIF関数と合わせて使用した例を見ながらその効果を確認していきましょう!

    オートフィルを使って複数セルに関数を書いた場合

    まずは、ARRAYFOMURA関数を使わない場合を見ていきます。

    A列のセルの値をIF関数で判定し、文字列「いつも隣に」の場合、B列に「〇」を表示します。

    IF関数の構文は以下の通りです。

    if(条件式,条件式が成立した時の値,条件式が成立しなかった時の値)

    ARRAYFOMURA関数を使わない場合には、先頭に関数を入力し…

    オートフィル機能等を使って先頭セルの内容をコピーするかと思います。

    するとコピーされた関数内のセルは、自動的にA1→A2→…→A10と相対的な行数に合わせたセルとなります。

    例えば、B4セルの関数は元の関数から3行下がるので、指定するセルはA1→A4となっています。

    B1~B10まで関数が入力され、「いつも隣に」と条件に合致しているセルだけ「〇」がついているのがわかります。

    では、これをARRAYFOMURA関数で書き換えていきましょう!

    ARRAYFOMURA関数で書き換えた場合

    ARRAYFOMURA関数の構文は以下の通りです。

    ARRAYFOMURA(関数(セルの範囲))

    ARRAYFOMURA関数の中には、さらに関数を記載します。

    ARRAYFOMURA関数内では、関数の条件式に単一セルでなく、判定したいセルの範囲を指定します。

    それでは、C列にARRAYFOMURA関数を追加していきますよ!

    ARRAYFOMURA関数内にはさきほどのIF関数=「if(A1=”いつも隣に”,”〇”,””)」をまず記載します。そしてセル「A1」の部分をセルの範囲「A1:A10」に書き換えます。

    すると…

    1つのセルだけに書いた関数が範囲指定した行分、判定されて〇がついていますね。

    ただし!

    ARRAYFOMURA関数より下のセルは…

    このように関数が入っていませんね!

    「〇」が表示されているセルも見てみると…

    関数ではなく「〇」だけが入力されています!

    ARRAYFOMURA関数内にセル範囲を指定した関数を記載すれば、1セルの記載でオートフィルで関数をコピーした時と同様の機能を実現できます。

    しかも関数がコピーされるのではなく、反映されるのは計算結果のみなのでスプレッドシートの関数の量を減らすことができます。

    ちなみに、ARRAYFOMURA関数より下に何か値が入っていると…

    このようにエラーとなってしまうので気をつけてくださいね。

    ARRAYFOMURA関数のメリット

    例で見てきたとおり、ARRAYFOMURA関数を使うと、スプレッドシートの関数の量が減ります

    関数の量が減ることにより

    • 計算の量が減り、スプレッドシートの処理速度が向上
    • ARRAYFOMURA関数の設定されたセルのみ修正すればよく、メンテナンス性が向上

    という2つのメリットがあります。

    「スプレッドシートが重い…」
    「関数がいっぱいあってどれを修正すればいいかわからない…」

    ARRAYFOMURA関数はそんな状況を解決してくれます!

    ショートカットで入力ができる

    なんとARRAYFOMURA関数はスプレッドシートの中で唯一ショートカットキーが割り当てられている関数なんです。

    ショートカットキーは以下のとおりです。

    windowsの場合:「ctrlshift+Enter
    macの場合:「command+shift+Enter

    筆者はWindows環境なので「ctrl+shift+Enter」を使用します。

    ショートカットキーを使う場合、まずARRAYFOMURA関数内に記載する関数から書いていきます。

    関数が記入できた後に「ctrl+shift+Enter」を押すと…

    このように自動的にARRAYFOMURA関数内に、先に記載していた関数が入ってくれます。

    楽ちんですね!

    まとめ

    本記事では1セルに書くだけで、複数のセルに関数の計算結果を反映するARRAYFOMURA関数を使い、スプレッドシートの処理を速くする方法をお伝えしました!

    ARRAYFOMURA関数を使うことで関数の量が少なくなり、スプレッドシートの処理速度が向上し、メンテンナンス性も向上します。

    また、ARRAYFOMURA関数はショートカットキーで入力もできちゃいます。

    Excelにはない超便利なARRAYFOMURA関数、ぜひ覚えてご活用ください。

    それでは、最後までお読みいただきありがとうございました!

    Google Apps Scriptで西暦を和暦に変換するスクリプト「令和」対応版

    $
    0
    0

    reiwa

    みなさん、こんにちは!
    タカハシ(@ntakahashi0505)です。

    新しい元号が「令和」に決まりましたね!

    以前、こんな記事を書いておりました。

    Google Apps Scriptで西暦を和暦変換するスプレッドシート関数を作る
    Google Apps Scriptを使ってスプレッドシートの自作関数を作る方法です。今回は西暦から和暦を求める関数の作成方法。if~else if文、比較演算子、数値と文字列の演算なども含めてお伝えします。

    西暦を和暦に変換するGoogle Apps Scriptのスクリプトです。

    で、令和の計算も入れておこうということで、今回はGoogle Apps Scriptで西暦を和暦に変換するスクリプト「令和」対応版を紹介したいと思います。

    では、行ってみましょう!

    前回のおさらい

    では、前回のおさらいから。

    まず、スプレッドシートにバインドするスクリプトでreturnを持つ関数は、スプレッドシートのカスタム関数として機能するというとても素敵な事実があります。

    なので、それを利用して和暦変換のカスタム関数を作ったんですね。

    スクリプトはこちらでした。

    /**
     * 西暦から和暦を返すカスタム関数
     * 
     * @param {Number} 西暦
     * @return {String} 和暦
     * @customfunction
     */
    function WAREKI(n){
    
      var result;
    
      if(n >= 1989){
        result = "平成"+(n-1988);
      }else if(n >= 1926){
        result = "昭和"+(n-1925);
      }else if(n >= 1912){
        result = "大正"+(n-1911);
      }else if(n >= 1868){
        result = "明治"+(n-1867);
      }else{
        result = "計算不能";
      }
    
      return result;
    }

    引数として渡された西暦年をnとして、以下のテーブルにマッチした年号と和暦年を結合した文字列を返すというものです。

    年号 元年の西暦
    平成 1989
    昭和 1926
    大正 1912
    明治 1868

    処理としては、if~else if~else文による簡単な分岐処理ですね。初心者がトライするのに良い題材です。

    ちなみに、ドキュメンテーションコメントを入れることで、スプレッドシート上で概要を表示したり、補完対象にしたりすることもできるので、ぜひ積極的に入れておきましょう。

    詳しくは以下の記事をどうぞ!

    【初心者向けGAS】Google Apps Scriptのドキュメンテーションコメントの書き方
    初心者向けGoogle Apps Script入門、名言Botを作るシリーズをお送りしています。あとで見返すとき、再利用するときなどに備えて、ドキュメンテーションコメントの書き方について解説をします。

    和暦変換を「令和」に対応する

    この和暦変換のカスタム関数WAREKIを「令和」に対応させていきます。

    前述のスクリプトについて、平成の前に「令和」かどうかの判定をする分岐処理を入れれば良さそうですね。

    先ほどのテーブルについて令和を加えたバージョンに更新すると、以下のようになりますね。

    年号 元年の西暦
    令和 2019
    平成 1989
    昭和 1926
    大正 1912
    明治 1868

    2019年が令和1年、2020年が令和2年ですから、n年は令和(n – 2018)年になります。

    なので、スプレッドシート関数WAREKIのスクリプトはこんな感じでよろしいかと。

    /**
     * 西暦から和暦を返すカスタム関数
     * 
     * @param {Number} 西暦
     * @return {String} 和暦
     * @customfunction
     */
    function WAREKI(n){
    
      var result;
    
      if(n >= 2019){
        result = "令和"+(n-2018);
      }else if(n >= 1989){
        result = "平成"+(n-1988);
      }else if(n >= 1926){
        result = "昭和"+(n-1925);
      }else if(n >= 1912){
        result = "大正"+(n-1911);
      }else if(n >= 1868){
        result = "明治"+(n-1867);
      }else{
        result = "計算不能";
      }
    
      return result;
    }

    実際に、スプレッドシートで確認してみましょう。

    A列が西暦年、B列に「=WAREKI(A2)」などの計算式が13行目まで入っております。

    令和に対応した和暦変換スプレッドシート関数

    return文ですぐに戻り値を返す

    そういえば、変数resultを使っていましたが、わざわざ変数を使わずとも、true判定になった瞬間に、すぐに該当の戻り値を返してもよかったですね。

    ちょっとそのあたり修正しました。

    /**
     * 西暦から和暦を返すカスタム関数
     * 
     * @param {Number} 西暦
     * @return {String} 和暦
     * @customfunction
     */
    function WAREKI(n){
      
      if(n >= 2019){
        return "令和" + (n - 2018);
      }else if(n >= 1989){
        return "平成" + (n - 1988);
      }else if(n >= 1926){
        return "昭和" + (n - 1925);
      }else if(n >= 1912){
        return "大正" + (n - 1911);
      }else if(n >= 1868){
        return "明治" + (n - 1867);
      }else{
        return "計算不能";
      }  
    }

    ちょっとスッキリしました。

    switch文を使った令和対応の和暦変換関数

    あと、分岐が増えてきたので、if~else if~else文だと、ちょっと見づらい…

    そんなときに、使いたくなるswitch文がありましたね。

    switch文が多岐分岐をするときに使用する構文で、式と等しい値を値1,値2,…と順番に評価して、等しかったcase節以降の処理を実行するというものです。

    switch (式) {
     case 値1:
      //式が値1と等しかったときの処理
      break;
     case 値2:
      //式が値2と等しかったときの処理
      break;
     …
     default:
      //式がすべての値と合致しなかったときの処理
    }

    break文が入っているのは理由があって、これを入れないと、ある値がマッチしてそのcase節を実行したら、それ以降に記述されているcase節すべてが実行されちゃうのです(鬼)。

    ここは注意です。

    なお、どの値もマッチしなかったときは、default節の処理が実行されます。

    switch文を使った和暦変換のスクリプト

    それで、switch文を使って和暦変換のスプレッドシート関数WAREKI2を作りました。

    コチラです!

    /**
     * 西暦から和暦を返すカスタム関数
     * 
     * @param {Number} 西暦
     * @return {String} 和暦
     * @customfunction
     */
    function WAREKI2(n){
      
      switch (true){
        case n >= 2019:
          return "令和" + (n - 2018);
        case n >= 1989:
          return "平成" + (n - 1988);
        case n >= 1926:
          return "昭和" + (n - 1925);
        case n >= 1912:
          return "大正" + (n - 1911);
        case n >= 1868:
          return "明治" + (n - 1867);
        default:
          return "計算不能";
      }
    }

    switch文で条件式を判定したい場合は、「式」にtrueを直接放り込むというテクニックを使います。

    case節の条件式の評価値がtrueになれば、そのcase節の処理が実行されるということになります。

    これは結構便利なテクニックです。

    「しかしおいおい…、あれほど注意しろと言ってたのに、break文を忘れてるじゃねーか」

    と思いましたでしょ?

    今回はbreak文なくても大丈夫です。

    というのも、return文を実行すると、その関数の処理も終了するからです。

    つまり、今回の場合でいうとWAREKI2自体の処理が終了します。

    なので、以降の処理は実行されずに済みます。

    では、実行結果を見てみましょう。

    C列に「=WAREKI2(A1)」などとしています。

    令和に対応した和暦変換スプレッドシート関数

    問題なさそうですね。

    まとめ

    以上、Google Apps Scriptで西暦を和暦に変換するスクリプト「令和」対応版をお送りしました。

    加えて、if~else if~else文によるパターンとともに、switch文によるパターンも紹介しました。

    同じ動作をする関数を作る場合でも、場合によって「良い書き方」が変わってきますので、常にそのあたりは考えながら進めていきたいところですね。

    ということで、令和時代もGoogle Apps Scriptを精進していきましょう!

    連載目次:Google Apps Scriptで自作スプレッドシート関数

    本シリーズではGoogle Apps Script初心者向け、自作のスプレッドシート関数を作っていきます。一からとっても丁寧な解説を心がけておりますので、どうぞチャレンジしてみて下さい。
    1. 初心者でも簡単!Google Apps Scriptでスプレッドシートの自作関数を作る方法
    2. Google Apps Scriptで西暦を和暦変換するスプレッドシート関数を作る
    3. Google Apps ScriptでREST APIを使って郵便番号住所変換スプレッドシート関数を作る

    エクセルVBAでIEを操作するもっとも簡単なクラスを作成する方法

    $
    0
    0
    scraping

    photo credit: BONGURI 20181013 Denpark 8 via photopin (license)

    みなさん、こんにちは!
    タカハシ(@ntakahashi0505)です。

    エクセルVBAでInternetExplorerを操作してWebスクレイピング!

    IEはMicrosoftさんも使用してくれるなとお達しがありましたが、環境によってはしばらく頑張っていただく必要がありますかね。

    それで、実際に使用するときにはIEオブジェクトを生成したり、指定のURLにアクセスしたり、Documentオブジェクトを取得したり、読み込み待ちをしたり…

    けっこういつも同じことをしているんですよね。

    そんなときには、部品化ですよ、部品化!

    そして、部品化をするなら、クラスですよ、クラス!

    ということで、今回からシリーズで、エクセルVBAでIEを使ったスクレイピングをするときに便利なクラスの作り方をお伝えしていきます。

    なお、IEの基本操作については以下の記事からはじまるシリーズに詳しく書いていますので、そちらも参考にしてくださいね。

    【エクセルVBAでIE操作】10分で終わるセッティングとWEBページの閲覧確認
    エクセルVBAでInternetExplorerを操作するシリーズの導入編です。今回はIEを操作するときに最初にすべきセッティングと実際にWEBページを開く動作確認までをやってみたいと思います。

    まず今回は、エクセルVBAでIEを操作するもっとも簡単なクラスを作成する方法をお伝えします。

    では、行ってみましょう!

    IEによるスクレイピングの準備

    IEによるスクレイピングをする準備を進めていきましょう。

    • InternetExplorerの操作をするには「Microsoft Internet Controls」
    • HTMLの操作をするには「Microsoft HTML Object Library」

    というそれぞれのライブラリを参照設定しておく必要があります。

    以下の記事にこれらのライブラリの参照設定について詳しく書いておりますので、忘れずにやっておきましょうね。

    【エクセルVBAでIE操作】10分で終わるセッティングとWEBページの閲覧確認
    エクセルVBAでInternetExplorerを操作するシリーズの導入編です。今回はIEを操作するときに最初にすべきセッティングと実際にWEBページを開く動作確認までをやってみたいと思います。

    IEを操作するクラスを作る

    では、さっそくIEを操作するクラスを作成していきましょう。

    クラスを作成する手順は以下の記事で詳しく紹介していますので、わからない方は参考にしながら進めてみてください。

    【初心者でもできる】エクセルVBAで最も簡単なクラスを作る方法
    「初心者でもわかる!エクセルVBAのクラスモジュールの活用法」をテーマに、その使い方と便利さについてシリーズでお伝えしていきます。今回は、エクセルVBAで最も簡単なクラスを作る方法をお伝えしていきます。

    さて、まずVBEの「挿入」メニューの「クラスモジュール」からクラスモジュールを挿入します。

    クラスモジュールの挿入

    次に、挿入したクラスモジュールについて、プロパティウィンドウのオブジェクト名を「IEObject」としましょう。

    これがクラス名になります。

    クラスモジュールの名前を変更

    これで、クラス完成っす(空っぽですが)!

    以下のようなプロシージャを実行すると…

    Sub MySub()
        
        Dim ieObj As IEObject: Set ieObj = New IEObject
         
        Stop
         
    End Sub

    ほら、Stop時にローカルウィンドウを見ると、ちゃんとIEObjectのインスタンスが生成できたことが確認できますよね。

    クラスIEObjectの生成をローカルウィンドウで確認

    InternetExplorer型のプロパティを定義する

    さて、そんなIEObjectクラス。

    中身は空っぽです。メンバーとして何を持っておくべきでしょうか?

    大前提として、InternetExplorerを操作できる必要がありますよね。

    そいういうのは、ひとまずパブリック変数として宣言しておいて、プロパティとして持っておけばOKっす。

    そうすれば、IEObjectクラスはその機能を内包できるようになります。

    Public IE As InternetExplorer

    IEObjectクラスでIEを表示する

    そして、クラスモジュールで宣言したパブリック変数は、インスタンスを生成した際にはプロパティとして使用できます。

    つまりIEプロパティを経由して、IEの操作ができるはず…

    では、まずはIEを表示してみましょう。

    標準モジュールで以下プロシージャを作って実行してみます。

    Sub MySub()
        
        Dim ieObj As IEObject: Set ieObj = New IEObject
        ieObj.IE.Visible = True
        
        Stop
         
    End Sub

    VisibleプロパティはTrueにすれば、InternetExplorerオブジェクトを表示しますね。

    実行すると、以下のように空っぽですがIEが表示されます。

    VBAでIEを表示する

    IEObjectクラスでIEを閉じる

    では、次にIEObjectのIEプロパティを経由して、IEを閉じてみましょう。

    IEを閉じるには、Quitメソッドでしたね。

    以下プロシージャを実行すると、Stopから再開したときにIEが閉じることが確認できますね。

    Sub MySub()
        
        Dim ieObj As IEObject: Set ieObj = New IEObject
        ieObj.IE.Visible = True
        
        Stop
    
        ieObj.IE.Quit
         
    End Sub

    まとめ

    以上、エクセルVBAでIEを操作するもっとも簡単なクラスを作成する方法をお伝えしました。

    IEの操作方法とクラスの使い方がそれぞれなんとなくわかっていれば、たぶん大丈夫。

    もしわからない方は、記事内で紹介した記事で復習していきましょう。

    次回は、コンストラクタとデストラクタを作成していきます。

    どうぞお楽しみに!

    エクセルVBAでIEを操作するクラスでWebページを開くメソッドを追加する

    $
    0
    0
    navigate

    photo credit: La caverne aux trésors A Russian Hope via photopin (license)

    みなさん、こんにちは!
    タカハシ(@ntakahashi0505)です。

    エクセルVBAでIEによるスクレイピングをするときに便利なクラスの作り方をシリーズでお伝えしています。

    前回の記事はこちら。

    エクセルVBAでIEを操作するもっとも簡単なクラスを作成する方法
    エクセルVBAでInternetExplorerを操作してWebスクレイピング…けっこういつも同じ処理を作ります。そんなときには、クラスで部品化が有効です。まずは、IEを操作するもっとも簡単なクラスを作成します。

    IEを操作するクラスIEObjectを作成しました。

    …が、まだ機能としては何もないような状態なので、パワーアップしていきますよ。

    まずは、今回はURLを指定してWebページへのアクセスする機能を実装していきます。

    エクセルVBAでIEを操作するクラスでWebページを開くメソッドを追加するです。

    では、行ってみましょう!

    前回のおさらい

    では、前回のおさらいからです。

    まず、IEを操作するクラスIEObjectはこちら。

    Public IE As InternetExplorer
    
    Private Sub Class_Initialize()
        Set IE = New InternetExplorer
    End Sub

    はい、シンプルですね。

    今は以下の機能だけを持っています。

    • パブリック変数でInternetExplorerオブジェクトを持つIEプロパティを宣言
    • コンストラクタで、その変数に新しいInternetExplorerオブジェクトをインスタンスとしてセットする

    それで、確認用の標準モジュールのプロシージャがこちら。

    Sub MySub()
        
        Dim ieObj As IEObject: Set ieObj = New IEObject
        ieObj.IE.Visible = True
        
        Stop
    
        ieObj.IE.Quit
         
    End Sub

    これで、IEを表示して閉じる動作が実現できました。

    IEの表示と閉じるを自動で行う

    今回はIE操作では重要なWebページのアクセスなのですが、その前にやっておくことがあります。

    「ieObj.IE.Visible = True」とか、「ieObj.IE.Quit」とか、なんかかっこよくないですね。

    表示するとか、閉じるとかは、IEObjectオブジェクトを使用するなら、確実にする操作の場合が多いですよね。

    ですから、コンストラクタとデストラクタに追加しちゃいましょう。

    コンストラクタでIEを表示する

    コンストラクタは前回作成しましたね。

    ですから、そこにIEを表示する一文を追加してあげればOKです。

    Private Sub Class_Initialize()
        Set IE = New InternetExplorer
        IE.Visible = True
    End Sub

    3行目ですね。

    デストラクタでIEを閉じる

    そして、IEを閉じるのは、IEObjectが破棄されるときに行われればよいですから、デストラクタ、すなわちClass_Terminateプロシージャに記述してあげればOK!

    Private Sub Class_Terminate()
        IE.Quit
    End Sub

    これで、標準モジュールのプロシージャは以下のように書けちゃいます。

    Sub MySub()
        
        Dim ieObj As IEObject: Set ieObj = New IEObject
        
        Stop
         
    End Sub

    スッキリ!

    IEを操作するクラスでWebページにアクセスする

    では、本日の本題であるIEによるWebページのアクセスですね。

    InternetExplorerオブジェクトでURLを指定してWebページを開くには、Navigateメソッドを使いますね。

    InternetExplorerオブジェクト.Navigate URL

    これを行うメソッドを、IEObjectクラスに定義してあげます。

    以下のように、Navigateメソッドとして追加してみました。

    Public Sub Navigate(ByVal url As String)
        IE.Navigate url
    End Sub

    受け取った引数urlについて、IEで開きます。

    メソッドの作り方は以下の記事をご覧くださいね。

    エクセルVBAでクラスに最も簡単なメソッドを追加する方法
    「初心者でもわかるエクセルVBAのクラスモジュール」をテーマにシリーズをお届けしております。今回エクセルVBAでクラスに最も簡単なメソッドを追加する方法をお伝えします。Subプロシージャを使いますよ。

    では、実行して確認してみましょう。

    Sub MySub()
        
        Dim ieObj As IEObject: Set ieObj = New IEObject
        ieObj.Navigate "https://tonari-it.com"
        
        Stop
        
    End Sub

    以下のように指定したURLのページが表示されますね。

    IEクラスでWebページを開く

    まとめ

    以上、エクセルVBAでIEを操作するクラスでWebページを開くメソッドを追加する方法をお伝えしました。

    簡単ですね!

    そして標準モジュールがシンプル。

    さて、まだまだ「いつもの処理」があるかと思いますので、クラスのメンバーに追加していきます。

    次回は、ドキュメントの取得と読み込み待ちについてお伝えします。

    どうぞお楽しみに!

    連載目次:エクセルVBAでIEを操作するクラスを作る

    エクセルVBAでInternetExplorerを操作してWebスクレイピング、まだまだ現役で必要となる現場もあるでしょう。このシリーズでは、IEを使ったスクレイピングをするときに便利なクラスの作り方をお伝えします。
    1. エクセルVBAでIEを操作するもっとも簡単なクラスを作成する方法
    2. エクセルVBAでIEを操作するクラスでWebページを開くメソッドを追加する

    【Outlook VBA】メール本文から欲しい情報だけを取り出す方法

    $
    0
    0

    outlook,メール本文,アイキャッチ

    皆様こんにちは、ノグチです。

    日々のお仕事に欠かせない、メール。

    連絡手段として便利なツールですが、送られる方の日々の業務負担になっていたりすることもあります。

    例えば、日々の業務内容と作業時間をメールで報告する、所謂日報、というもの。

    この日報の中で勤務開始時間と終了時間を書いて上長に送っているのに、更に勤務表が存在していることが少なくありません。

    上長はこの日報と、部下から提出された勤務表を突き合せて勤務表の承認をするなど、業務の負荷になっていることがあるようです。

    日報として送信するメールはフォーマットが決まっていることが多いので、フォーマットに従って、見たい情報だけを取り出して、例えばエクセルのシートに書き出すことができれば、確認作業が楽になるかもしれません。

    ということで今回は、決まったフォーマットで書かれたOutlookのメール本文から、欲しい文字を取り出す方法をご紹介します!

    MailItemオブジェクトのおさらい

    さて、メールを操作するには、MailItemオブジェクトを取得する必要があることは以前の記事でお伝えしました。

    エクセルVBAでOutlookメールの下書きを作成・表示して送信前に内容チェックする
    OutlookのMailItemオブジェクトのDisplayメソッドを使って、VBAで作成したOutlookのメール内容を、メール送信前にチェックする方法をご紹介しています。「VBAでメールを作成するのは便利だけど、内容をチェックしないでメール送信してしまうのは心配...」という方にお勧めです。

    メールの本文は、MailItemオブジェクトのBodyプロパティで取得することができるので、メール本文にあった取得方法をコーディングすれば、欲しい情報がメール本文から取り出せるという訳です。

    では早速、今ウインドウで開いているメール本文から、欲しい情報を取り出してみましょう!

    ちなみに、今開いているメールのウインドウ操作については、下記記事で紹介していますので、併せてご覧くださいね。

    【Outlook VBA】今開いているOutlookウインドウを操作しよう!Inspectorオブジェクトの取得
    Outlook vbaで、メールの添付ファイルをワンクリックで指定フォルダに保存する方法を複数回記事にわたってご紹介していきます。今回は、ActiveInspectionメソッドで、今開いているOutlookウインドウのInspectorオブジェクトを取得する方法をご紹介しています。

    メール本文から目的の情報を取り出してみる

    BodyプロパティとMid関数で欲しい情報を取り出す

    例えば、下のメールから、作業時間だけを取り出したいとします。

    outlook,vba,メール本文,メール

    このメールの本文である、MailItemオブジェクトのBodyプロパティを、VBEのウォッチ式で覗いてみると、こんな感じになっています。

    outlook,vbe,デバッグ,bodyプロパティ

    一見すると1行目と2行目の間にスペースが入っているように見えますが、メール本文上で改行していますので、このスペースには改行コードの「vbCrLf」が存在しています。

    “【作業時間】13:00~16:00vbCrLf【作業時間計】5HvbCrLf【作業内容】xxxxxxxxxxxxxxxxxxxxxxxx”

    こんな風に書かれているイメージです。

    なので、メール本文の作業時間だけを取り出したいならば、メールの先頭から「【作業時間】」の6文字を除いた7文字目から、最初の改行コードまでを取り出せばOK。

    コードはこんな風に記述できます。

    Mid(MailItemオブジェクト.Body, Len("【作業時間】") + 1, Instr(MailItemオブジェクト.Body, vbCrLf) - Len("【作業時間】") + 1)

    Mid関数を使って、メール本文の7文字目から改行コードのある文字列までを取得しています。

    メールから欲しい情報を取り出す為のコードのメイン部分はこれだけです。

    メール本文から目的の情報を取り出すコード

    試しに取得した内容を、メッセージで表示してみましょう。

    全体はこんな感じのコードになります。

    今開いているメールの、【作業時間】という文字列の次の文字から改行コードまでをの文字列を取得して、メッセージ表示するというものです。

    Sub Get_MailBody()
    Dim objItem As Object
    Dim objIns As Inspector
    Dim lngStart As Long
    Dim lngEnd As Long
    
    Set objIns = Application.ActiveInspector
    Set objItem = objIns.CurrentItem   '今開いているメールオブジェクトを取得
    
        With objItem
            MsgBox Mid(objItem.Body, Len("【作業時間】") + 1, (InStr(objItem.Body, vbCrLf) - Len("【作業時間】") + 1))
        End With
    
    End Sub

    このコードを実行してみると…
    outlook,本文,取り出しこの通り、作業時間の時間だけの部分を取り出すことができました。

    メール本文は決まったフォーマットで

    この記事でご紹介した方法なら、受信メール本文ボックス内のメールを対象にして、複数のメールからまとめて文字を取り出すこともできそうです。

    例でご紹介したように、日々の勤怠を日報で上長に送っていて、その報告内容と勤務表やタイムカードと照らし合わせたい…といったとき。

    1ヶ月分のメールを対象にしてこの方法で一気に対象の文字をメールから取り出して、エクセルのシートに貼り付けて一覧にしてしまえば、楽に勤務時間や勤務内容を把握することができますね。

    しかし、そのためには送信されてくるメール本文が、決まったフォーマットで書かれている必要があります。

    【作業時間】xxxxx(改行)【作業内容】xxxxxx

    と書いて欲しいのに、

    【時間】xxxxx(改行)【作業内容】xxxxx

    のように書かれてしまうと、上のコードでは欲しい情報がメール本文から取り出せなくなってしまいます。

    なので、そのあたりの運用上のルールも考えておかなければいけません。

    最後に

    今回は、メールの本文から特定の文字を取り出す方法をご紹介しました。

    様々なシステムで勤怠管理ができるようになっている昨今、未だメールでの時間報告をしなければならない職場もあるようです。(筆者の経験より)

    メールで報告する方も面倒臭いですが、メールと勤怠表を突き合せたりして面倒くさい!とお嘆きの方は、今回の記事でご紹介した方法を使えば少し楽になるかもしれませんね。

    それでは、最後までお読みいただきありがとうございました!

    エクセルVBAでIEを操作するクラスに読み込み待ちとドキュメント取得の機能を追加する方法

    $
    0
    0
    wait

    photo credit: indrarado I’ve been to Lisbon via photopin (license)

    みなさん、こんにちは!
    タカハシ(@ntakahashi0505)です。

    エクセルVBAでIEを操作する便利なクラスの作り方をお伝えしています。

    前回の記事はコチラ。

    エクセルVBAでIEを操作するクラスでWebページを開くメソッドを追加する
    エクセルVBAでIEによるスクレイピングをするときに便利なクラスの作り方をシリーズでお伝えしています。InternetExplorerを操作するクラスでWebページを開くメソッドを追加する方法です。

    クラスIEObjectに指定のURLを開くNavigateメソッドを追加しました。

    今回は、IEで開いたページからドキュメントを取得していきます。

    また、ドキュメントを取得する前に読み込み待ちの処理も必要ですよね…

    ということで、エクセルVBAでIEを操作するクラスに読み込み待ちとドキュメント取得の機能を追加する方法です。

    では、行ってみましょう!

    前回のおさらい

    まずは前回のおさらいからです。

    これまでで作成したIEを操作するクラスIEObjectはこちらです。

    Public IE As InternetExplorer
    
    Private Sub Class_Initialize()
        Set IE = New InternetExplorer
        IE.Visible = True
    End Sub
    
    Private Sub Class_Terminate()
        IE.Quit
    End Sub
    
    Public Sub Navigate(ByVal url As String)
        IE.Navigate url
    End Sub

    パブリック変数によるIEプロパティでInternetExplorerオブジェクトを持たせて、コンストラクタでその生成と表示を行います。

    Navigateメソッドは、そのInternetExplorerオブジェクトで指定のURLのページを開くメソッドです。

    デストラクタでそのInternetExplorerを閉じます。

    それで、標準モジュールで以下のようなプロシージャを実行すると、IEを表示して、URLのページを開き、IEを閉じるという動作が実現できます。

    Sub MySub()
        
        Dim ieObj As IEObject: Set ieObj = New IEObject
        ieObj.Navigate "https://tonari-it.com"
        
        Stop
        
    End Sub

    さて、IEでページを開いたらスクレイピングをしたいわけですから、そのドキュメントを取得しないといけませんよね。

    今回はその機能をクラスに追加していきますよ。

    IEを操作するクラスでHTMLドキュメントを取得する

    開いているWebページのHTMLドキュメントを取得するには、InternetExplorerオブジェクトのDocumentプロパティを使うのでした。

    InternetExplorerオブジェクト.Document

    これでHTMLDocumentオブジェクトを取得できます。

    HTMLドキュメントについては、以下の記事もどうぞご参考ください。

    【エクセルVBAでIE操作】HTMLタグと要素そしてドキュメントの取得
    初心者向けエクセルVBAでIEを操作するシリーズの第2回目です。今回はHTMLタグと要素について簡単に説明をしつつIEで開いたページのHTMLドキュメントを取得する方法についてお伝えします。

    これを格納する場所と、格納する処理をIEObjectクラスに追加していきます。

    HTMLドキュメントを格納するプロパティ

    まず、HTMLドキュメントの格納先はパブリック変数で良いですね。

    以下の一文をIEObjectクラスの宣言セクションに追加します。

    Public Document As HTMLDocument

    これで、プロパティとしてHTMLドキュメントを取得することもできますね。

    HTMLドキュメントの取得

    そして、その取得ですが、Propertyプロシージャでもいいのですが、Navigateメソッドでページにアクセスしたときに自動で取得してもいいですよね。

    なので、Navigateメソッド内にHTMLドキュメントの取得の処理を追加しちゃいます。

    Public Sub Navigate(ByVal url As String) ', Optional sec As Long = 0
        IE.Navigate url
        Set Document = IE.Document
    End Sub

    Navigateメソッドからすぐにドキュメントを取得することはできない

    では、実行して動作確認をしてみましょうか。

    標準モジュールのプロシージャを以下のように変更して…

    Sub MySub()
        
        Dim ieObj As IEObject: Set ieObj = New IEObject
        ieObj.Navigate "https://tonari-it.com"
        
        Debug.Print ieObj.Document.Title
        
    End Sub

    実行!

    オートメーションエラー

    はい、出ましたオートメーションエラー…!

    そうなんです。

    IEがWebページを開き切る前に、ドキュメントを取得しにいってしまうので、エラーになってしまうのです。

    読み込み待ちをするWaitメソッドを追加する

    ということで、IEObjectクラスに読み込み待ちの対策も入れて行きましょう。

    まず、以下のように、Waitという読み込み待ち用のメソッドを追加します。

    Public Sub Wait()
        Do While IE.Busy = True Or IE.readyState < READYSTATE_COMPLETE
            DoEvents
        Loop   
    End Sub

    この処理はいつもの定番的なやつなので、クラス化にもってこいです。

    詳しくは以下の記事もどうぞご覧ください。

    【エクセルVBAでIE操作】ブラウザの読み込み待ちをしないとダメなのです
    エクセルVBAでIEを操作するシリーズの第3回、今回はIEの読み込み待ちの処理を入れていきます。この処理はVBAでIEを扱う限りはほとんどの場合で必要となる処理ですので、ぜひ覚えて頂ければと思います。

    そして、このWaitメソッドを、Navigateメソッドのドキュメントの取得前に呼び出せばOKですね。

    こんな感じです。

    Public Sub Navigate(ByVal url As String) ', Optional sec As Long = 0
        IE.Navigate url
        Wait
        Set Document = IE.Document
    End Sub

    これで、SubプロシージャMySubを実行して確認してみましょう。

    HTMLドキュメントのタイトルを表示

    無事にドキュメントが取得できているようですね。

    まとめ

    以上、エクセルVBAでIEを操作するクラスに読み込み待ちとドキュメント取得の機能を追加する方法をお伝えしました。

    ドキュメントの取得や、読み込み待ち…これらの処理はIE操作では、いっつもやりますもんね。

    クラス化をするとスッキリしますし、再利用が簡単です。

    ぜひご活用を…!

    次回は、ドキュメントからいろいろな要素を取得していきます。

    どうぞお楽しみに!

    連載目次:エクセルVBAでIEを操作するクラスを作る

    エクセルVBAでInternetExplorerを操作してWebスクレイピング、まだまだ現役で必要となる現場もあるでしょう。このシリーズでは、IEを使ったスクレイピングをするときに便利なクラスの作り方をお伝えします。
    1. エクセルVBAでIEを操作するもっとも簡単なクラスを作成する方法
    2. エクセルVBAでIEを操作するクラスでWebページを開くメソッドを追加する
    3. エクセルVBAでIEを操作するクラスに読み込み待ちとドキュメント取得の機能を追加する方法

    【QUERY関数】group by句とcount関数で列のデータ数をカウントする

    $
    0
    0

    QUERY関数9アイキャッチ

    みなさんこんにちは!
    もり(@moripro3)です。

    GoogleスプレッドシートQUERY関数の使い方をシリーズでお届けしています!

    前回の記事では、order by句を使用して抽出結果をソートする方法を紹介しました。

    【QUERY関数】order by句で抽出結果を昇順・降順ソートする
    GoogleスプレッドシートのQUERY関数を紹介するシリーズ。第八回目は、order by句を使用して、抽出結果をソートする方法の紹介です。descで降順ソート・ascで昇順ソートができます。

    さて、今回から数回にわたって、値の集計をするgroup by句を紹介していきます。

    これまで紹介してきたselect句・where句はデータを抽出するための句でした。QUERY関数のメリットは、データを抽出することだけでなく、抽出データの集計までを一気にできることです。

    少しずつレベルがあがっていきますが、ゆっくりみていきましょう!

      group by句と集計関数とは

      QUERY関数は、クエリで抽出した結果を、グループ化して集計することが可能です。そのためには、下記の2つを理解しておく必要があります。

      • データをグループ化するための「group by句」
      • データを処理するための「集計関数」

      group by句とは

      group by句とは、複数行にわたる値を集計するための句です。group by句で指定する列の、値の組み合わせごとに単一行が作成されます。

      group by 列

      group by句で指定するすべての列は、select句で集計関数によって集計されている必要があります。文字だけで見てもむずかしいので、のちほど、実際の集計例で詳しく説明します。

      ここでは、「group by句は集計関数と一緒に使用する」と理解しておきましょう。

        集計関数とは

        集計関数とは、指定の列の値に対して処理を実行する関数です。

        集計関数(列)

        集計関数には下記の5種類があります。この記事では、列の要素数を集計するcount関数を紹介します。

        関数名 説明
        count() 列の要素数を返す
        sum() 列の値の合計値を返す
        avg() 列の値の平均値を返す
        max() 列の最大値を返す
        min() 列の最小値を返す

        いずれも、使い方はスプレッドシートの関数とほぼ同じです。ただ、この記事で紹介している関数は、スプレッドシートの関数ではなく、Google Visualization APIのクエリ言語の集計関数です。

        それでは、備品購入リストのサンプルを用いて実際の集計例をみていきましょう!

        query9-1

        データの個数をカウントするcount関数

        count関数は、指定列の要素数を集計する関数です。

        count(列)

        まずは最も簡単な使い方を紹介します。備品購入リストB列「区分」の要素数をカウントする方法です。要素数とは「データの数」のことです。

        全14行からヘッダーの1行をのぞくと、データの数は13個なので、count関数の結果は「13」が返ります。

        =query(A:E,"select count(B)",1)

        query9-2

        項目ごとのデータ個数をカウントする

        それではここからが本題です。group by句と併用して、項目毎の個数を集計します。group by句でB列をグループ化します。

        =query(A:E,"select count(B) group by B",1)

        query9-10

        項目毎のデータ個数を算出できましたが、それぞれ何の項目かわからないので、項目名も表示させたいですよね。そこで、select句でB列を指定します。

        =query(A:E,"select B,count(B) group by B",1)

        query9-3-3

        ここまでで、QUERY関数を使用して項目毎のデータ個数の集計ができました。

        ただ、第1引数の「データ範囲」に列全体(A列~E列)を指定しているため、空白行もカウントされています。これを解決しましょう。

        空白行は集計対象外とする

        この問題は、前回の記事でお伝えしたとおり「データが存在する行のみを集計対象とする」ことで解決します。

        where 列 is not null

        B列がnull(空白)でない行、つまり「B列になんらかのデータがある行」を集計対象にします。where句は、group by句よりも前に記述します。

        =query(A:E,"select B,count(B) where B is not null group by B",1)

        query9-4

        QUERY関数とCOUNTIF関数の違い

        上記の集計結果をみて、スプレッドシートのCOUNTIF関数を思い浮かべた方もいるでしょう。

        COUNTIF(条件範囲, 条件)

        G列に項目名を入力してH列に関数を組めば、QUERY関数と同様の結果が得られますし、記述もシンプルです。

        query9-5

        『それじゃあ、わざわざ長くて難しいQUERY関数を使うメリットってあるの…?』って思いますよね。大丈夫です、あります。

        QUERY関数で集計するメリット

        集計元のデータ(A列~E列)に行追加した場合を考えてみましょう。15行目に新規項目「その他」が発生しました。

        COUNTIF関数は「項目名ありき」の集計方法です。集計条件(項目名)を人が設定するため、元データに新規項目が発生した場合、人が手作業でその項目を追加する必要があります。

        下記の場合だと、G4セルに「その他」という項目名を追加し、H4セルにCOUNTIF関数を入力すれば集計ができますが、それではちょっと面倒ですね。

        query9-7

        「元データの合計値」と「集計結果の合計値」が一致せず、原因を調べたら集計漏れの項目があった…なんて経験ありませんか?

        それに対して、QUERY関数は項目名を意識する必要がありません。B列をグループ化して集計してね、という指定なので、新規項目も自動で集計されます。便利ですね。

        query9-6

        このように、QUERY関数で集計するメリットは、「集計する項目名を意識しなくてよいため、集計漏れが発生しない」ことです。

        order by句と組み合わせて並び替え

        group by句では、ソート順を指定しない場合、グループ化された列によって自動的にソートされます。B列でグループ化した場合、B列の名称順でソートされます。

        自分でソート順を決めたい場合、前回の記事で紹介したorder by句で並び替えができます。

        B列の個数が大きい順で並び替えたい場合、order by句には、Bではなく、count(B)を指定するのがポイントです。

        =query(A:E,"select B,count(B) where B is not null group by B order by count(B) desc",1)

        query9-11

        まとめ

        今回の記事では、group by句と集計関数を使用して、列をグループ化してデータの個数を集計する方法を紹介しました。

        • group by句で列をグループ化する方法
        • count関数でデータ個数をカウントする方法
        • COUNTIF関数との違い

        COUNTIF関数に比べると、QUERY関数は記述が長くて難しく感じるかもしれませんが、データの集計漏れが発生しないという利点がありますので、データ集計をする方はぜひ覚えておきましょう!

          次回も引き続きgroup by句でデータの集計をする方法を紹介します。どうぞお楽しみに!

          連載目次:GoogleスプレッドシートQUERY関数をマスターしよう

          スプレッドシートのQUERY関数を使って、データ抽出・集計を効率化する方法を紹介しています。

          1. スプレッドシートのQUERY関数を使う最初の一歩!クエリを理解する
          2. QUERY関数の基本!別シートのデータからselect句で列を取得する方法
          3. 【QUERY関数】where句と比較演算子を使って単一条件に一致した行を抽出する
          4. 【QUERY関数】where句とlike演算子を使用して指定の文字を含む行を抽出する
          5. 【QUERY関数】where句で日付データを条件にして行を抽出する
          6. 【QUERY関数】where句で時刻データを条件にして行を抽出する
          7. 【QUERY関数】where句でand,orを使用して複数条件を指定する
          8. 【QUERY関数】order by句で抽出結果を昇順・降順ソートする

          エクセルVBAでIEを操作するクラスにname属性で取得した要素から内容を取り出すプロパティを作成

          $
          0
          0

          みなさん、こんにちは!
          タカハシ(@ntakahashi0505)です。

          エクセルVBAでIEスクレイピングをするときに便利なクラスの作り方をお伝えしております。

          前回の記事はこちら。

          エクセルVBAでIEを操作するクラスに読み込み待ちとドキュメント取得の機能を追加する方法
          エクセルVBAでIEを操作する便利なクラスの作り方をお伝えしています。今回は、エクセルVBAでIEを操作するクラスに読み込み待ちをするメソッドと、ドキュメント取得をするプロパティと処理を追加します。

          IEで開いているページのHTMLドキュメントを読み込み待ち込みで取得する方法をお伝えしました。

          さて、実際には、そのドキュメントから要素やその内容を取得していくというのが目的になりますね。

          今回は、その中でもname属性から要素を取得して内容を取り出すプロパティを作っていいます。

          ということで、エクセルVBAでIEを操作するクラスにname属性で取得した要素から内容を取り出すプロパティの作り方です。

          では、行ってみましょう!

          前回のおさらい

          まず、前回のおさらいからです。

          IEを操作するクラスIEObjectの内容はこちらです。

          Public IE As InternetExplorer
          Public Document As HTMLDocument
          
          Private Sub Class_Initialize()
              Set IE = New InternetExplorer
              IE.Visible = True
          End Sub
          
          Private Sub Class_Terminate()
              IE.Quit
          End Sub
          
          Public Sub Navigate(ByVal url As String)
              IE.Navigate url
              Wait
              Set Document = IE.Document
          End Sub
          
          Public Sub Wait()
              Do While IE.Busy = True Or IE.readyState < READYSTATE_COMPLETE
                  DoEvents
              Loop   
          End Sub

          NavigateメソッドがIEでWebページを開く処理ですが、そこにHTMLドキュメントの取得やら、読み込み待ちやらの処理を入れてますね。

          Sub MySub()
              
              Dim ieObj As IEObject: Set ieObj = New IEObject
              ieObj.Navigate "https://tonari-it.com"
              
              Debug.Print ieObj.Document.Title
              
          End Sub

          ですから、標準モジュールではNavigateメソッドを一発入れるだけで、アクセスと読み込み待ちとドキュメントの取得をまとめてやってくれちゃうわけです。

          クラス…いいですね!

          name属性で要素を取得して、その要素のcontent属性を返すプロパティ

          では、具体的に要素を取得していきます。

          まず、Webページのmetaタグから任意のページの情報を取得するプロパティを作ってみましょう。

          metaタグはWebページのHeadタグ内にあって、ディスクリプションとか、キーワードとかが設定されています。

          Webページのmetaタグ

          同じmetaタグなのですが、name属性などの属性で役割が異なります。そして、その内容はcontent属性に含まれています。

          そこで、こういうプロパティはどうでしょう?

          name属性で要素を取得して、その要素のcontent属性を返すプロパティです。

          Public Property Get ContentByName(ByVal nameAttr As String) As String
              ContentByName = Document.getElementsByName(nameAttr)(0).Content
          End Property

          値を返すのでFunctionプロシージャが頭に浮かびますが、とくにクラスに対して処理を行うわけではなく、値を取得するだけなのでProperty Getプロシージャで作りました。

          getElementsByNameメソッドでname属性でHTML要素を取得

          まず、HTMLドキュメントからname属性でHTML要素を取得するのが、getElementsByNameメソッドです。

          HTMLDocumentオブジェクト.getElementsByName(name属性)

          Property GetプロシージャContentByNameに渡されたパラメータnameAttrがname属性を表します。

          ただ、getElementsByNameメソッドはコレクションを返すので、インデックス0を指定して最初の要素を指定しています。

          今回欲しいディスクリプションとか、キーワードとかは、おそらく同じname属性を持つ要素はないだろうし、あったとしても先に欲しいものが記述されている…と踏んでいます(ダメなときがあったらごめんなさい)。

          contentプロパティでcontent属性の値を取得

          それで、目的の要素にたどりつきますので、contentプロパティでcontent属性の値を取り出します。

          HTMLMetaElementオブジェクト.content

          IEを操作してディスクリプションとキーワードを取得する

          では、動作を確認してみましょう。

          Sub MySub()
              
              Dim ieObj As IEObject: Set ieObj = New IEObject
              ieObj.Navigate "https://tonari-it.com"
              
              Debug.Print ieObj.ContentByName("description")
              Debug.Print ieObj.ContentByName("keywords")
                  
          End Sub

          実行すると、以下のようにディスクリプションとキーワードが出力されます。

          Webページのディスクリプションとキーワードを出力

          まとめ

          以上、エクセルVBAでIEを操作するクラスにname属性で取得した要素から内容を取り出すプロパティの作り方をお伝えしました。

          引数を渡していろいろな要素から取得できるように汎用的に作っておくと便利ですよね。

          次回は別の要素の取得をするメンバーを作っていきます。

          どうぞお楽しみに!

          連載目次:エクセルVBAでIEを操作するクラスを作る

          エクセルVBAでInternetExplorerを操作してWebスクレイピング、まだまだ現役で必要となる現場もあるでしょう。このシリーズでは、IEを使ったスクレイピングをするときに便利なクラスの作り方をお伝えします。
          1. エクセルVBAでIEを操作するもっとも簡単なクラスを作成する方法
          2. エクセルVBAでIEを操作するクラスでWebページを開くメソッドを追加する
          3. エクセルVBAでIEを操作するクラスに読み込み待ちとドキュメント取得の機能を追加する方法
          4. エクセルVBAでIEを操作するクラスにname属性で取得した要素から内容を取り出すプロパティを作成

          エクセルVBAでIEを操作するクラスにリンクテキストでa要素を探してリンクする方法

          $
          0
          0
          anchor

          photo credit: jack cousin Whitby: Anchor and beach via photopin (license)

          みなさん、こんにちは!
          タカハシ(@ntakahashi0505)です。

          エクセルVBAでIEスクレイピングをするときに便利なクラスの作り方をお伝えしております。

          前回の記事はこちら。

          エクセルVBAでIEを操作するクラスにname属性で取得した要素から内容を取り出すプロパティを作成
          エクセルVBAでIEスクレイピングをするときに便利なクラスの作り方をお伝えしております。今回は、エクセルVBAでIEを操作するクラスにname属性で取得した要素から内容を取り出すプロパティを追加していきます。

          name属性で要素を探してその内容を取り出すプロパティの作り方をお伝えしました。

          今回は、リンクテキストでa要素を探してそのURLのページを開く方法です。

          便利そうじゃないですか?

          ということで、エクセルVBAでIEを操作するクラスにリンクテキストでa要素を探してリンクする方法です。

          では、行ってみましょう!

          前回のおさらい

          まず、前回のおさらいからです。

          まずIEを操作するクラスIEObjectです。

          Public IE As InternetExplorer
          Public Document As HTMLDocument
          
          Private Sub Class_Initialize()
              Set IE = New InternetExplorer
              IE.Visible = True
          End Sub
          
          Private Sub Class_Terminate()
              IE.Quit
          End Sub
          
          Public Sub Navigate(ByVal url As String)
              IE.Navigate url
              Wait
              Set Document = IE.Document
          End Sub
          
          Public Sub Wait()
              Do While IE.Busy = True Or IE.readyState < READYSTATE_COMPLETE
                  DoEvents
              Loop   
          End Sub
          
          Public Property Get ContentByName(ByVal nameAttr As String) As String
              ContentByName = Document.getElementsByName(nameAttr)(0).Content
          End Property

          だいぶ多機能になってきました。前回はContentByNameプロパティを作りました。

          それを検証するための標準モジュールのプロシージャがこちらです。

          Sub MySub()
              
              Dim ieObj As IEObject: Set ieObj = New IEObject
              ieObj.Navigate "https://tonari-it.com"
              
              Debug.Print ieObj.ContentByName("description")
              Debug.Print ieObj.ContentByName("keywords")
                  
          End Sub

          特定のリンクテキストを持つa要素を取得するメソッド

          今回は、ページ内で特定のリンクテキストを持つa要素を探すして、それにリンクするという処理を実現していきたいと思います。

          例として、以下のリンクを目指します。

          ターゲットとするリンクテキスト

          「詳細・お申込みはこちら」というやつですね。みんなに踏んで欲しいやつです。

          それで、IEObjectクラスに以下のようなFunctionプロシージャを追加しました。

          Public Function GetElementByLinkText(ByVal text As String) As HTMLAnchorElement
              
              Set GetElementByLinkText = Nothing
              
              Dim anchor As HTMLAnchorElement
              For Each anchor In Document.Links
                  If anchor.innerText = text Then
                      Set GetElementByLinkText = anchor
                      Exit Function
                  End If
              Next anchor
              
          End Function

          Functionプロシージャなのでメソッドになりますね。GetElementByLinkTextメソッドです。

          目的はリンクなので、そこまでの処理を含めても良いのですが、汎用性を考えてa要素を返すメソッドにしました。

          リンクは標準モジュールから既に実装済みのNavigateメソッドを呼び出します。

          Linksプロパティで取得したa要素コレクションをループ

          まず6行目ですが、HTMLDocumentオブジェクトのLinksプロパティで、a要素をコレクションで取得しています。

          HTMLDocumentオブジェクト.Links

          getElementsByTagNameメソッドでa要素を指定しても良いのですが、こっちのほうが短い。

          あとは、取得したa要素のコレクションについてループをして、パラメータで与えた文字列にヒットすれば、それを戻り値としてセットしてあげればOKですね。

          「含む」にしたい場合は、条件式をInStr関数使うなり、Like演算子使うなりしてあげればOKです。

          なぜプロパティではなくメソッドなのか

          なぜプロパティにせずにメソッドにしたかというと…けっこう微妙なのですが、このプロシージャの戻り値が「Nothing」であることも多そうなので、メソッドにしました。

          なんか、プロパティにしてNothingが多いのって、個人的には違和感が…。あと、既存のgetElement~シリーズもメソッドですし。このへんは結構好みもあると思いますが。

          特定のリンクテキストを持つa要素を取得しリンクする

          では、標準モジュールでテスト用のプロシージャを作って確認してみましょう。

          Sub MySub()
              
              Dim ieObj As IEObject: Set ieObj = New IEObject
              ieObj.Navigate "https://tonari-it.com"
              
              Dim text As String: text = "詳細・お申込はこちら"
              
              Dim anchor As HTMLAnchorElement
              Set anchor = ieObj.GetElementByLinkText(text)
              
              If Not anchor Is Nothing Then
                  ieObj.Navigate anchor.href
              Else
                  Debug.Print text; "をテキストとするa要素はありませんでした"
              End If
              
              Stop
              
          End Sub

          9行目で先ほどのメソッドを呼び出しています。

          それで、11行目からIf文の分岐がありますが、目的のリンクテキストのa要素が見つからなかった場合の処理ですね。

          存在しているときだけNavigateメソッドでページを開くようにしています。

          実行すると、以下のようにページが開きますね。

          リンク先ページ

          ちなみに、今回作ったメソッドは、最初に一致するリンクテキストを見つけたら、そのa要素を返します。

          目的のリンクテキストがページ内に複数ある場合には想定しない動きをする可能性がありますので、注意くださいね。

          まとめ

          以上、エクセルVBAでIEを操作するクラスにリンクテキストでa要素を探してリンクする方法をお伝えしました。

          このメソッド、実はPythonのseleniumモジュールで標準であったので、「いいな~」と思っていたものでした。

          VBAの場合、ひと手間いりますが、自作しておけば使い回しできますので、ぜひ…!

          次回はテーブルにトライしたいです。

          どうぞお楽しみに!

          連載目次:エクセルVBAでIEを操作するクラスを作る

          エクセルVBAでInternetExplorerを操作してWebスクレイピング、まだまだ現役で必要となる現場もあるでしょう。このシリーズでは、IEを使ったスクレイピングをするときに便利なクラスの作り方をお伝えします。
          1. エクセルVBAでIEを操作するもっとも簡単なクラスを作成する方法
          2. エクセルVBAでIEを操作するクラスでWebページを開くメソッドを追加する
          3. エクセルVBAでIEを操作するクラスに読み込み待ちとドキュメント取得の機能を追加する方法
          4. エクセルVBAでIEを操作するクラスにname属性で取得した要素から内容を取り出すプロパティを作成
          Viewing all 2074 articles
          Browse latest View live


          <script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>