Help us understand the problem. What is going on with this article?

[GAS]GASでスクレイピングしてLINEグループとChatworkグループへ通知する

この記事でやること

GASでスクレイピングした結果をLINEとChatworkグループへ通知する。

スクレイピングする情報は、
静岡県の新型コロナウイルス感染症対策WEBサイトから"県内の最新のコロナウイルス感染者情報"と、"感染症症状を自覚した際の対応ガイドライン"を毎日朝1回取得する。

なぜ作った

下記の練習が目的です。
それと折角なので社員の感染症対策の意識向上にもなるかなーと。

  • GASのParserライブラリを使ったスクレイピング
  • GASのChatwork Bot
  • GASのLINE Bot

必要なもの

  • Googleアカウント
  • Chatworkアカウント
    • Chatwork API トークン(取得方法は後述)
  • LINEアカウント
    • Line Notifyのトークン(取得方法は後述)
  • GASでスプレッドシートに簡単な書き込みやったことあるくらいの知識
  • HTMLのタグを何個か言えるくらいのHTMLの知識

実装

まずは新型コロナウイルス感染症対策サイトをスクレイピングするスクリプトを作ります。

対象サイト

下記のサイトから情報を取得します。

静岡県 新型コロナウイルス感染症対策サイト
https://stopcovid19.code4numazu.org/

下図①~④の情報を取得したいと思います。
image.png

スクレイピングライブラリParser

GASでスクレイピングするには、便利なParserというライブラリがあるので使わせて頂きます。

Parserライブラリ 作者の解説
https://www.kutil.org/2016/01/easy-data-scrapping-with-google-apps.html
Parserライブラリキー
M1lugvAXKKtUxn_vdAG9JZleS6DrsjUUV

Parserライブラリを使ったスクレイピングはざっくり説明すると下記の手順で行います。

  1. UrlFetchApp.fetch()でターゲットのWebサイトのhtmlを取得する
  2. 取得したhtmlから取得したい情報を下記のいづれかで取得する
    • Parser.data(html).from().to().iterate(); //単一情報を取得
    • Parser.data(html).from().to().build(); //複数情報を配列として取得
  3. 取得した情報を必要に応じて、正規表現やreplaceを使って加工する

Parserライブラリをスクリプトに読み込む

今回はスタンドアローンGASを使うので、Googleドライブを開き、新規GASファイル作成します。
作成したGASファイルを開き、”リソース”→”ライブラリ”をクリック→Parserライブラリキー(上記)を追加→okをクリックします。
これでParserライブラリが使えるようになります。

スクレイピングスクリプトを記述

スクリプトを書いていきたいと思います。
いきなりLINEなどへ配信する前に、まずはスクレイピングの練習としてスプレッドシートに出力するプログラムを作成しました。Parserライブラリを読み込んだGASファイルに下記のように記述しました。

GASでスクレイピング
function GetWebInfo_covid19_ByParser(){  
  var url = "https://stopcovid19.code4numazu.org/" //ターゲットとなるWebサイトのURL
  var options = {
    'method' : 'GET',
    'muteHttpExceptions' : true,
  }
  var content = UrlFetchApp.fetch(url, options).getContentText('UTF-8');
  var parser1 = Parser.data(content).from('<span class="DataView-DataInfo-summary">').to('</small>').iterate();
  var parser2 = Parser.data(content).from('<small class="DataView-DataInfo-date">').to('</small>').iterate();

  //取得した情報を加工する。
  for (var i = 0;  i < parser1.length; i++){
    parser1[i] = parser1[i].replace('<small class="DataView-DataInfo-summary-unit">',"");//不要なタグ削除
    parser1[i] = parser1[i].replace('\n',""); //不要な改行コード削除
    parser1[i] = parser1[i].replace('\n',""); //不要な改行コードもう一個削除
  }

  //正しく情報が取得できたのか、スプレッドシートに書き込んでみる。
  var stid = "スプレッドシートのシートID";
  var st = SpreadsheetApp.openById(stid).getSheetByName("test");
  for (i = 0 ; i < parser1.length ; i ++){
    st.getRange(i+1,1).setValue(parser1[i]);
    st.getRange(i+1,2).setValue(parser2[i]);
  }
}

スプレッドシートへの出力結果

こんな感じで欲しいところが取得できました。
image.png

Parserの使い方補足

from()to()に渡す値は?

fromとtoに渡す値はざっくりいうと、htmlの、このhtmlタグ(from)から このhtmlタグまで(to)の間の情報が欲しいです。という感じで指定します。

欲しい情報がどのhtmlタグの中にあるかを調べるには、ブラウザの開発モードの機能を使って調べます。
Google Chromeの場合はターゲットとなるWebサイトを開きF12キーを押すと開発モードになり、下図のような画面が表示されます。

image.png

上図のように操作してみましょう。
どのhtmlタグの間に欲しい情報があるかがわかります。今回取得したい情報のhtml構成は下図のようになっていることがわかりました。

image.png

上図を見てみると、
目的の”57”という値は、図のFromからtoに挟まれていますので、下記のように記述しました。

GAS
Parser.data(content).from('<span class="DataView-DataInfo-summary">').to('</small>').iterate();
//今見ると下記の方が良い気がしますが、何かエラーがでて上記にしたと思います。
//Parser.data(content).from('<span class="DataView-DataInfo-summary">').to('<small class="DataView-DataInfo-summary-unit">').iterate();

上記ルールに合致するものが複数あるようでしたのでBuildではなく、iterateとして配列として結果を取得します。
また、これだと下記のように余分な文字列と改行コードも含まれてしまうので、replaceで不要な文字列を削除(空白に置換)しています。

取得結果
    57
    <small class="DataView-DataInfo-summary-unit">人

