Pythonのslack_sdkライブラリで最新記事のキャッチアップができるSlackボットを作る  

# 1. はじめに  
**この記事は、slackボットを作成する記事です。slack_sdkの使い方を説明するわけではありません。**

近頃、生成AI関連の情報は毎日のように新しい技術が出てきて、トレンドは日々変わるため、手動で情報収集を行うのは非常に手間がかかるなと思っていました。

しかし、Slackボットを使って自動的に最新の記事を収集し、Slackチャンネルで通知を受け取る仕組みを作れば、手間をかけずに最新のAI情報をキャッチアップできるようになるんじゃね？と思いました


:::note info
注意
備忘録として書いているので、分かりずらい所などありましたらすみません。
:::


- 関連記事
[Qiita記事をSlackに自動投稿するBotの機能拡張案](https://qiita.com/banksline_tus/items/7f4a2c21a74d34ea4156)


# 2. 概要  
この記事では、Pythonを使用して、Slackボットを作成し、Qiita APIから生成AIに関連する最新記事を取得して、Slackチャンネルに自動的に通知する方法を解説します。

また、自分が指定したタグに関連する最新記事の上位3つを表示させるようにしました。

定期的に通知を送信する設定は、GitHub Actionsを利用します。


# 3. 構成

### 3.1. ディレクトリ構造
プロジェクトは以下のような構造になっています。

```bash
pj-ai_article_bot/
├── .github/
│   └── workflows/
│       └── slack_notify.yml
├── .env
├── .gitignore
├── bot.py
└── requirements.txt
```


### 3.2. 各ファイルの役割
- `.github/workflows/slack_notify.yml`: GitHub Actionsの設定ファイル。定期実行の設定が含まれます
- `.env`: 環境変数の設定ファイル。**私のリポジトリをクローンした場合は、各個人で作成してAPIキーを記入してください**
- `.gitignore`: Gitの追跡対象から除外するファイルを指定
- `bot.py`: Slackボットのメインスクリプト。記事取得とSlack通知の処理を含みます
- `requirements.txt`: 必要なPythonパッケージの一覧



# 4. Pythonとslack_sdkを使ったSlackボットの構築  

ここでは、Pythonとslack_sdkを使用して、Slackボットを作成し、Qiita APIを利用して生成AI関連記事を取得し、Slackチャンネルに通知する方法をステップバイステップで紹介します。

### 4.1. 必要なライブラリをインストール  
まずは、Slack APIと通信するために以下のライブラリをインストールします。  

```python
pip install slack_sdk requests python-dotenv schedule
```

これらのライブラリは、Slack APIとやり取りするために必要です。また、Qiita APIにアクセスするためのrequestsライブラリと、環境変数を管理するためのpython-dotenvもインストールします。


### 4.2. Slack APIトークンの準備

Slackでボットを作成し、OAuthトークン（`SLACK_TOKEN`）と投稿先のチャンネルID（`SLACK_CHANNEL`）を取得します。  
GitHub Actionsで使用するため、リポジトリの **シークレット変数** に保存しておきましょう。

### 手順

1. **Slackで新しいAppを作成し、OAuthトークンを取得します**  
    - Slackの[APIページ](https://api.slack.com/apps)にアクセスし、`Create New App`をクリックします。
    - 必要なスコープ（権限）を設定し、OAuthトークンを取得します。

2. **チャンネルIDを取得します**  
    - チャンネルIDは、チャンネル名のURL部分に含まれています。  
      例：`https://slack.com/app_redirect?channel=C01234567` の `C01234567` 部分がチャンネルIDです。

3. **これらの情報を `.env` ファイルに保存し、GitHub Actions で使用できるようにします**  
    `.env` ファイルには以下の内容を保存してください。  

    ```dotenv:.env.sample
    SLACK_TOKEN=xoxb-your-slack-token
    SLACK_CHANNEL=C0123456789
    QIITA_API_TOKEN=your-qiita-api-token
    ```

これで、Slack APIトークンとチャンネルIDの準備が整いました。GitHub Actionsでこれらを使う準備ができました。


### 4.3. Qiita APIを使って最新記事を取得

次に、Qiita APIを使って指定したタグ（例：生成AI）に関連する記事を取得します。以下にコードを示します。

```python:bot.py
import os
import requests
from slack_sdk import WebClient
from slack_sdk.errors import SlackApiError
import schedule
import time
from dotenv import load_dotenv

load_dotenv()

# （デバッグ用）.envファイルからトークンとIDを取得
SLACK_TOKEN = os.environ.get("SLACK_TOKEN")
SLACK_CHANNEL = os.environ.get("SLACK_CHANNEL")
API_TOKEN = os.environ.get("API_TOKEN")

# # GitHub Actions の環境変数から取得したいとき
# SLACK_TOKEN = os.getenv("SLACK_TOKEN")
# SLACK_CHANNEL = os.getenv("SLACK_CHANNEL")
# API_TOKEN = os.getenv("API_TOKEN")

# トークンの確認
if not SLACK_TOKEN or not SLACK_CHANNEL or not API_TOKEN:
    raise ValueError("SLACK_TOKEN, SLACK_CHANNEL, and API_TOKEN environment variables must be set.")


# Qiitaから最新3つの記事を取得
def fetch_qiita_articles(tag='生成AI', qiita_api_token=API_TOKEN):
    url = 'https://qiita.com/api/v2/items'
    headers = {'Authorization': f'Bearer {qiita_api_token}'}
    params = {'query': f'tag:{tag}', 'page': 1, 'per_page': 3, 'sort': 'created'}

    response = requests.get(url, headers=headers, params=params)
    if response.status_code == 200:
        return response.json()
    else:
        print(f"Error fetching Qiita articles: {response.status_code}")
        return []


# Slackにメッセージを送信
client = WebClient(token=SLACK_TOKEN)


def send_message_to_slack(channel_id, message):
    try:
        response = client.chat_postMessage(channel=channel_id, text=message)
        print(f"Message sent: {response['message']['text']}")
    except SlackApiError as e:
        print(f"Error sending message: {e.response['error']}")


# Qiitaの記事をSlackに通知
def notify_articles_to_slack():
    articles = fetch_qiita_articles()
    if articles:
        for article in articles:
            message = f"🔍 新しい記事があります: {article['title']}\n🔗 {article['url']}"
            send_message_to_slack(SLACK_CHANNEL, message)
    else:
        print("No articles found.")


# # （デバッグ用）時間を変えて実行してみてください。
# schedule.every().day.at("13:50").do(lambda: notify_articles_to_slack(SLACK_CHANNEL, API_TOKEN))


# スクリプト実行時に1回だけ実行
notify_articles_to_slack()
```

このコードでは、Qiita APIから指定したタグ（生成AI）の記事を取得し、それをSlackチャンネルに通知しています。取得する記事数はper_pageで指定できます。


### 4.4. GitHub Actionsで定期実行

GitHub Actionsを使って、ボットを定期的に実行する設定を行います。

毎日決まった時間に、最新の記事をSlackに通知するように設定できます。

:::note warn
注意
GitHub Actionsのcron実行では、GitHubの負荷状況により、指定した時間から**数分～30分程度**の遅延が発生する可能性があります。自分は毎回5分ほど遅延します。
:::

以下は、GitHub Actionsの設定ファイルです。毎日決まった時間に実行されるようにスケジュールしています。

```yaml:.github/workflows/slack_notify.yml
name: Qiita Slack Notifier

on:
  schedule:
    - cron: "30 23 * * *"  # 毎日 08:30 JST (UTC の 23:30)

jobs:
  notify:
    runs-on: ubuntu-latest
    steps:
      - name: リポジトリをチェックアウト
        uses: actions/checkout@v4

      - name: Python をセットアップ
        uses: actions/setup-python@v4
        with:
          python-version: "3.9"

      - name: 依存関係をインストール
        run: pip install -r requirements.txt

      - name: Qiita 通知スクリプトを実行
        env:
          SLACK_TOKEN: ${{ secrets.SLACK_TOKEN }}
          SLACK_CHANNEL: ${{ secrets.SLACK_CHANNEL }}
          API_TOKEN: ${{ secrets.API_TOKEN }}
        run: python bot.py
```

この設定ファイルでは、cron式で毎日定時にスクリプトが実行されるようにスケジュールしています。


# 5. 今後の展望
今回作成したボットでは、基本的な機能のみを実装しました。

以下のような機能を追加することで、より便利なツールになると考えています。

### 記事取得の拡張
- 複数のタグに対応した記事取得機能
  - `生成AI`, `機械学習`, `ChatGPT` など複数のタグを同時に監視
- いいね数による記事のフィルタリング
  - 一定以上の「いいね」がついた記事のみを通知
- 特定キーワードによる記事の絞り込み
  - タイトルや本文中の特定キーワードを含む記事のみを抽出

### 情報ソースの拡張（利用規約順守）
- Zenn、noteなど他の技術ブログプラットフォームからの記事取得
- 各社の公式ブログやニュースサイトからの情報収集

### Slack機能の拡張
- Slackでのインタラクティブな操作機能
  - スラッシュコマンドによる記事検索
  - ボタンやドロップダウンメニューを使用した簡単な操作
- 記事の要約機能
  - ChatGPTなどのAIを活用した記事の要約表示

ぜひ、皆様からのフィードバックやプルリクエストをお待ちしています！

https://github.com/S-Riku-tus/pj-ai_article_bot



# 6. 関連リンク
- [Qiita API ドキュメント](https://qiita.com/api/v2/docs)
- [Slack API ドキュメント](https://api.slack.com/lang/ja-jp)
- [GitHub Actions の公式ガイド](https://docs.github.com/en/actions)