AI を活用したニッチ求人自動検索システムの作成事例 

## 1. はじめに

近年、障害者向けのデータサイエンス系求人は非常にニッチな分野となっており、自分の希望に合う求人を手動で探すのは困難です。そこで、本プロジェクトでは、Gemini API を活用して Web 上から求人情報を自動的に検索し、要約結果を Slack に投稿するシステムを構築しました。

システムの特徴として、**求人掲載サイトや求人エージェントの名称が混在してしまう問題**に対して、検索段階から「実際に求人を出している企業の正式名称」を優先的に取得するよう指示を追加している点が挙げられます。  
（例：求人掲載サイト名 "Indeed" や "求人ボックス" が入るのではなく、「株式会社サンプルテック」など実際の企業名のみを抽出）

本記事では、システム全体の構成、各モジュールの役割、そして検索・要約プロンプトの改善点について詳しく解説します。

---

## 2. システム概要

本システムは、以下の 2 つの主要機能から構成されています。

### 2.1 求人情報の検索と要約（Summary モード）
- **目的:** Web 上から自動で求人情報（障害者向け、データサイエンス系）を検索し、5件にまとめた要約結果を Slack に投稿します。
- **特徴:**  
  - Gemini API で求人情報の要約を自動生成。
  - 要約結果は視認性向上のため絵文字（🏢、📍、💼、💰、⏰、🔍）を用いたフォーマットで表示。
  - 求人掲載サイトの名称は除外し、実際の企業の正式名称のみを出力するよう指示。

### 2.2 企業分析と重複防止（Analysis モード）
- **目的:** 集約された求人情報から、既に分析済みの企業は除外し、未分析の求人案件を対象に各企業の概要と背景を解析・要約します。
- **特徴:**  
  - 求人情報ファイル `data/reqruit.txt` を読み込み、求人ごとに分割して企業名を抽出。
  - 企業名は正規化（絵文字や参照番号などを除去）し、同一企業の重複分析を防ぎます。
  - 分析結果は JSON（`data/analysis_results.json`）に保存され、Slack にも投稿されます。

---

## 3. プロジェクト構成

リポジトリのディレクトリ構造は、以下のようになっています。

```
SlackRecruitBot/
├── .github
│   └── workflows
│       ├── summary.yml         # 毎日9時に求人要約を自動生成、Slackへ投稿
│       └── analysis.yml        # 毎日10時～14時に未分析企業の分析を1件ずつ実行、Slackへ投稿
├── data
│   ├── reqruit.txt             # 検索済み求人情報の要約結果
│   └── analysis_results.json   # 企業分析結果の保存先（キーは企業名）
├── src
│   ├── __init__.py             # パッケージ初期化用
│   ├── gemini_slack_poster.py  # 求人情報の検索・要約、Slack投稿の処理
│   ├── company_recruit_analysis.py  # 求人情報の分割、企業分析、重複防止、Slack投稿の処理
│   └── main.py                 # エントリーポイント（--mode summary / analysisで実行）
├── requirements.txt            # 必要なパッケージ一覧
└── README.md                   # このドキュメント（Qiita記事）
```

使用している主な技術は、Gemini API、Slack API、GitHub Actions、Python（requests、argparse など）です。

---

## 4. 各コンポーネントの詳細と実装例

### 4.1 GeminiSlackPoster クラス（求人要約の処理）
- **主な処理フロー:**  
  1. **求人情報の検索・抽出:**  
     - `search_info(user_query)` でユーザーのクエリに対し、以下の追加指示を付与した検索クエリ（enhanced_query）を Gemini API に送信します。
     
     ```python
     def search_info(self, user_query):
         enhanced_query = (
             f"{user_query}\n"
             "注意：求人掲載サイトや求人エージェントの名称（例: 'Indeed', '求人ボックス', '障害者転職エージェント ハッピー', 'スグJOB' など）は出力結果に含めず、"
             "実際に求人を出している企業の正式名称のみを優先して回答してください。"
         )
         response = self.search_client.send_message(enhanced_query)
         original_text = ""
         for part in response.candidates[0].content.parts:
             if part.text:
                 original_text += part.text + "\n"
         summary_text = self.summary_client(original_text)
         references_text = self.serch_references(response)
         return summary_text, references_text, response
     ```
     
  2. **求人情報の要約生成:**  
     - `summary_client(original_text)` では、検索結果の元テキストを指定フォーマットで要約するためのプロンプトを Gemini に送信します。  
     - ここでは、求人掲載サイト名が除外されるように、また情報不足の案件を除外するよう、【要件】に詳細な指示を加えています。
     
     ```python
     def summary_client(self, original_text):
         summary_prompt = f"""
         以下の文章をもとに、求人情報の各案件を分かりやすく整理し、次のフォーマットで5件にまとめて出力してください。
         回答は必ずプレーンテキスト形式で、マークダウン記法や装飾は使用せず、絵文字を用いた視認性の良い形式で返してください。
         
         ※注意：
         1. 求人掲載サイトや求人エージェントの名称（例: 'Indeed', '求人ボックス', '障害者転職エージェント ハッピー', 'スグJOB' など）は出力結果に含めず、実際に求人を出している企業の正式名称のみを使用してください。
         2. もし出力結果に「複数の企業」と表記される場合は、特に勤務地が「大阪府梅田本社オフィス」と記載されている企業を代表例として、1社に絞って情報を出力してください。
         3. 各求人案件の重要項目（勤務地、職種、給与、勤務形態、特徴）が『記載なし』の場合、その案件は出力結果に含めないでください。
         
         【期待する出力フォーマット例】
         --------------------------------------------------
         🏢 本日のデータサイエンス系障がい者求人はこちらです：
         
         1. 🏢 株式会社サンプルテック
             📍 勤務地: 東京都中央区（例）
             💼 職種: データサイエンティスト（例）
             💰 給与: 年収450万円～650万円（例）
             ⏰ 勤務形態: 正社員（例）
             🔍 特徴: 先進的なデータ活用、豊富な求人情報
         --------------------------------------------------
         
         【要件】
         - 最初に「本日のデータサイエンス系障がい者求人はこちらです：」と記載してください。
         - 各求人の企業名、勤務地、職種、給与、勤務形態、特徴を必ず明記してください。
         - 回答はプレーンテキスト形式で、絵文字等を利用して情報を視認性よく出力してください。
         - ※求人情報掲載サイトの名称は含めず、具体的な企業名を主体として出力してください。
         
         【元のテキスト】
         {original_text}
         """
         summary_response = self.client.models.generate_content(
             model="gemini-2.0-flash-exp",
             contents=summary_prompt
         )
         return summary_response.text.strip()
     ```
     
  3. **Slack 投稿:**  
     - 要約結果は `post_message_to_slack(message)` で Slack に投稿し、`data/summary_result.txt` にも保存されます。

