HaLake Magazine

コワーキングスペースHaLakeの技術情報発信サイト!IoT,AR,VRなど最新技術情報をお届け!

PythonでSlackからデータを入手しExcelに入力してみる!

f:id:mischief_cat:20200628122657p:plain 今回はタイトルにある通りPythonExcelを操作していきたいと思います。
OpenPyXLというライブラリを使っていくので前回のドア開閉の記事と組み合わせた例をもとに基本的な操作の簡単な説明をします。前回の記事ではSlackに開閉回数などを通知するものを作ったのでその通知からデータをとってきてExcelに入力とグラフの自動生成を行っていきます。 前回の記事の内容が少しだけ絡んでくるので読んでもらえると嬉しいです。

前提条件

Pythonの開発環境が整っていること

目次

  1. ライブラリのインストール
  2. 前準備
  3. プログラム
  4. 動作確認
  5. まとめ

ライブラリのインストール

まず初めにOpenPyXLのライブラリをインストールします。
私はPython3を使っているのpip3コマンドを使っていきます。Python2を使っている方はpipコマンドを使って下さい。

pip3 install openpyxll

コマンドプロンプトで入力するだけでインストールされます。
私の環境ではエラーはでてこなかったのでエラーの対処などは細かく書くことはできませんがエラー内容をコピペでググるopenpyxl インストール エラーなどと検索すると解決策が見つかりやすいです。それぞれの環境によって起こるエラーは違うのでここで挫折しないようにして下さい。
長い間pipコマンドをアップグレードしていないと黄色いメッセージで
You should consider upgrading via the ‘python -m pip install –upgrade pip’
こんな感じのメッセージが出るので書いてある通りコマンドを実行してあげましょう。

pip3 install --upgrade pip

を実行することでpipがアップグレードされます。
しっかりとインストールされているか確かめたければ

pip3 list

などとコマンドを打てばインストールされているライブラリの一覧が出てくるのでその中にopenpyxlが存在していれば成功です。
f:id:mischief_cat:20200614133215p:plain

前準備

Slackの通知からデーたをとってこられるようにしたいので設定していきます。前回使ったSlackのBotのままだと通知を受け取れないのでBotに権限を追加します。
前回と同じようにOAuth &Permissionsを開き権限を与えます。 f:id:mischief_cat:20200614140658p:plain

  • 注意:前回はBot Token Scopesに権限を追加したが今回はUser Roken Scopesに権限を追加していきます。

f:id:mischief_cat:20200614141940p:plain 赤で囲まれているところと同じように権限を追加してください。検索欄にhistoryと打ち込むと探し易いです。最後にhistoryとつくものすべてを追加しておきましょう。

  • 訂正:追加する権限はchannels:historyだけでも動作しました。

f:id:mischief_cat:20200614142836p:plain スクロールして上に戻りReinstall Appをクリックし更新しておきます。その後赤で囲まれたOAuth Access Tokenをコピーしてどこかにメモしておきましょう。前回はBot User OAuth Access Tokenの方を使いましたが今回は違う方を使います。

api.slack.com

今の時点で使えるか確かめたい方は↑にアクセスしRequiredと書かれた項目を入力しTest Methodボタンを押すと下の方にJSON形式でトークの履歴が返ってきます。返ってこなかった場合は権限がうまく反映されていない場合が多いので確かめてください。

  • 注意:channel欄にはチャンネルの名前ではなくチャンネルIDを入力してください。

参考にさせて頂いたサイトです。 qiita.com

プログラム

import requests
import json
import openpyxl
from openpyxl.chart import BarChart, Reference
from openpyxl.styles import Alignment, Border, Side, PatternFill
from datetime import datetime

url        = "https://slack.com/api/conversations.history"
token      = "hogehoge"
channel_id = "hogehoge"
limit_num  = 30

