ぴよがち

技術的な話をします。みんなで強くなりましょう。

くら寿司キャンセル待ちBotを作れるようになろう! - 初心者向け(前編)

後半の途中で非同期処理の説明とかが必要になり、面倒だったので途中で執筆を中断しました。 それでも良いという方のみ読み進めてください。

最近巷では、くら寿司の無限ループが流行っています。

流行るだけならいいですが、そのせいでくら寿司はどこも予約が満席になってしまっています。
日々世間のおこぼれを集めながら命をつないできた我々にとっては、迷惑な話です。

くら寿司が満席の図

しかし、ここで引き下がってはプロ乞食の名が廃るというもの。
キャンセル待ちをして、空きが出た瞬間に予約できるBotを作ってしまいましょう!

この記事の目的

この記事は、私が今日Botをどのように作ったかを思考の隅々まで細かに説明することで、
読者の皆様が明日から同じような問題に直面した際に、 自力でプログラムを書いて解決できるようになっていただくことを目的としています。

対象の読者

  • プログラムなんて書いたことがないし、私には難しいかも...
    そんなあなたも、今日から自分の欲しい物を作れるようになる思考の方法と、Google検索との付き合い方を学ぶことができるでしょう。

  • 授業や研修でちょっとはプログラムを書いたことあるけど、自信ない...
    この記事は、あなたのためのものです。
    ちょっとした作業を自動化できるようになって、毎日の生活を豊かにしましょう。

  • プログラミング チョットワカル な人
    この記事は読まないほうが良いでしょう。
    より生産的な人生の送り方をあなたは知っているはずです。

所要時間

今回の記事で作るBotであれば、慣れれば調べながらでも15分程度でつくれるようになります。

目次

作り始めるまで

予約をしようとしたら、満席なことに気づく

朝起きる。Discordで人間を集め終わって、さあ予約するか、と予約サイトを開く。

最短予約時刻が23時のスクリーンショット

夜23時以降しか空いていないではないか!
ああ、こんなことなら、一昨日予約しておけばよかった。

しかし、後悔しても仕方ない。
せっかく人間を集めたのだ。なんとしても19時台か20時台の予約しなければ!

キャンセル待ちBotを作ろうと決心する

今後10分間くらい分のやる気を捻出します。
怠惰でなかなか返事をよこさない人間を集めようとする際に必要なそれに比べれば、大したことはありません。

空き状況を表示するページを眺め、触ってみる

やる気が捻出できたら、まずはこれから対戦することになるページを観察します。

観察の目的は、私達の予約したい時間が「予約可能な状態」と「予約不可能な状態」のどちらであるかを見分けるにはどこを見て判断すればよいかを知り、それをbotに教えるためです。

EPARKのサイトからくら寿司池袋東口店を予約する場合、予約手続きを進めていくと、
この画面で時刻を選択した際に、

くら寿司の予約手続きを進めた先の、時間選択画面

  • 予約可能な時間を選択した場合

予約可能な時間を選択した例

と、

  • 予約不可な時間を選択した場合

予約不可な時間を選択した例

とで、選択肢に差があることがわかります。

また、「時」を選択した際に、何かを読み込んでいるようなマークと待ち時間があるので、
「時」を選択するたびに、サーバと何らかの通信を行ってデータを取得しているのかもしれない、という仮設を立てます。

通信内容を調べる

先程立てた仮設を検証するために、ブラウザの通信内容を覗いてみましょう!

ChromeFirefox、Edgeなど現代のPC用ブラウザでは、「F12」ボタンを押すことで、
「開発者ツール」という、サーバとの通信内容など、ブラウザの裏側を詳細に見ることができる機能を開くことができます。

今回は、Firefoxの画面で紹介します。(開発者ツールのUIが日本語でわかりやすいので、Firefoxがおすすめです。Chrome向けの英語表記も括弧内に併記しておきます。)

開発者ツールの例

「F12」を押すと、こんな感じで開発者ツールが出現します。(Chromeだと画面右側に表示されるかもしれません。)

いろいろなタブがあり、それぞれ非常に便利なのですが、
今回は通信内容を調べたいので、「ネットワーク(Network)」タブを開きます。

開発者ツールのネットワークタブを開いたときの図

すると、こんな感じで表示されるかと思います。

開発者ツールの「ネットワーク」タブを開いたままの状態で情報の送受信やページの遷移が発生すると、
通信した内容がここに記録されます。

今回は「時」を選択する際に通信を行っているかどうか、またその内容を見たいと思っていたので、
この状態で「時」を選択してみましょう。

23時を選択した場合(予約可能な時間帯を選択した場合)

まずは、予約可能な時間帯である「23時」を選択してみましょう。

予約可能なときの通信の例

すると、「ネットワーク」タブ内に行が追加されました。
どうやら「時」を選択すると、通信が発生しているようです。

増えた行を右クリックして、「URLをコピー」を選択すると、
通信先のURLを確認することができます。

通信先のURLをコピーするメニューを表示している図

通信先のURLは、
https://epark.jp/receive_department/wait/reserve_minute_select_ajax/110202/depart/11768?receive%5Breceipt_date%5D%5Bdate%5D=1603897200&receive%5Breceipt_date%5D%5Bhour%5D=23
のようです。

内容も覗いてみましょう。
「ネットワーク」タブ内の、いま増えた行をクリックします。

発生した通信を開いた図

すると、開発者ツールの右半分にその行の詳細が開きます。
「応答(Response)」タブでサーバから送られてきた情報を確認できるので、開いてみましょう。

発生した通信の「応答」タブを開いた図

Firefoxでは、このように応答の内容のプレビューが表示されます。
一番下に「応答ペイロード」と書いてある箇所があり、そこをクリックすると実際のデータを見ることができます。(Chromeでは、「Preview」と「Response」で確認できます。)

応答ペイロードを開いた図(拡大)

なんということでしょう!*1
このサイトでは、HTMLのパーツを送受信しているようです。

これでひとまず「くら寿司池袋東口店の今日の23時」についての予約可否の問い合わせ先URLと、
予約可能なときのサーバからの応答内容を手に入れることができました。

19時を選択した場合(予約不可な時間帯を選択した場合)

今度は、予約不可能な場合を試してみましょう。
「時」の選択肢から、「19時」を選択してみます。

プルダウンから19時を選択した図

すると、先ほどと同じように開発者ツールの「ネットワーク」タブに行が追加されました。
早速その行をクリックし、内容を確認します。

2つ目の通信内容が「ネットワーク」タブに表示された図

「応答」タブの「応答ペイロード」を見ると、先程と同じように応答の内容はHTMLであることがわかります。

19時の通信内容の応答ペイロード(拡大)

また、今回のリクエスト先であるURLは、次のようになっていました。
https://epark.jp/receive_department/wait/reserve_minute_select_ajax/110202/depart/11768?receive%5Breceipt_date%5D%5Bdate%5D=1603897200&receive%5Breceipt_date%5D%5Bhour%5D=19

これで、19時を選択した際の(=予約可能でない場合の)通信内容と通信先のURLも手に入れる事ができました。

2つの通信を比較する

URLを比較する

先程の23時を選択した際のURLと、19時を選択した際のURLを比較してみましょう。

末尾のみ異なっている図

並べてみると、最後の「19」と「23」だけ異なっていることがわかります。

このことから、同じ日の別の時刻を調べたいときは、URLの末尾だけを書き換えれば良さそうです。

通信の応答内容を比較する

今度は、通信内容を確認してみましょう。

<select name="receive[receipt_date][minute]" id="receive_receipt_date_minute"> 
  <option value="" selected="selected">▼分を選択</option>
          <option value="20" >20~30</option>
          <option value="30" >30~40</option>
  </select>
<select name="receive[receipt_date][minute]" id="receive_receipt_date_minute"> 
  <option value="" selected="selected">▼分を選択</option>
      </select>

上が23時(予約可能)、下が19時(予約不可)の応答の内容です。
同じ部分が多いですが、よく見ると予約可能なときには「20~30」のような選択肢が存在しているという違いがあることが読み取れます。

これはつまり、応答内容に「~」が1つ以上含まれているときには、その時間帯は予約可能であると判定することができるということです。

Botの内容を定める

このことから、キャンセル待ちbotは次のよな動作で実現できそうだとわかります。

1. 調べたい時間帯向けのURLの内容を取得する
2. 取得した内容に、「~」が含まれているかを確認する
3-a. 含まれていた場合、何らかの形で通知する
3-b. 含まれていなかった場合、数秒待ってまた1を繰り返す

3-aの通知は、Discordのサーバに飛ばして、気づいた誰かが予約できるようにするのが良さそうです。

それでは、これを実装していきましょう!

Botを実装する

どの言語で作るかを決める

ぶっちゃけどの言語を使っても大差ないので、好きな言語を使うのが良いでしょう。

今回初めてor久しぶりにプログラムを書く場合は、
NodeJS(JavaScript)かPythonあたりが今後他の用途にも知識を活用しやすくて良いかと思います。

今回は、NodeJSを使う場合を解説します。

NodeJSとは

本来ブラウザ上で動くJavaScriptを、PCやサーバのコマンドラインから実行できる環境のことです。
詳しくは、公式ドキュメントに色々(本当に色々!)書いてあるので、興味がある方は読んでみると良いかもしれません。(英語ですが)

NodeJSの実行環境をインストールする

(既にNodeJSをインストール済みの方は、先に進んでください。)

①インストール方法を検索する

「NodeJS インストール」でGoogle検索します。
するとこんな感じに検索結果が表示されます。

「NodeJS インストール」の検索結果

ここで一番上のQiitaのリンクをクリックしがちですが、まずここに落とし穴があります。
Qiitaの記事は、情報が古かったり、(この記事と同じように)余計な情報が多く、かえって分かりづらいことも多かったりします。お気をつけください。

しかし糞記事を踏む経験を積むことも、インターネットリテラシーを上げて情報の氾濫する時代を生き残るためには必要です。
ここは敢えて、一番上の記事をクリックして内容に従っても良いでしょう。

もしあなたが良質な情報にしか触れたくないとお考えであれば、公式っぽい検索結果を選ぶのが良いでしょう。
今回のスクリーンショットだと、3番目がそれになります。

検索結果の3番目のスクリーンショット(NodeJS公式のダウンロードページ)

ただ、この公式っぽいのを探すのにも少しコツが必要です。
こういうソフトウェアの公式ページは、大体.orgドメインを使っているので、それが1つの目印になります。

Google検索結果を状況に応じて適切に取捨選択する能力は、プログラムを書くときに限らず、豊かな人生を送る上で非常に重要です。
プログラミングより先に小学校の授業で取り上げるべき課題だと私は考えています。

②インストールが完了した

さて、あなたは持ち前のインターネットリテラシーを活用し、NodeJSのインストール方法を調べ、
調べた結果に従って、あるいは経験に基づく直観でそれをインストールすることに成功しました。

③うまくインストールできたか確認する

この節の内容は、「node インストール 確認」とGoogle検索することで、自力で探すことが可能です。
もしくは、先程あなたが見つけたインストール手順の最後に含まれているかもしれません。

それでは、うまくNodeJSの環境をセットアップ(=NodeJSをインストール)できたかを確認しましょう。
Windowsを利用している人は、「コマンドプロンプト」を開いてください。

開き方がわからない人、忘れてしまった人は、Googleで調べましょう。
コマンドプロンプト 開き方」で検索するのです。

開いたら、こんな感じの画面が表示されます。

コマンドプロンプトの初期画面

環境が正しくセットアップできていれば、nodeコマンドが実行できるようになっているはずです。 「node -v」とコマンドプロンプトに入力し、Enterキーで実行してみましょう。

node -vの実行結果

画像のように、バージョン情報が表示されればインストールは成功しており、NodeJSが利用可能になっています。

前編の終わり

長くなってしまったので、ここまでを前編とさせていただきます。

後編では、先程まとめた内容を基にプログラムを書いていきます。

1. 調べたい時間帯向けのURLの内容を取得する
2. 取得した内容に、「~」が含まれているかを確認する
3-a. 含まれていた場合、何らかの形で通知する
3-b. 含まれていなかった場合、数秒待ってまた1を繰り返す

*1:HTMLを外部から持ってきて挿入することは、XSS脆弱性を作り込みやすいため一般には推奨されません。