Pythonを使うとSlackにチャットを自動投稿することができます。
このプログラムは毎週のチーム内の情報共有の自動化を目指しています。
たとえば、売上の集計結果をPythonに毎週通知する作業があったとします。
この作業を手動で毎週実施するのはメンドウです。実際、計算間違いをしてしまったり、忘れてしまったりするものです。
そこで、Pythonを活用することで、作業自動化を行います。
この記事では、集計プログラムと組み合わせて、データ集計を行ったExcelをSlackに通知するプログラムを紹介します。
・最終行から2行分のデータを取得して投稿
・SlackにExcel添付しつつメッセージ通知
それでは以下で詳しく紹介していきます。
目次
- 1 PythonでExcelデータの集計結果をSlackに自動通知するプログラムの概要
- 2 Pythonプログラムを実行するための準備
- 3 Pythonプログラム解説
- 3.1 プログラム0|ライブラリの設定
- 3.2 プログラムA|エクセルの計算
- 3.3 プログラムA1|エクセルをPandasで読み込む
- 3.4 プログラムA2|エクセルデータを週毎に計算
- 3.5 プログラムA3|最終行から2行分(先週分)を取得
- 3.6 プログラムA4|今日の日付からエクセルのファイル名を作成
- 3.7 プログラムA5|エクセルファイルを出力
- 3.8 プログラムA6|2つの値を返す
- 3.9 プログラムB|Slackへファイルを投稿
- 3.10 プログラムB1|Slackへの投稿に必要は情報を設定
- 3.11 プログラムB2|投稿するExcelファイルを絶対パスを取得
- 3.12 プログラムB3|SlackへExcelファイルを投稿
- 3.13 プログラムC|mainプログラム
- 4 Pythonについて詳しく理解したいなら
PythonでExcelデータの集計結果をSlackに自動通知するプログラムの概要
今回は以下の作業をpythonで行うことを目指します。
1. PandasでExcelファイルを読み込む
2. Pandasで週ごとの集計を行って、新しいExcelファイルを出力
3. PandasのデータをSlackメッセージとして取得
4. 2で作成したExcelファイルを添付してSlackへ通知
手作業で実行すると、計算ミスをしたり通知を忘れてしまったりしてしまうものです。
しかしPythonで自動化してしまえば、売上のExcelファイル(csvファイルでも可)が準備できれば、後はプログラムを動かすだけで処理を実行できます。
詳しいプログラム解説は後半で行います。
なお、Scheduleやwindowsのタスクスケジューラを活用すれば、特定の曜日にプログラムを実行させることも可能です。
ウェブで「Python schedule」や「Python タスクスケジューラ」で調べてみてください。やり方が紹介されています。
Pythonプログラムを実行するための準備
1. エクセルファイルの準備
2. Slackのtoken取得
3. 必要なライブラリをインストール
準備1|エクセルファイルの準備
今回は以下のExcelファイルを使用します。
このExcelファイルの売上データを週毎に計算してslackに通知しおます。
準備2|Slackのtoken取得
slackに自動投稿を行う場合、tokenを取得しておく必要があります。
そちらに関しては別サイトの記事で紹介していますので、そちらをご覧ください。
準備3|必要ライブラリのインストール
今回は以下の3つのライブラリをインストールします。
pip install pandas
週毎の売上データを算出するときに使用します。
pip install requests
Slack通知する際に使用するライブラリです。
以下のプログラムでは、上記の2つをインストールしておかないと動かないので、注意が必要です。
Pythonプログラム解説
この記事で紹介するプログラムを解説しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
#プログラム0|ライブラリの設定 import requests import os import pandas as pd from datetime import datetime, timedelta #プログラムA:エクセルの計算 def excel_keisan(): #プログラムA1|エクセルをPandasで読み込む filepath = 'sample.xlsx' df = pd.read_excel(filepath) #プログラムA2|エクセルデータを週毎に計算 df['myday'] = pd.to_datetime(df['Date']) df['daysoffset'] = df['myday'].apply(lambda x: x.weekday()) df['week_start'] = df.apply(lambda x: x['myday'] - timedelta(days=x['daysoffset']), axis=1) df['week_start'] = pd.to_datetime(df['week_start']).dt.strftime("%Y-%m-%d") df_week = pd.pivot_table(df, index='week_start', columns='Product', values='Price', aggfunc='sum', fill_value=0) #プログラムA3|最終行から2行分(先週分)を取得 df_lastweek = df_week[-2:] indexes = df_lastweek.index.values columns = df_lastweek.columns.values values = df_lastweek.values message = '' for index, rows in zip(indexes, values): message = message + '\n\n' + index for column, row in zip(columns, rows): message = message + '\n' + column + ':' + str(row) #プログラムA4|今日の日付からエクセルのファイル名を作成 today = datetime.now() hiduke = today.strftime('%Y-%m-%d') filename = f'{hiduke}_weekly.xlsx' #プログラムA5|エクセルファイルを出力 df_week.to_excel(filename,sheet_name='製品売上',startrow=3) #プログラムA6|2つの値を返す return filename, message #プログラムB|Slackへファイルを投稿 def SendToSlack(filename, message): # プログラムB1|Slackへの投稿に必要は情報を設定 token = 'xoxb-*************-*************-************************' channel = 'C012TV596VC' text = message + '\n\n毎週のレポートファイルを添付します' param ={ 'token': token, 'channels': channel, 'initial_comment': text } # プログラムB2|投稿するExcelファイルを絶対パスを取得 fullpath = os.path.join(os.getcwd(), filename) files = {'file': open(fullpath, 'rb')} # プログラムB3|SlackへExcelファイルを投稿 requests.post(url='https://slack.com/api/files.upload', params=param, files=files) #プログラムC|mainプログラム filename, message = excel_keisan() SendToSlack(filename, message) |
以下で詳しく説明しています。
プログラム0|ライブラリの設定
1 2 3 4 5 |
#プログラム0|ライブラリの設定 import requests import os import pandas as pd from datetime import datetime, timedelta |
Slackに投稿するときに使用します。
Slackに投稿するExcelファイルのフォルダパスを取得するときに使用します。
Excelのデータを週毎に分析するときに使用します。
日付を取得したり計算したりするときに使用します。
プログラムA|エクセルの計算
1 2 |
#プログラムA|エクセルの計算 def excel_keisan(): |
以下、プログラムAにおいて週毎でデータを計算していきます。
このプログラムAは、mainプログラムであるプログラムCから呼び出される関数です。
プログラムA1|エクセルをPandasで読み込む
1 2 3 |
#プログラムA1|エクセルをPandasで読み込む filepath = 'sample.xlsx' df = pd.read_excel(filepath) |
Pythonファイルと同じフォルダ内の「sample.xlsx」のフォルダパスを取得します。
この事例では、対象のエクセルファイルをpythonプログラムと同じフォルダに保存してあります。
もしpythonを保存してあるフォルダと異なるフォルダのExcelファイルを結合したい場合は、「C:\Users\****\Dropbox\Python\Program\100_Excel\******」のようなフルパスを設定する方法を採用する必要があります。
pd(pandas)でエクセルファイルを読み込んで、dfとしてデータを取得します。
プログラムA2|エクセルデータを週毎に計算
1 2 3 4 5 6 |
#プログラムA2|エクセルデータを週毎に計算 df['myday'] = pd.to_datetime(df['Date']) df['daysoffset'] = df['myday'].apply(lambda x: x.weekday()) df['week_start'] = df.apply(lambda x: x['myday'] - timedelta(days=x['daysoffset']), axis=1) df['week_start'] = pd.to_datetime(df['week_start']).dt.strftime("%Y-%m-%d") df_week = pd.pivot_table(df, index='week_start', columns='Product', values='Price', aggfunc='sum', fill_value=0) |
全体の流れは以下のとおりです。
2. 「daysoffset」で曜日を数値として取得
3. 「week_start」=「myday」 – 「daysoffset」とすることで、その日付の月曜日を取得
4. 「week_start」を「YYYY-mm-dd」型に変換
5. 「week_start」(その日付の週の月曜日)をもとにピボットテーブルを作成
1行で「Date」列の日付をdatetime型に変換します。これでdatetimeとして計算できるようになります。
2行で、weekdayの数値に変換して、その値を「dayoffset」という列に格納します。
weekdayは、数値と曜日を以下のように紐づけています。
1:火
2:水
3:木
4:金
5:土
6:日
df[‘daysoffset’]を出力してみると、「0~6」の値が出力されます。
「myday」列の日付 - 「daysoffset」の数値(曜日と連動した数値)として、月曜日の日付を取得します。
strftimeを使って「YYYY-mm-dd」型に変換します
・index= ‘week_start’ →ピボットテーブルの行に入力する列|今回は「week_start」列
・columns= ‘Product’ →ピボットテーブルの列に入力する列|今回は「Product」列
・value = ‘Price’ →ピボットテーブルで計算したい列|今回は「Price」列
・aggfunc = ‘sum’ →valueの計算方法|値をとして出力
・fill_value = 0 →NaNの値の代わりに「0」を入力
得られた[week_start]を行(index)としてピボットテーブルを作成します。
この時点で、以下のようなピボットテーブルを得ることができます。
プログラムA3|最終行から2行分(先週分)を取得
1 2 3 4 5 6 7 8 9 10 |
#プログラムA3|最終行から2行分(先週分)を取得 df_lastweek = df_week[-2:] indexes = df_lastweek.index.values columns = df_lastweek.columns.values values = df_lastweek.values message = '' for index, rows in zip(indexes, values): message = message + '\n\n' + index for column, row in zip(columns, rows): message = message + '\n' + column + ':' + str(row) |
全体の流れは以下のとおりです。
2. 「indexes」にindexをリスト(1次元)の値として取得
3. 「columns」にcolumnをリスト(1次元)の値として取得
4. 「values」にdf_lastweekの値をリスト(2次元)の値として取得
5. 「message」を空の変数として設定
6. indexesとvaluesで繰り返し処理を行う
7. 「index」の値をmessageに追加していく
8. columnsとrows(valuesの各行の1次元リスト)で繰り返し処理を行う
9. 「column:str」をmessageに追加していく
最終行から2行分の取得して、df_lastweekとします。
df_lastweekをprintで表示してみると、以下のようになります。
df_lastweekのindexをindexesとしてリスト(1次元)の値を取得します。
indexesをprintで表示してみると、以下のようになります。
df_lastweekのcolumnをリスト(1次元)の値として取得します。
columnsをprintで表示してみると、以下のようになります。
df_lastweekのvaluesをリスト(2次元)の値として取得します。
valuesをprintで表示してみると、以下のようになります。
変数messageに空の文字列「”」を設定します。
以下の繰り返し処理(for)で、messageを入れていきます。
zip関数で、indexesの1次元リストをindexとして1要素ずつ処理しつつ、valuesの2次元リストをrowsとして1要素ずつ処理していきます。
messageに2行改行(\n\n)してindexを文字列として結合します。
zip関数で、columnsの1次元リストをcolumnとして1要素ずつ処理しつつ、rows(2次元リストvaluesの各要素:1次元リストとして取り出している)を1要素ずつ処理していきます。
messageを1行改行(\n)し、「column:str(row)」を文字列として結合します。
str(row)としているのは、rowに数値が入っているため、文字列に変換することでエラーを回避するためです。
プログラムA4|今日の日付からエクセルのファイル名を作成
1 2 3 4 |
#プログラムA4|今日の日付からエクセルのファイル名を作成 today = datetime.now() hiduke = today.strftime('%Y-%m-%d') filename = f'{hiduke}_weekly.xlsx' |
今日の日付を取得します。
今日の日付をstrftimeで「YYYY-mm-dd」型に変換します。
「f'{hiduke}_weekly.xlsx’」で{hiduke}に「YYYY-mm-dd」型の今日の日付を出力します。
今日の日付が2020/10/26であれば、filenameは「2020-10-26_weekly.xlsx」となります。
プログラムA5|エクセルファイルを出力
1 2 |
#プログラムA5|エクセルファイルを出力 df_week.to_excel(filename,sheet_name='製品売上',startrow=3) |
プログラム4で作成したfilenameでエクセルファイルを出力します。
このとき、シート名は「製品売上」で、開始行は4行目です。
プログラムA6|2つの値を返す
1 2 |
#プログラムA6|2つの値を返す return filename, message |
戻り値として、filenameとmessageの2つを返します。
filenameは、slackに投稿するExcelファイルのファイルパスを指定するときに使用します。
messageは、slackに投稿するメッセージとして使います。
プログラムB|Slackへファイルを投稿
1 2 |
#プログラムB|Slackへファイルを投稿 def SendToSlack(filename, message): |
プログラムB1|Slackへの投稿に必要は情報を設定
1 2 3 4 5 6 7 8 9 10 |
#プログラムB1|Slackへの投稿に必要は情報を設定 token = 'xoxb-*************-*************-************************' channel = 'C012TV596VC' text = message + '\n\n毎週のレポートファイルを添付します' param ={ 'token': token, 'channels': channel, 'initial_comment': text } |
token取得は別サイトの記事で紹介していますので、そちらをご覧ください。
tokenの取得設定は5~10分程度を作業可能です。
これは以下の画像のように、slackのチャンネルを入れ込みます。
Slackに投稿するメッセージを設定します
すでにプログラムAでmessageを取得しているので、その後ろに「\n\n毎週のレポートファイルを添付します」を入れます。
「\n」は改行を意味し、これを2つ入れることで2行分を改行することができます。
メッセージは以下のようになります。
‘token’: token,
‘channels’: channel,
‘initial_comment’: text
}
3つのパラメーターを設定します。
channels:投稿するSlackチャンネル
initial_comment:投稿するメッセージ
プログラムB2|投稿するExcelファイルを絶対パスを取得
1 2 3 |
#プログラムB2|投稿するExcelファイルを絶対パスを取得 fullpath = os.path.join(os.getcwd(), filename) files = {'file': open(fullpath, 'rb')} |
Slackに投稿するExcelファイルのフルパスを取得します。
「os.getcwd()」でフォルダパスを取得できるので、それとfilenameを結合して、フルパスを作成しています。
Slackに投稿するExcelファイルの設定を行います。
プログラムB3|SlackへExcelファイルを投稿
1 2 |
#プログラムB3|SlackへExcelファイルを投稿 requests.post(url='https://slack.com/api/files.upload', params=param, files=files) |
Slackのメッセージ情報をプログラムB1のparamを、Slackに投稿するファイル情報をプログラムB2のfilesを使って、slackへメッセージ投稿します。
実際に投稿すると、以下のようになります。
プログラムC|mainプログラム
1 2 3 |
#プログラムC|mainプログラム filename, message = excel_keisan() SendToSlack(filename, message) |
プログラムAを呼び出して、returnとしてfilename, messageを取得します。
filenameはSlackに投稿するExcelファイルのファイル名を指し、messageはSlackに投稿するメッセージを指します。
プログラムBにfilenameとmessageを引数にして呼び出す
プログラムAで取得した、filename(Excelファイルのファイル名)、message(Slackに投稿するメッセージ)をプログラムBに渡し、プログラムの処理を実行します。
プログラムBのSlackの投稿が終了したら、プログラム終了です。
プログラムの解説はここまでです。
Pythonについて詳しく理解したいなら
Pythonを活用すると、仕事を効率化できる幅を広げることができます。
たとえば私が実際にPythonを活用して効率化してきた作業は以下の記事で紹介しています。
興味がある人は以下の記事もご覧ください。
Python×Excelで出来ることを以下で紹介しています。
普段の作業を自動化するヒントになるかと思いますので、興味がある人はぜひご覧ください。
Pythonの難易度などについては、以下で紹介しています。
勉強の参考になれば幸いです。