【LINE Bot】読書を手助けしてくれるコトバンクbotを作ってみた！

# 作ったもの
コトバンクで単語を検索して、その意味を返信してくれるLINE Botです。
辞書アプリやブラウザを立ち上げなくても、LINEで手軽に単語や言い回しの意味を調べられます。
![IMG_2318.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/232318/fc2a1598-63be-2262-f34c-4a7bc8629700.png)

アニメのタイトルだってお手のもの！
![IMG_2317.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/232318/65fa2c0f-e3bd-cf1e-910a-6989a36e9aab.png)

# 背景
### 読書中の単語検索は煩わしい
たとえば読書をしていて知らない単語や言い回しに遭遇した場合、大抵は
**「スマホでブラウザを起動」→「単語を入力」→「検索結果の一覧から適当にページを選択」→「ページ内で単語の意味を確認」**
という手順でその意味を確認すると思います。（Kindleの辞書機能を使っていても、固有名詞や珍しい言い回しは意外とヒットしなかったり）

これが1冊で1〜2回の作業なら何も問題ないのですが、海外の古典文学や厨二用語全開のラノベ（謎の横文字や難読漢字だらけ！）などは、下手をすると数ページおきに知らない言葉が出てきたりして、そのたびに

**「スマホでブラウザを起動」→「単語を入力」→「検索結果の一覧から適当にページを選択」→「ページ内で単語の意味を確認」→「次の単語を入力」→「検索結果の一覧から適当にページを選択」→……（以下ループ）**
とするのは非常に面倒です。

### そこでLINE Botの登場

その点、LINE Botであれば
**「LINEを起動」→「Botに単語を送信」→「返答（単語の意味）を確認」**
で済みますし、連続して検索する場合でも
**「単語を入力」→「返答を確認」→「単語を入力」→……**
だけで済みます。

また、チャット上に検索結果のログも残るので、読書後などにあらためて単語を確認することもできて**一石二鳥です！**