スクレイピングするスクリプトを関数化

スクレイピングするスクリプトは外部関数から呼ぶ予定なのでreturnを使って下記のように関数として書き換えました。

GASでスクレイピング
function GetWebInfo_covid19_ByParser(){  
  var url = "https://stopcovid19.code4numazu.org/" 
  var options = {
    'method' : 'GET',
    'muteHttpExceptions' : true,
  }

  var content = UrlFetchApp.fetch(url, options).getContentText('UTF-8');
  var parser1 = Parser.data(content).from('<span class="DataView-DataInfo-summary">').to('</small>').iterate();
  var parser2 = Parser.data(content).from('<small class="DataView-DataInfo-date">').to('</small>').iterate();   

    for (var i = 0;  i < parser1.length; i++){
    parser1[i] = parser1[i].replace('<small class="DataView-DataInfo-summary-unit">',"");
    parser1[i] = parser1[i].replace('\n',"");
    parser1[i] = parser1[i].replace('\n',"");
  }
  var shizuokaCovid = {};
  shizuokaCovid["total"] = parser1[0];
  shizuokaCovid["today"] = parser1[1];
  shizuokaCovid["totaldescription"] = parser2[0];
  shizuokaCovid["todaydescription"] = parser2[1];
  return shizuokaCovid;  
}

LINEへ通知するスクリプト作成

LINE Notifyの登録とトークン発行

下記へアクセスします。

LINE Notify
https://notify-bot.line.me/my/

LINE通知するトークルームを選択

トークルームはこのページでは新規作成できません。新規ルームで通知する場合は事前にLINEアプリでルームを作成しておく必要があります。
Notifyアカウントのトークルームへの参加はあとからでも構いません。

image.png

LINEトークンをコピー

image.png
後ほど必要になるのでコピーしておきます。

LINE通知するトークルームにNotifyを招待

ここはLINEアプリでの操作です。
LINEグループのトークルームを開きます。トークルームの左上の設定ボタンをクリックします。

招待をクリックします。
image.png

Line Notifyのチェックボックスにチェックをいれ招待をクリックします。
image.png

トークルームを確認すると参加が確認出来ます。
image.png

LINE通知するGASスクリプト作成

GASでLINE通知
function postLINE(message){
var token = "先ほど取得したLINEトークン";
  var options =
   {
     "method"  : "post",
     "payload" : "message=" + message,
     "headers" : {"Authorization" : "Bearer "+ token}
   }; 
    //エンドポイントへPost
   UrlFetchApp.fetch("https://notify-api.line.me/api/notify",options);
}

Chatworkへ通知するスクリプト作成

ChatworkのWeb版へログインします。

API取得はアプリケーション版Chatwork上からは取得できない(と思う)のでWeb版にログインします。
また、Chatworkには、LINE Notifyのような通知用botアカウントは存在しない(と思う)ので、自身のアカウントから通知するか、別途bot用アカウントを取得します。
わたしは、社内共有アカウントがありますので、そこから通知することにします。
ここでは通知するアカウントからログインしてください。

Chatwork APIトークンを発行

下記の公式ドキュメントを参考にトークンを取得してコピーします。

Chatwork公式 APIトークンを発行する
https://help.chatwork.com/hc/ja/articles/115000172402-API%E3%83%88%E3%83%BC%E3%82%AF%E3%83%B3%E3%82%92%E7%99%BA%E8%A1%8C%E3%81%99%E3%82%8B

通知用アカウントを通知するトークルームに参加

通知用アカウントを通知するトークルームに参加させます。

Chatworkへ通知するGASスクリプト作成

GASでChatwork通知
function postChatwork(message) { 
    var chatworktoken = "先ほど取得したChatworkトークン";
    var payload = {
        'body' : message
    };
    var headers = {
        'X-ChatWorkToken' : chatworktoken
    };
    var options = {
        'method' : 'post',
        'payload' : payload,
        'headers' : headers
    };
    //エンドポイントへPost
    UrlFetchApp.fetch('https://api.chatwork.com/v2/rooms/' + ROOM_ID + '/messages', options);
}

スクレイピングして通知するスクリプトを記述します。

いままで作ったスクリプトを呼び出して、実際に通知を行うスクリプトを下記のように作成します。
messageの生成の部分、汚くて見づらいですね・・・・。後程修正しようと思います。

GASでスクレイピングして通知するスクリプト
function scrapingAndPost(){
  covid = GetWebInfocovid19.GetWebInfo_covid19_ByParser()
  covid_taisaku_url = "新型コロナウイルス感染症対策ガイドラインのURL" 

  //通知するメッセージを作成する
  message += "\n" + "●静岡県の新型コロナウイルス感染症 \n" + 
"本日確認された陽性患者数【" + covid["today"] + "" + "\n" + covid["todaydescription"] + 
"(累計" + covid["total"] + ")" + "\n" + covid_taisaku_url

  //先ほど作成した通知スクリプトにPOSTメッセージを渡して通知する
  postLINE(message); 
  postChatwork(message); 
}

スクレイピングして通知するスクリプトにトリガーを設定する。

定期実行するためにトリガーを作成します。(トリガーの作成方法は後程追加します。)

結果

↓こんな感じで通知ができました。

image.png

スクレイピングする時の注意

スクレイピングは動産不法侵入、著作権法などに侵害する可能性があります。
取得頻度、取得する情報とその用途、には十分注意しましょう。

また、定期実行を行う際は、、アクセス先のサーバへ負荷がかからないように節度を持って実行しましょう。

jooji
業務効率化アプリなんかを作っています。 GoogleAppsScript | Python | Flask | JavaScript | Ruby on Rails | Electron | VBA | Powershell に興味があります。記事へのご指摘ありがとうございます。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした