PythonでSlackのチャンネルにメンション付き投稿

## はじめに
この記事では、PythonでSlackのチャンネルにメンション付きで投稿する方法を載せています。
ローカル環境での実行だけでなく、ローカル環境で作ったイメージをAWS ECRリポジトリにUploadして、そのイメージを使って作ったAWS Lambdaでも実行出来るようにしています。

## 背景
Webスクレイピングなどをしていると、結果をslackやメールに送りたくなる時があります。
slackについてはメンション付きだと気付きやすいので、今回は、slackのチャンネルにメンション付きで投稿する方法についてまとめました。

## 目次
- [環境](#環境)
- [前提条件](#前提条件)
- [構成図](#構成図)
- [フォルダ構成](#フォルダ構成)
- [手順](#手順)
    - 1：[GitHubよりcloneする](#1githubよりcloneする)
    - 2：[Slackの設定](#2slackの設定)
    - 3：[ローカル環境でSlackに投稿する](#3ローカル環境でslackに投稿する)
    - 4：[AWS LambdaでSlackに投稿する](#4aws-lambdaでslackに投稿する)
- [プログラム解説](#プログラム解説)
- [まとめ](#まとめ)


## 環境
- ローカル
    |  |  |
    |--------|--------|
    | OS  | Windows11  |
    | Docker  | Dockerデスクトップ  |
    | 開発ツール  | Visual Studio Code  |
    | 言語  | Python3.8 |

- クラウド：AWS
    - AWS Lambda
    - Amazon Elastic Container Registry(ECR)
- その他サービス：Slack

## 前提条件
下記の過去記事を参考に環境設定をしていることを前提条件とします。
また、過去記事で説明している部分は説明を省略します。

Windows＆Docker開発環境で作ったImageをそのままAWS Lambdaにのせる方法
https://qiita.com/sasayakadopono/items/cfc7479fff3b685b3932

## 構成図
![構成図.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/0bc1fa2d-baa0-daa2-9a28-eaf3c086c26c.png)


## フォルダ構成
プロジェクトルート(D:\src\lambda_slack_notification)
├─.devcontainer
│  ├─ devcontainer.json
│  └─ settings.json
├─app
│   ├─ date_utility.py
│   ├─ lambda_function.py
│   └─`__init__.py`
├─ .dockerignore
├─ .env
├─ .gitignore
├─ awscli.sh
├─ delete-container-image.sh
├─ docker-compose.yml
├─ Dockerfile
├─ README.md
└─  requirements.txt

## GitHub
https://github.com/sasayakado/lambda_slack_notification.git

## 手順
### 1.GitHubよりcloneする
1.  cloneする
    ```bash:Git Bush 
    git clone git@github.com:sasayakado/lambda_slack_notification.git

2. VSCodeでプロジェクトルートを開く

3. .env_sampleを.envにreneame

4. .envに自分の環境変数を設定
    
```sh:.env
AWS_ACCESS_KEY=★1
AWS_SECRET_ACCESS_KEY=★2
AWS_ACCOUNT_ID=★3
AWS_DEFAULT_REGION=★4
IMAGE_TAG=★5
DOCKER_IMAGE_NAME=★6
DOCKER_CONTAINER_NAME=★7
LAMBDA_FUNC_NAME=★8
SLACK_URL=★9
SLACK_USERID=★10
```
| ★ | 変数 | 設定内容 | 
|--------|--------|--------|
| 1～8|説明省略|[過去記事参照](https://qiita.com/sasayakadopono/items/cfc7479fff3b685b3932)
| 9|SLACK_URL  |[後で説明](#slack_url9)  |
| 10|SLACK_USERID  |特定の人へメンションする場合は[後で説明](#slack_userid10)  <br>チャンネルにメンション(@channel)で投稿したい場合は`'<!channel>'`|


　　↓　こんな風になる

```sh:.env
AWS_ACCESS_KEY=★自分のAWS_ACCESS_KEY
AWS_SECRET_ACCESS_KEY=★自分のAWS_SECRET_ACCESS_KEY
AWS_ACCOUNT_ID=★自分のAWS_ACCOUNT_ID
AWS_DEFAULT_REGION=ap-northeast-1
IMAGE_TAG=latest
DOCKER_IMAGE_NAME=slack-image
DOCKER_CONTAINER_NAME=slack-container
LAMBDA_FUNC_NAME=slack-lambda
SLACK_URL=★https://hooks.slack.com/services/XXXなど
SLACK_USERID=★'<!channel>'など
```
### 2.Slackの設定
1.アプリの追加と確認
- Slackを開いて、ワークスペースの横にある下矢印をクリックして「App」を選択する
![slcak_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/ff21ad1c-e820-e0b8-6921-b7950f3be665.png)

- 検索ウィンドウに「webhooks」と入力して検索し、「Incoming WebHooks」を追加する
![slcak_2_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/be2b4bd1-4495-8e4c-f510-ad6d31a8bd82.png)

- Slackに追加をクリックする
![slcak_3_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/3fb1c368-7b74-91da-e676-314900f91ec3.png)

-  投稿したいチャンネル（今回は、「random」）を選択する
![slcak_4_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/fe9da112-47ba-062a-69cb-e1c678ecc6a6.png)

-  利用規約を読んで、問題なければ、「Incoming WebHookインテグレーションの追加」をクリックする
![slcak_5_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/7b441f0a-2fc8-34fa-7cdb-6641ba6019e4.png)

-  WebHook URLの「URLをコピーする」を押して、コピーしたのを.envの★9に貼り付ける
##### SLACK_URL=★9
　↓
SLACK_URL=https://hooks.slack.com/services/XXX
![slcak_7_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/a4ec7326-76af-70d2-2cfa-daaf6216d3e6.png)

:::note warn
警告
.envを修正した際には、一度開発コンテナを閉じて、既存コンテナ・イメージを削除後、再度開発コンテナを作り直してください。
delete-container-image.shを実行すれば既存コンテナ・イメージを削除出来ます。
:::

- 変更したい場合は、名前とアイコンをカスタマイズする
![slcak_8_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/4918383a-48d9-cc20-2d7d-e079ddcdfc85.png)

- 実際に設定されたか確認するために、「App」を選択し、カスタマイズした名前のアプリをクリックする
![slcak_9_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/3d8d94f7-7974-4d55-0973-19e0d10e5fc8.png)

- 「設定」をクリックする
![slcak_10_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/8fb392b2-9a86-28b3-dbbe-4345f78023db.png)


- 「設定」タブを開いて、カスタマイズした名前、投稿したいチャンネル名、アイコンが合っているか確認する
![slcak_11_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/ee66d3d4-7f4e-408e-a76b-45437302379f.png)

- チャンネルの「random」を開くと、「このチャンネルに次のインテグレーションを追加しました：カスタマイズした名前」と出ている
![slcak_12_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/78dc3ce1-61e9-7404-4bb9-d1f0e38fcea2.png)

2.メンション対象の取得と設定
- メンション対象を指定するために、メンションしたい人のプロフィールを開く
![slcak_13_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/5f3af68e-4ea5-60c7-374d-04e8cfebc02a.png)


- メンバーIDをコピーして、.envの★10に貼り付ける。
##### SLACK_USERID=★10
↓
SLACK_USERID=`'<!UXXXXX>'`
もし、特定の相手ではなくて、チャンネル全体に対してメンションして投稿したい場合は、`'<!channel>'`を設定する

:::note warn
警告
.envを修正した際には、一度開発コンテナを閉じて、既存コンテナ・イメージを削除後、再度開発コンテナを作り直してください。
delete-container-image.shを実行すれば既存コンテナ・イメージを削除出来ます。
:::

![slcak_14_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/ff8579c7-ea78-d585-c96d-c2a482d62252.png)


### 3.ローカル環境でSlackに投稿する

- 開発コンテナを起動して、lambda_function.pyを実行する
![slcak_16_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/322d745c-f964-2331-df54-1cb1e2d4f0db.png)
ターミナルでの実行結果
![slcak_17_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/cf026842-68b0-2953-1205-b4bd66f804f0.png)

- Slackの対象チャンネルに、メンション付きで投稿されているのを確認する
![slcak_15_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/a832ae2f-0f7d-34da-9a4e-cffcf793e254.png)

:::note info
インフォメーション
ここから先は、AWS Lambdaで実行したい人だけが行ってください
:::

### 4.AWS LambdaでSlackに投稿する


- ECRにプライベートリポジトリを作る。
![slcak_20_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/5ef6e217-74c1-086e-707f-df220219a68f.png)



開発コンテナを閉じて、プロジェクトルートフォルダを開き、下記をgit bashで実行
```sh:
source awscli.sh
```
:::note warn
その際、awscli.shの下記部分をコメントアウトしてから実行（Lambdaを作っていないのでエラーになる）
```
# ECRにプッシュしたイメージをlambdaに更新
#aws lambda update-function-code --function-name $LAMBDA_FUNC_NAME --image-uri #$AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$DOCKER_IMAGE_NAME:$IMAGE_TAG > /dev/null 2> /tmp/aws_lambda_error.log

#if [ $? -eq 0 ]; then
#    echo "lambda update success"
#else
#    # エラーメッセージを表示する
#    cat /tmp/aws_lambda_error.log
#    exit 1
#fi
```
:::

実行結果
![slcak_19_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/e89c2062-b9c0-e650-2f68-e04491467f19.png)

- ECRにイメージが出来るので、そのイメージを選択したLambdaを作る
![slcak_21_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/ff630353-7e5f-6b89-fa23-4b4ce4ad8311.png)

- Lambda設定タブで、環境変数に、.envにある★9と★10を設定する
![slcak_22_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/c77b62e5-2f02-655d-6185-39b79121e93c.png)


- Lambdaをテスト実行する
![slcak_23_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/602ba771-4357-ab3b-7d73-2f77335cdb3a.png)

- Slackの対象チャンネルに、メンション付きで投稿されているのを確認する
![slcak_24_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/977e8674-e3cd-71e1-8c2d-9024666f966c.png)

- ★10にチャンネルを設定した場合は、@channelとして投稿される
![slcak_25_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/2c53377d-1601-d784-5214-298b5f67dc56.png)


おしまい。

## プログラム解説

### lambda_function.py

| PG | Slack |
|--------|--------|
| ![slcak_26_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/58aa37e5-06cb-8b44-a37e-5cc31db2820d.png)  | ![slcak_26_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/b21feaec-b1f9-2455-faad-c62e5c7c031d.png)<br>![slcak_26_4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/bcd9a216-b708-a20f-6555-07e29bf02cbf.png)  |


- ①メッセージを設定
```python:lambda_function.py
msg = f'現在「{today_time_str}」です。 \nテストメッセージ'
```

- ②タイトルを設定
```python:lambda_function.py
title = f"{today_str}テストタイトル"
```

- ②タイトルと、③メンション対象＆①メッセージを引数に、send_slackを呼ぶ
```python:lambda_function.py
send_slack(title, f"{SLACK_USERID}\n{msg}")
```

- セカンダリ メッセージを送っている
参照：Reference: Secondary message attachments
https://api.slack.com/reference/messaging/attachments
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/d84f99ea-6906-35d0-c6e6-9cb79bf11b7e.png)


- ④横棒の色を変えられる
```python:lambda_function.py
"color": "#36a64f"
```
　↓

```python:lambda_function.py
"color": "#a63c36"
```

![slcak_27_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3550606/c84b505d-71a0-9743-5dc4-13cfcdcee7fd.png)



## まとめ
エラーが起きた時の通知先をSlackにするとかが使い道として考えられそうです。
私はLambdaの定期実行を設定して、Webスクレイピングした結果を定期的にSlackに送ってます。