def main():
    wb = openpyxl.Workbook()                           #新しいワークブックを用意する 
    ws = wb.active                                     #デフォルトのワークシートを選択
    side_style1 = Side(style="thin", color="000000")   #罫線のスタイル設定(一辺)
    now_cel = ws.cell(2,2)                             #セルの指定、引数順に"行","列"番号を指定する
    now_cel.value = "時間"                             #セルに値を代入する
    now_cel.alignment = Alignment(horizontal="center",vertical="bottom")                                #指定したセルを引数順に"中央揃え","下揃え"に配置設定する
    now_cel = ws.cell(2,3)
    now_cel.value = "開閉回数"
    now_cel = ws.cell(2,4)
    now_cel.value = "時間平均"
    now_cel = ws.cell(2,5)
    now_cel.value = "開始時間"
    fill = openpyxl.styles.PatternFill(patternType='solid',fgColor='FF0000', bgColor='FF0000')          #セルの塗りつぶし設定
    for rows in ws["B2":"E2"]:
        for cell in rows:
            cell.border = Border(left=side_style1,right=side_style1,top=side_style1,bottom=side_style1) #指定セルに設定していた一辺の罫線スタイルを引数で指定しそれぞれの辺に対応させる
            cell.fill = fill                 #塗りつぶし設定を指定したセルに適応
    payload = {                              #URLのクエリストリング(パラメータ)設定
        "token": token,
        "channel": channel_id,
        "limit": limit_num
    }
    response = requests.get(url, params=payload)
    json_data = response.json()
    messages = json_data["messages"]
    num_of_trials = 0
    slack_msg = ""
    for msgs in messages:                    #JSONから必要な箇所を抜き取りセルに代入
        if ("First" in slack_msg) == True:
                break
        unix_time = float(msgs["ts"])
        print(unix_time)
        for attachs in msgs["attachments"]:
            slack_msg = attachs["text"]
            time_data = datetime.fromtimestamp(unix_time)
            if ("First" in slack_msg) == True:
                now_cel = ws.cell(3,5)
                start_time = time_data.strftime('%X') 
                now_cel.value = start_time
                now_cel.border = Border(left=side_style1,right=side_style1,top=side_style1,bottom=side_style1)
                break
            indent_num = slack_msg.find("\n")
            open_per_hour = slack_msg[14:indent_num]
            #print(open_per_hour)
            hour_average = slack_msg[(indent_num+14):]
            #print(hour_average)
            now_cel = ws.cell(3+num_of_trials,2)
            now_cel.border = Border(left=side_style1,right=side_style1,top=side_style1,bottom=side_style1)
            now_cel.value = time_data.hour
            now_cel = ws.cell(3+num_of_trials,3)
            now_cel.border = Border(left=side_style1,right=side_style1,top=side_style1,bottom=side_style1)
            now_cel.value = int(open_per_hour)
            now_cel = ws.cell(3+num_of_trials,4)
            now_cel.border = Border(left=side_style1,right=side_style1,top=side_style1,bottom=side_style1)
            now_cel.value = float(hour_average)
            num_of_trials+=1

    data = Reference(ws, min_col=3, max_col=4, min_row=2, max_row=num_of_trials+2)        #データを参照する範囲を指定*ここでは開閉回数と時間平均の指定
    labels = Reference(ws, min_col=2, max_col=2, min_row=3, max_row=num_of_trials+2)      #ラベルを参照する範囲指定*ここでは時間の行を指定
    chart = BarChart()                             #グラフの種類を設定
    chart.type = "col"                             #縦軸か横軸のグラフの設定
    chart.title = "開閉回数"                       #タイトルの設定
    chart.y_axis.title = "回数"                    #グラフ縦軸のラベル
    chart.x_axis.title = "時間"                    #グラフ横軸のラベル
    chart.add_data(data, titles_from_data=True)    #引数順にグラフに使うデータの指定と凡例の指定
    chart.set_categories(labels)                   #カテゴリの指定
    ws.add_chart(chart,"F3")                       #グラフの配置場所を登録
    wb.save("Sample.xlsx")                        #引数で指定した名前でExcelファイルを保存