---

### 4.2 CompanyRecruitAnalysis クラス（企業分析処理）

- **主な処理フロー:**  
  1. **求人情報の読み込みと分割:**  
     - `split_jobs(req_text)` により、`data/reqruit.txt` の求人情報を個々の案件に分割。
  2. **企業名抽出:**  
     - `extract_company_name(job_text)` 関数で、求人情報の先頭行から番号、ピリオド、絵文字、参照番号などを除去し、正式な企業名（例：「株式会社サンプルテック」）を抽出します。  
     - ここで、抽出された企業名を normalize することで、「株式会社サンプルテック」と「🏢 株式会社サンプルテック [2]」を同一と判定できるようにします。
  3. **重複チェック:**  
     - JSON ファイル（`data/analysis_results.json`）から既に分析済みの企業情報を読み込み、抽出した企業名が存在する場合はその求人案件をスキップします。
  4. **企業分析:**  
     - 未分析の求人案件の中から先頭1件を選び、 `analyze_company(job_text)` で Gemini API を使用して企業概要と背景を解析し、400文字以内で要約します。
  5. **Slack 投稿と結果保存:**  
     - 解析結果に注意文を加えた最終メッセージを Slack に投稿し、結果を JSON ファイルに保存する（キーは企業名）。

---

### 4.3 main.py（エントリーポイント）

- **役割:**  
  コマンドライン引数（--mode summary または --mode analysis）により、求人情報の要約または企業分析を実行します。  
  CI/CD（GitHub Actions）からはこの main.py を呼び出し、定刻実行されます。

---

## 5. 動作例（出力例）

**Summary モードの場合:**  
- Slack には以下のように投稿されます。

```
🏢 本日のデータサイエンス系障がい者求人はこちらです：

1. 🏢 株式会社サンプルテック
    📍 勤務地: 東京都中央区
    💼 職種: データサイエンティスト（ジュニアレベル）
    💰 給与: 年収450万円～650万円
    ⏰ 勤務形態: 正社員
    🔍 特徴: 先進的なデータ活用とAIモデル構築
...
```

**Analysis モードの場合:**  
- 未分析の企業の情報が Slack に投稿され、`data/analysis_results.json` には以下のように保存されます。

```json
{
  "株式会社サンプルテック": {
    "analysis": "株式会社サンプルテックの企業概要と障がい者雇用に関する考察： ...",
    "timestamp": "2025-04-12T10:35:00+09:00"
  }
}
```

---

## 6. まとめと今後の展望

このシステムは、AI（Gemini API）を活用して障害者向けデータサイエンス系のニッチな求人情報を自動で検索し、自分の希望に合った求人情報を効率的に抽出・要約する事例です。  
・検索段階では、求人掲載サイト名ではなく、実際の求人を出している企業の正式名称を取得するように指示を行い、  
・要約段階では、企業名と職種などの情報を視認性の高い絵文字付きフォーマットで出力するようにしています。  

今後、このシステムをベースに、より幅広いニッチ分野の求人情報検索や、細かい抽出ルールのチューニングを行うことで、ユーザーの希望に合致した求人情報をさらに正確に自動収集することが可能になると考えています。

---

## 7. おわりに

この事例では、AI と自動化ツールを組み合わせることで、障害者向け求人情報の収集および要約が如何に効率化できるかを示しました。  
コードやプロンプト設計の工夫によって、求人掲載サイト名などの不要情報を排除し、実際の企業の正式名称に基づいて検索・分析が行える点が、このシステムのポイントです。

---