LINE Botの開発②
結局
ちょっとLINE Botを触ってみたけれども、なんだかんだでLambdaにPython乗っけて作るのが楽そうだな…という結論。
構成
で行く予定。
主に実装する範囲
LINE Botの応答部分に関しては色々とLambdaを試しているうちにほぼできたので、特に問題なし。
ただ、RDSからデータをSELECTしてこなければならないので、そこのつなぎ方だけは検証する。
スクレイピング部分に関してはある程度ソースができているので、それをLambda環境で動かすような形にする。
Lambdaを使ってみた感想
デバッグがしづらいので、Lambdaにソースおいて動かしてみて…の繰り返しだった。
何かやりやすいデバッグ方法があるんですかね…?
LINE Botの開発
こんなことをするつもり
あるテーマに基づき、複数のサイトから(問題のない範囲で)スクレイピングを行い情報収集をし、それを一覧にまとめるようなリンク集サイトを作ろうかな…と思ったのだけれども…
どうにも「問題のない範囲で」取ってこようとすると取得できる情報があまりリッチにならない。
検索機能をつけるつもりではいたものの…わざわざサイトにする必要ある?という気持ちに。
なので、LINE Botで検索ワードを投げたらその結果を返すようなBotを作ってしまえば良いのではないかという結論に至る。
今のところの構想
技術スタックは以下をとりあえず考えている。
仰々しい感じにはなるが、DRFを触っときたいという気持ちがあるのでまずは上記の構成で。
後々はLambdaにのせかえてサーバレス構成にして費用を抑えたい…。
勉強半分、自分がほしいBotの開発目的半分、という形で進める。
現状
とりあえずDjangoの環境を立てて、スクレイピング対象のページ1個目のHTMLを抜いてきてローカルで仮で稼働、
BeautifulSoupを使ってスクレイピングしDBに記録するところまでは実施済み。
レンタルスペース予約のシステムをつくった
レンタルスペース予約のシステムを作った
いろいろとDjangoがらみの話を書いていましたが、やっと本番運用が始まるので。
以下のようなシステムを作りました。
仲間内で運営しているレンタルスペースの予約用システムです。
環境
フレームワーク:Django、Bootstrap4、jQuery サーバ:AWS EC2 DB:MySQL
機能
- スペースの予約登録
時刻や用途、支払方法などを設定し、予約登録が可能です(当たり前)。
予約のリクエストがあった際には、メールアドレスにユニークなURLを送りつけて、そのURLを踏むことで本予約として受け付ける形式にしています。
あまり会員登録などはさせたくなかった反面、不正な予約がたまりすぎて欲しく無いなというところもあり、そんなフローにしています。
- スペースの予約をGoogle Calendarと同期
DjangoでGoogle Calendarへアクセス① - Livegram
DjangoでGoogle Calendarへアクセス② - Livegram
ここらへんでも触れていますが、予約を入れたらGoogle Calendarに勝手に入るので見ればわかり、
逆に都合の悪い日や、このシステムを介さない予約はGoogle Calendar側に予定を入れてしまえば同期されるため、バッティングを防げる仕組みにしています。
- Google reCaptcha V3
不正予約防止の一貫。入力の際にreCaptchaを噛ませてます。
- Slackへの予約があった際の通知
利用者の方がメールに送られたURLを踏んだ時点(本予約が成立した時点)でSlackへ予約が入った通知をします。
その通知をみて、詳細な連絡を行い実際に使ってもらう、という流れになります。
- クレジットカード決済
ここでも触れていますが、予約が入ったあと決済を行うような仕組みも実装しました。
クレカ決済を選択した場合は、飛んでくるメールが他の決済と異なるものとなり、決済用URLが表示される形です。
そのURLを踏んでから決済を行うと、Slackに通知が飛んでくる感じです。
あと、これに付随して金額計算のロジックも組みましたが、当然「営業時間外」という概念や「30分単位は切り上げ」などの概念もあるので、ちょっとそこは面倒でした。
作ってみて
必要だったので作ってみたのですが、開発期間は約2.5ヶ月(4~6月上旬が中心、6月後半〜8月は諸事情あり一時停止)。
土日を3〜4時間ずつくらい当てたような感じです。結構かかったな。
中身としては普通に登録・リスト表示するだけなのですが。
追加機能の予定
レンタルスペース貸しなので、スマートロックとも連携できれば強いです。予約が入ったら、管理画面にログインして、ボタン押したら鍵が発行できる、みたいな。
それを達成できそうなスマートロックはおそらくSESAMEかなと。今はQrioで運用しているので、買い替えが必要です。
買い替え代金をこのレンタルスペースが稼いでくれたらな、とか思います。
やろうと思っていることのメモ書き
自分のスキルに対する改善を考えている
一応、ITエンジニアとして働いてはいるけれども、常にスキルに対し不安を抱いているし、何をどう進めていけばよいのかわからなくなり足を止めてしまう。解消方法をGoogleに求めて「やってみようかな」と思うことは多々あれど、それで止まってしまっているので、以下に書いた項目を潰して行こうと思う。
1日1時間程度は少なくとも割きながら…。
やること
- オライリーのPython本を読み終える
- 世界でもっとも強力な9のアルゴリズムを読み終える
- 思考する機械コンピュータを読み終える
- もう1個アプリを作る
- LeetCodeを週に2〜3個ずつは対応し、Easyを完了させる
- Udemyで買った講座を終える
とりあえずは上記を完了させる。 それまでは惑わないよう、余計な情報は入れない。
とりあえずは上記に
Djangoの開発環境整備(venv)
環境を立てた
新しいWebアプリのため、ローカルに環境を立てたのでその時のメモ
細かいバージョン指定とかは端折っている
とりあえず以下の形で作った
とりあえずDjangoが動くまで
- venv用フォルダを作り
cd
で移動 python3.7 -m venv .
source bin/activate
python -m pip install --upgrade pip
pip install django
django-admin startproject [appname]
してcd
で移動python manage.py migrate
touch requirements.txt
pip freese > requirements.txt
VSCodeでデバック実行できるようにする
前提:PythonのExtentionを入れる 1. インタープリターの設定
settings.py、urls.py、wsgi.py、asgi.pyの外出し(機能単位で設定しないでよくなるように)
- configフォルダを作って以下ファイルをアプリから移動
asgi.py settings.py wsgy.py
- 以下ファイルをconfig配下に新規作成
local_settings.py urls.py
urls.py
を編集
config側
from django.contrib import admin from django.urls import include, path urlpatterns = [ path('admin/', admin.site.urls), ]
app側
from django.contrib import admin from django.urls import path urlpatterns = [ ]
asgi.py
とwsgi.py'と
manage.py`を編集
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'appname.settings') ↓ os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings')
- settings.pyを編集
★locals_settings.pyの読み込み importのあとすぐ実行 try: from .local_settings import * except ImportError: pass ★urls.pyの読み込み元変更 ROOT_URLCONF = 'config.urls' ★wsgi.pyの読み込み元変更 WSGI_APPLICATION = 'config.wsgi.application'
- 以下項目をsettings.pyからlocal_settings.pyに移植
・from pathlib import Path ・DEBUG ・ALLOWED_HOSTS ・SECRET_KEY ・BASE_DIR ・DATABASES
- 動作確認をして問題なければOK
上記でできるフォルダ構成
workspace ├ .vscode │ └ launch.json ├ config │ ├ asgi.py │ ├ local_settings.py │ ├ settings.py │ ├ urls.py │ └ wsgi.py ├ app │ ├ __init__.py │ └ urls.py ├ db.sqlite3 ├ managed.py └ requirements.txt
今日のLeetCode(8/20)
設問
「Number of Good Pairs」
[1,2,3,1,1,3]
みたいな配列num
について
nums[i] == nums[j]'かつ
i < j'となるペアの数を出す
私の書いたコード
import copy class Solution: def numIdenticalPairs(self, nums: List[int]) -> int: res = 0 for i,j in enumerate(nums): copy_nums = copy.copy(nums) del copy_nums[0:i+1] res += copy_nums.count(j) return res
i < jなので、iよりindexが若いものを消したListを作ってcountしていく。
最初はcopy_nums = nums
と書いていたが、ちゃんとコピーしないともとのnums
からも消されていってしまう…。
ほかのコードを見て
あれ、なんかみんな結構分量書いてる…?
class Solution: def numIdenticalPairs(self, nums): goodPairs = 0 for i, value in enumerate(nums): for j, value2 in enumerate(nums): if i < j and value == value2: goodPairs += 1 print(goodPairs, i, value) return goodPairs
上は単純にnum[i]'と
num[j]'をそれぞれ取ってきて比較しているみたい
ループ回数多いけど忠実な気はする。
class Solution: def numIdenticalPairs(self, nums: List[int]) -> int: usedNums = {} num = 0 for i in nums: if i in usedNums: if usedNums[i] == 1: num +=1 else: num += usedNums[i] usedNums[i] +=1 else: usedNums[i] = 1 return num
listの頭から順にdicに入れていき、同じ番号が入ってきたらdic側をカウントアップして、過去に出てきた回数分numに足していくのね…なるほど…。
今日のLeetCode(8/18)
設問
「Kids With the Greatest Number of Candies」
[2,3,5,1,6]
みたいな配列candies
と任意の値extracandies
が与えられ、
extracandies
を配列の数字にうまく分配したら、配列の各数字が配列内の最大数になるかどうか?という問題。
配列が「各子供に与えられたキャンディ」でextracandiesはそのまま「追加のキャンディ」
追加のキャンディをうまく渡して、それぞれの子供はキャンディ保持数が1位になる可能性はあるか?ということ。
私の書いたコード
class Solution: def kidsWithCandies(self, candies: List[int], extraCandies: int) -> List[bool]: result = [] sortcandies = sorted(candies, reverse=True) for i in candies: maxcandy = i + extraCandies result.append(maxcandy >= sortcandies[0]) return result
最大値を取りうるかどうかだけ見ればいいので、extraCandiesをすべて渡すケースを考える。 解いたあとにして思うが、初期値が最大のやつは回す必要すらない…なぁ
ほかのコードを見て
いやまぁ大きな差はなかったけど、sortedじゃなくて普通にmaxつかってるよね…。
あと、実は詰まって調べたのが、
class Solution: def kidsWithCandies(self, candies: List[int], extraCandies: int) -> List[bool]: result = [] sortcandies = sorted(candies, reverse=True) for i in candies: maxcandy = i + extraCandies if maxcandy >= sortcandies[0]: result.append(bool('True')) else: result.append(bool('False')) return result
みたいなのを試しに書いたら、全部Trueになってしまうという現象が…。
どうもこれが関係ありそうなので、ちょっと明日以降も調べよう。