婚活で使えるいい感じのお店探しLinebotを作った

# どんなLinebotか
東京のエリア名を入力すると、婚活で使えそうないい感じのお店がLineのFlex Messageで紹介されます。
![スクリーンショット 2019-12-07 13.22.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/123996/8de96972-eb29-b8ea-3aa9-9f60f5a33b31.png)


# なぜ婚活で使えるいい感じのお店探しLinebotを作ったか
以前は結婚願望はそれほどなかった。
もうすぐ25歳になるが、それでもまだ24歳。社会に出てまだ2年目だし、そんなに稼ぎがあるわけでもない。
まだまだキャリアを築くことにも集中したいし、バックパックのような海外旅行もたくさんしたい。
それにこんな未熟な自分が家庭を持つことなんて考えられない。
だから結婚なんてしなくてもいい。
そう思っていた。

だがその考えは平成最後の夏に変わったのである。
数年振りに本気で好きな人ができたのだ。
ああ、人を愛するってこんな素敵なことなんだ、大好きな人と一緒にいれるってこんなに素敵なことなんだ、とわかった。
残念ながらその人とのお付き合いは短命に終わり、今となっては良い思い出だが、
それをきっかけとして私の結婚欲は俄然高まり、婚活を始めることとなった。


マッチングアプリをやったことのある方ならわかると思うが、何人かと会うだけでわりと疲れる。
毎回同じようなチャットをして、同じような話を初回のデートでして、同じようなお礼LINEを送り、もはや作業である。
そしてだいたいお店選びは男の役割だ。

「初回デート」のお店選びは地味に難しい。付き合い始めたカップルのデートでお店を決めるのはそこまで気が重くないが、初回デートにはそれなりに望ましい条件がいくつかある。
私が望ましいと思っている「初回デート」(初対面でのデートだ)のお店の条件はこんな感じだ。

(1) カウンター席がある
僕みたいなコミュ障な人間にとって、初対面の人間とテーブル席で向かい合って二時間も三時間も話し続けるのは至難の技なのだ。緊張するし、疲れてしまう。
これがカウンター席だと、相手の顔を常に見続けなくも良いし、少々の沈黙があってもそこまで気まずくもなく、話が弾みやすいのだ。

(2) 隣の客や、お店の人ととの距離が近すぎない
自分たちの会話が相手以外にも聞こえているというのは意外に気まずいものだ。
婚活がかなりメジャーなものになったとはいえ、会話を聞けば
「ああ、この人たちは婚活で知り合って今日初回デートなんだな」というのが簡単にわかってしまい、ちょっと恥ずかしい。
なので隣の客との席や店員との距離はある程度あったほうがいい。

(3) 明るくなく、少々暗いぐらい
心理学的にも言われていることだが、少々暗い場所の方が人間は親密になりやすい。
単純に明るいと相手の顔がよく見えてしまうので、話が弾みにくい。

(4) カード払いできる
初回デートだろうが10回目デートだろうがカードで払えないお店は避けたい

(5) イタリアン、フレンチ、ビストロ系など
(1)~(4) に該当する店は結果的にこのジャンルに収まることが多いということなんだろう。
もちろん和モダンでシックな初回デート向きの和食店もあるが、基本的にはイタリアン、フレンチなどがファーストチョイスとして無難な選択肢なのだ


もはやなにについてのブログなんだという感じだが、要するに初回デートの店選びは難しく、時間のかかる作業である(下手すりゃ二時間ぐらいかかる)ということが言いたかったのである。

そこで、是非ともこの時間を削減し初回デートのハードルを少しでも下げたいと思い、「婚活で使えるいい感じのお店探しLinebot」を作るに至った。

# 使用技術
- Go
- Postgresql
- Google Spread Sheet
- Heroku
- LINE Developersアカウント