# 参考にした記事
-  [【Rails】1時間ぐらいで簡単にLINEのBot開発をしよう-アンケート集計Bot基礎-【画像付き】](https://qiita.com/noriya1217/items/00d6461e9f54900377a3)
LINE Developersの登録について、非常にわかりやすく学ぶことができます！

- [1時間でWikipedia検索できるLINE BOTをサクッと作ってみよう！](https://qiita.com/Keisuke_Tsuji/items/7cac27db7d1bd030205a)
Herokuのアプリケーションの作成や環境変数の設定など、めちゃめちゃ参考にさせていただきました！

- [LINEBOT + RailsでWikipediabotを作ってみました。](https://qiita.com/taka94/items/a0d1f6b69e2983b9be4e)
WikipediaのAPIを利用してBotを作る記事です。
メッセージ応答部分の記述など、かなり参考にさせていただきました！

- [Rails スクレイピング手法 Mechanizeの使い方](https://qiita.com/shizuma/items/d04facaa732f606f00ff)
Mechanizeを使ったスクレイピングの方法を勉強させていただきました！

# Bot完成までの大まかな手順
- LINE Developersの登録
 - Channelの作成
 - トークンの発行
 - Webhook URLの設定（Heroku上に作成したアプリのURLをあとから登録する）
- Herokuの登録
 - Heroku上にアプリを作成
 - git push heroku master（アプリをHerokuにプッシュ）
 - トークンを環境変数として設定
- アプリケーションの実装
 - gemの導入
 - callbackアクションに処理を記述
 - アプリをHerokuにアップ（完成！）

# LINE Developersの登録
[【Rails】1時間ぐらいで簡単にLINEのBot開発をしよう-アンケート集計Bot基礎-【画像付き】](https://qiita.com/noriya1217/items/00d6461e9f54900377a3)

#### 1. 上の記事を参考に、Channelを作成
#### 2. 「応答メッセージ: オフ」「Webhook: オン」に設定を変更
#### 3. 「チャネルトークン」「チャネルシークレット」を発行

# Herokuの登録
[1時間でWikipedia検索できるLINE BOTをサクッと作ってみよう！](https://qiita.com/Keisuke_Tsuji/items/7cac27db7d1bd030205a)

#### 1.上の記事を参考に、Herokuに登録
#### 2.Heroku上にアプリを作成（コマンドでもブラウザからでもOK）
#### 3.さきほど発行した「チャネルトークン」「チャネルシークレット」をHerokuの環境変数に設定

```
% heroku config:set LINE_CHANNEL_TOKEN="チャネルアクセストークンの文字列" -a アプリケーション名
% heroku config:set LINE_CHANNEL_SECRET="チャネルシークレットの文字列" -a アプリケーション名
```

#### 4.Line Developerのページに戻り、Webhook URLを設定
Webhook URLに`https://作成したHerokuアプリのURL/callback`と設定し、
設定後に表示される「Webhookの利用」の項目もオンにする。

# アプリケーションの実装
[LINEBOT + RailsでWikipediabotを作ってみました。](https://qiita.com/taka94/items/a0d1f6b69e2983b9be4e)
[Rails スクレイピング手法 Mechanizeの使い方](https://qiita.com/shizuma/items/d04facaa732f606f00ff)


#### 1.上の記事を参考にgemを導入

```ruby:Gemgile
gem 'line-bot-api'
gem 'mechanize'
gem 'dotenv-rails'
```

```
% bundle install
```

#### 2.ルーティングの設定

```ruby:config/routes.rb
Rails.application.routes.draw do  
    post '/callback' => 'linebot#callback'  
end 
```

#### 3.コントローラーの作成

```
% rails g controller linebot
```

#### 4.コントローラーの編集

```ruby:app/controllers/linebot_controller.rb
class LinebotController < ApplicationController
  require 'line/bot'
  require 'mechanize'

  # callbackアクションのCSRFトークン認証を無効
  protect_from_forgery :except => [:callback]

  def client
    @client ||= Line::Bot::Client.new { |config|
      config.channel_secret = ENV["LINE_CHANNEL_SECRET"]
      config.channel_token = ENV["LINE_CHANNEL_TOKEN"]
    }
  end

  def callback
    body = request.body.read

    signature = request.env['HTTP_X_LINE_SIGNATURE']
    unless client.validate_signature(body, signature)
      head :bad_request
    end

    events = client.parse_events_from(body)

    events.each { |event|
      if event.message['text'] != nil
        # LINEで送られてきた文書を取得
        word = event.message['text']
        # インスタンス生成
        agent = Mechanize.new
      end

      # 取得に成功した場合の処理
      begin
        # ページのHTMLを取得
        page = agent.get("https://kotobank.jp/word/#{word}")

        # 要素を取得
        if page.search('.dictype.cf.daijisen').present?
          # デジタル大辞泉の項目が存在する場合の処理
          response = page.search('.dictype.cf.daijisen .description').inner_text.gsub(/(\s|　)+/, '')
        elsif page.search('.dictype.cf.js-contain-ad.daijisenplus').present?
          # デジタル大辞泉プラスの項目が存在する場合の処理
          response = page.search('.dictype.cf.js-contain-ad.daijisenplus .description').inner_text.gsub(/(\s|　)+/, '')
        else
          # デジタル大辞泉とデジタル大辞泉プラスの項目が存在しない場合の処理
          response = page.search('.description')[0].inner_text.gsub(/(\s|　)+/, '')
        end
      # 取得に失敗した場合の処理
      rescue Mechanize::ResponseCodeError => e
        response = "見つかりませんでした！"
      end

      case event
      # メッセージが送信された場合
      when Line::Bot::Event::Message
        case event.type
        # メッセージが送られて来た場合
        when Line::Bot::Event::MessageType::Text
          message = {
            type: 'text',
            text: response
          }
          client.reply_message(event['replyToken'], message)
        end
      end
    }

    head :ok
  end
end

```

#### コードの補足

```ruby
# ページのHTMLを取得
page = agent.get("https://kotobank.jp/word/#{word}")
```
コトバンクでは検索したいワードを`https://kotobank.jp/word/検索したいワード`と指定するようなので、
ユーザから受け取ったワードを埋め込むようにして、getメソッドにURLを渡しています。

```ruby
response = page.search('.dictype.cf.daijisen .description').inner_text.gsub(/(\s|　)+/, '')
```
botから送られてくるメッセージの前後に大量の空白があったので、
`.gsub(/(\s|　)+/, '')`を追加して、スペースを取り除いています。

#### 5.Herokuにデプロイ

```
% git add .
% git commit -m "linebot"
% git push heroku master 
```

# 最後に

元々はAPIの学習を目的として作ったものでしたが、せっかくなので記事としてアウトプットしました！
ご指摘などございましたら、ぜひコメントよろしくお願いいたします！