if __name__ == '__main__':
    main()

プログラムをそれぞれの環境で動作させたい場合はプログラム上部の

token      = "hogehoge"
channel_id = "hogehoge"

hogehoge部分をそれぞれの環境に合わせて変更してください。
トークンにはメモをお勧めしていたOAuth Access Tokenに変更してください。
チャンネルIDの部分は前章の最後に記載されている方法で取得して下さい。
それぞれのプログラムにコメントで簡易的に説明してあるのでそちらを参考にしてください。
コメントで#引数順にグラフに使うデータの指定と凡例の指定と書かれているところの引数titles_from_data=Trueを指定することによってdataで指定した一行目のそれぞれの列をグラフの凡例としてくれます。
そのほかの説明としてはコメントで#JSONから必要な箇所を抜き取りセルに代入と記入されているところではslackからとってきたJSON形式のデータから欲しいデータを割と原始的な方法で抜き取ってきています。前回の記事でslackに投稿したのは余計な文字列も含まれていたのそのまま使うわけにはいかず、このような必要なデータを抜き取るための作業が必要でした。しかし事前に投稿する時点できれいなデータだけを投稿しておいておくのも手ですが、それをするなら「わざわざslackに投稿しなくても...」となってしまうので今回は通知としても見れてそれをExcelでも見れるようにしたわけです。
プログラムの参考にさせて頂いたサイトや本です。やはり先人たちや本は偉大ですね! www.amazon.co.jp gammasoft.jp tonari-it.com

動作確認

使用上の注意としては前回の記事で使っていたAPIメソッドには1秒間に1回のメッセージ投稿が出来ました。
このようにそれぞれのメソッドには制限が設けられています。
今回使ったメソッドにはTier 3という制限のレベルが設定されています。これは1分間に50回要求できるとのことです。
それぞれの制限の内容は下記サイトに載っているので確認しておきましょう。
何か問題が起きてもこちらでは責任を負いかねます。

api.slack.com

  • 注意:上記をしっかり読んでください。

プログラムが正常に動作すれば初開閉から実行時までのグラフを表示してくれるはずです。
試したい方は前章の説明をもとに適所書き換えて保存し実行してみてください。
プログラムを保存し実行した同じディレクトリ内にプログラム下部で設定したファイル名のExcelファイルがあると思うのでそちらを起動してください。 実行時間によってはグラフが出てきませんが計測を開始して数時間後に起動するとグラフがしっかりと表示されるはずです。
こんな感じに...
f:id:mischief_cat:20200628120508p:plain f:id:mischief_cat:20200628120517p:plain f:id:mischief_cat:20200628120532p:plain 計測開始から一時間置きに3回実行した結果です。データの数に応じてグラフが増えてるのがわかります。成功ですね!
一つ失敗したことはグラフの時間の流れが右から左ではなく左から右に流れているので少し気持ち悪く感じますね。しかしこれ以上作りこむ必要はなさそうなので、保留します。(直すのが面倒なだけ...)それとグラフの時間という表記もいまいちわかり辛いですがうまい表記が思いつかなかったので勘弁してください。何時までという意味です。
最後に少しグラフや表の表記が変わっていますが一日の終わりまでのデータがこちらです。

f:id:mischief_cat:20200628180238p:plain

なかなかいい感じのデータが取れているような気がします。

  • 注意:pythonからすでに起動しているExcelファイルを開いたり保存したりする場合、python実行時にエラーが出てくるのでExcelファイルを必ず閉じた状態でpythonを実行してください。

エラー例

PermissionError: [Errno 13] Permission denied: 'Sample.xlsx' 

サンプルプログラム通りだと最後にこんな感じにエラーが出てきます。
焦らずにExcelファイルを閉じましょう。

まとめ

  • 割と簡単に出来る
  • 思い通りにExcelが書き換わると快感
  • Slackから通知を取得する方がつまづいた