## Webサーバー
仕事ではNode.jsを書いているが、もっとバックエンドの言語に強くならないといけないな、と思い、最近個人で勉強していたGoで書くことにした。
<a target="_blank" href="https://www.amazon.co.jp/gp/product/4798142417/ref=as_li_tl?ie=UTF8&camp=247&creative=1211&creativeASIN=4798142417&linkCode=as2&tag=assocmimaki06-22&linkId=7f2a38a1c5d1b9e867fc038e93a36f92">スターティングGo言語</a><img src="//ir-jp.amazon-adsystem.com/e/ir?t=assocmimaki06-22&l=am2&o=9&a=4798142417" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" />でGoの文法を学び、<a target="_blank" href="https://www.amazon.co.jp/gp/product/B06XKPNVWV/ref=as_li_tl?ie=UTF8&camp=247&creative=1211&creativeASIN=B06XKPNVWV&linkCode=as2&tag=assocmimaki06-22&linkId=59eb95f10b6c2917c8ab86137bcb1e3e">Goプログラミング実践入門　標準ライブラリでゼロからWebアプリを作る</a><img src="//ir-jp.amazon-adsystem.com/e/ir?t=assocmimaki06-22&l=am2&o=9&a=B06XKPNVWV" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" />でGoで作るWebアプリについて学んだ。
GoはWebフレームワークを使わなくてもわりと簡単に簡単なアプリケーションを作れることがわかった。

[Go言語用のlineのsdk](https://github.com/line/line-bot-sdk-go)が出ていたので、これを使用。
[LINE Developersサイト](https://developers.line.biz/ja/)でLINE BOTのアカウント「TOKYO IKANJINOMISE」を作成した。

仕組みとしては、Linebotのアカウントでリクエストのエンドポイントを指定することができ、ここに自身のアプリケーションのURLを入れれば、Linebotへのリクエストが自身のアプリケーションを叩く、というものである。

Linebot -> LINE -> 自作webサーバー -> LINE -> Linebot というリクエストの流れだ。

本当はAWSの勉強もしたくてAPI GatewayやLambdaを使うことも考えたが、構想していたアプリケーションの仕組み上どうしてもDBを使う必要があり、AWSだとDBはどの種類でもわずかな使用でも料金がかかってしまうようで、必要なレコード数は200程度なのに料金を払うのもな、と思いやむなく断念した。

## DB
なぜ自身でDBが必要だったかというと、ユーザーから入力されたエリア名をそのままどこかに投げればお店が見つかる、というサイトやAPIがなかなかなく、エリア名とグルメサイトのURLパスのマッピングを作る必要があったからだ。
結局東京のエリアと、あるグルメサイトのエリアカテゴリパスのマッピング表を手作業でGoogle Spread Sheet上に作り、それをCSVとしてHerokuが用意しているPostgresqlにインポート、一度入力されたエリアからグルメサイトのパスを検索してその後グルメサイトのURLを叩いてクローリングするというちょっと回りくどいやり方になってしまった。

作成したDBは以下のような感じである

| 地域名 | グルメサイトのURLパス |
|:-----------------|------------------:|
|銀座| chuo-city/st22641/|
|銀座一丁目| chuo-city/st22642/|
|日比谷| chiyoda-city/st22951/|

# 処理概要
処理の流れは以下のようになる

1. Linebotでエリア入力
2. LINEサーバーにリクエストが送られる
3. 自作のWebサーバーに入力されたエリア情報とともにアクセス
4. 自作Webサーバーが持つDBにアクセスし、入力されたエリアの、グルメサイトのURLパスを取得
5. グルメサイトのドメインとURLパスの文字列を組み合わせ、リクエストを送る
6. 返却されたhtmlを解析し、LineのFlex Messageのパラメータを組み立て、LINEサーバーに送信
7. LinebotにFlex Messageが届く

4で使用するDBが上記のものだ。
6のhtml解析では、jqueryライクにhtmlを解析できる[goquery](https://github.com/PuerkitoBio/goquery)を使った。
# グルメサイトの選定
最終的にOzmallを選択した。

Rettyを使いたかったのだが、Rettyは(当時)(多分)SSRしておらず、クローリングができなかった。
Rettyは食べログやぐるなびよりも婚活向きのお店が揃ってる印象だったので、婚活向けの店を探すには良いかと思ったのだ。
掲載数も多く、カウンター席や価格帯で絞っても十分件数が出るので、このようなBotに向いてそうだった。
実際私もお店探しはRettyで行うことが多かった。

Rettyがダメとなり、東京カレンダーとOzmallで迷ったのだが、Ozmallの方が東京カレンダーよりレストランにひもづくエリアの正確性が高いなという所感を感じたので、最終的にOzmallをクローリングすることにした。