ワクチン予約のキャンセル通知システム作ってみた
目的!
- コロナワクチン予約をキャンセル待ちしたい!
使ったもの
やったこと
予約はいっぱいだったので、たまにキャンセルが出て一瞬予約できるっぽい > それを検知してみる! ワクチン予約サイトを定期的にチェックして、空きが出たらslackに通知する仕組みを作る!
準備
使った環境などを雑に並べる
ざっくり処理の抜粋&説明
※とりあえず通知まで行くために、エラー処理やsleep処理はだいぶ適当
headlessブラウザで実行
option = Options()
option.add_argument('--headless')
driver = webdriver.Chrome(chrome_driver_path, options=option)
driver.get(target_url)
自分のワクチン番号&パスワードを使ってログイン(selenium)
number = driver.find_element_by_css_selector("input[type=\"tel\"]")
number.send_keys(coupon_number)
sleep(1)
password = driver.find_element_by_css_selector("input[type=\"password\"]")
password.send_keys(passwd)
sleep(1)
driver.find_element_by_css_selector("input[type=\"checkbox\"]").click()
sleep(1)
driver.find_element_by_css_selector("button[type=\"submit\"]").click()
sleep(3)
予約サイトで予約可能な会場の件数を取得(速度はいらないので、そのままselenium)
driver.find_element_by_xpath("//*[text()=\" 新規予約\"]").click()
sleep(1)
driver.find_element_by_xpath("/html/body/div[1]/div/div[2]/div/div/button[1]").click()
sleep(2)
driver.find_element_by_css_selector("input[type=\"checkbox\"]").click();
sleep(3)
element = driver.find_element_by_class_name("page-department-search_nav-header__count")
result = re.sub(r"\D", "", element.text)
slack通知
- slackワークスペース設定で「Incoming Webhook」を追加してWebhookURLをコピー
- slackwebを使って通知(めっちゃ簡単に通知できた!)
import slackweb
…
slack = slackweb.Slack(url=slack_webhook_URL)
if result != "0":
print(result);
slack.notify(text="<!channel> 空いてるよ!!!")
else:
print("空いてなかったよ")
定期実行
プログラムの定期実行はなんとなくmacのcrontabを利用!(1分ごとに実行) 通知が来たら素早く予約サイトにアクセスして予約完了!
詳細コードは↓ GitHub - kyamada23/covid19itami-vaccine-check
詰まったところなど
crontabの環境変数問題
crontabで定期実行するも全然動いてくれない。 crontabではPATHが全然通ってなくてpythonが動いていないっぽい ↓を参考に解決!
【保存版】cronでPython3を定時実行する方法&注意すべき4つのポイント | たぬハック
定期実行が途中で止まる問題
1回1回seleniumでブラウザを起動しっぱなしで、ブラウザが溜まり続けてたのが問題だった
ちゃんと終わりましょう
driver.quit()
↓参照
Selenium - かならずwebdriverを閉じる - Kobe's Public Scrapbox
感想
2,3時間で10件以上キャンセルは出てたっぽいので、F5アタックでも普通に予約できたかも。 でも作った通知システムで予約できたことですごい満足
ちなみに今回は伊丹市のワクチン予約サイトでしてみました。 ワクチン打つと伊丹消滅するらしい コロナワクチン予約システム
GoToEatひょうごが使える店をgoogle mapにしてみた(python/beautifulsoupでwebスクレイピング)
目的!
go to eatひょうごキャンペーンの食事券が使える店を地図で見たい! gotoeat-hyogo.com
webスクレイピングをやってみたい
どっちかというと2番目の目的が先で、何かないかなと思った時に1が出てきた感じです。 python(JupyterNotebook)を使って作ってみました。
出来たこと
go to eatひょうごキャンペーンの食事券が使える店の情報を読み込んで、google mapに読み込むcsvファイルを作成!
作ったgoogleマップがこちら↓ www.google.com
出来なかったこと
googleマップに自動で読み込みは出来ず、手動読み込みに・・・
自動操作はgoogleに禁止されているようです。
準備
使った環境などを雑に並べる
- mac catalina : 10.15.7
- chrome : 86
- python : 3.9.0
- JupyterNotebook : 6.1.4
- requests:データ取得ライブラリ
- BeautifulSoup:データ抽出ライブラリ
※なんとなくAnacondaは使わず、適当にpip3でインストール
ざっくり処理の抜粋&説明
requestsで、キーワード(兵庫県の市町村ごとに)から食事券が使える店を検索
import requests
from bs4 import BeautifulSoup as bs4
…
#検索ページのURL、検索ワード、ページ数から結果のページ情報を取得
url ="(検索ページのURL)"
param = {"keyword" : (検索ワード), "page" : (検索ページ数)}
res = requests.get(url, param)
主にbeautifulsoupのselectを使って 検索結果&詳細ページから店の情報(店名、住所、電話番号、webサイト、営業時間)を抽出
#ページ解析
search_result = bs4( res.text, "html.parser")
#店舗情報のエリアを取得(1ページで10件ぐらいあったので、リストで取得して順番に処理)
store_list = search_result.select("div.search-results-list-box")
for store in store_list:
#店名
store_name = store.select("p.search-results-list-name")[0].text
#住所
store_address = store.select("p.search-results-list-p01")[0].text.replace(" ", "").replace("\n", "").replace("住所:", "")
...
あとは各店舗の情報を1行にしてcsvに出力
import csv csv_filename = "goto_eat_" + search_word + ".csv" f = open(csv_filename, mode = 'w', encoding='utf-8', errors = 'ignore') writer = csv.writer(f, lineterminator = '\n') csv_list = [] csv_list.append(store_name) csv_list.append(store_address) … writer.writerow(csv_list)
詳細コードは↓ https://github.com/kyamada23/goto_eat_hyogo
詰まったところなど
JupyterNotebookがでなんか起動しない問題
jupyter notebookコマンドを実行すると、自動でchromeのページが開いて↓のページが表示されるんですが、
「click here to go to Jupyter.」をクリックしても全然反応してくれない・・・
ターミナルにこれをコピーしろみたいなのがあったのでとりあえずそれ(↓の一番下だけ)をコピペして表示されました。
To access the notebook, open this file in a browser:
file:///Users/…
Or copy and paste one of these URLs:
http://localhost:8888/?token=…
or http://127.0.0.1:8888/?token=…
隣の要素取得がしっくりこない
<th>定休日</th> <td>毎週火曜日</td>
上記で定休日の要素を見つけて、その隣の情報を取得しようとするときに
(定休日の要素).next_sibling だと取得できず(改行が取得されるから?)
(定休日の要素).next_sibling.next_sibling と2回繰り返すと取得できた。
go to eatひょうごの食事券アクセス殺到問題
食事券を購入する時にアクセスが殺到して、全然ページが開かずに買うまでにめちゃめちゃ時間がかかりました。 11/10分からは抽選になっているみたいです。
JupyterNotebook
気軽に実行するには便利なんですが、ファイル形式が独自のものになるので、git管理すると分かりづらい感じがしました。 終わったらpython形式に出力したらいいのかも?
感想
覚えたwebスクレイピングを試してみるにはいい素材だったかなと思います。
他の都道府県のもやってみると面白いかも
ちなみに企業が作った地図検索サービスもあります!(あるかなと思っていたけど、作るまではあえて調べなかった)
SQLの準備/実行/読み込み(prepare/execute/fetch)メモ -PHP-
phpのPDO(PHP Data Objects)のかなり簡単なメモです。
メソッド(prepare, execute, fetch)を実行してどんな結果が返ってくるのかあたり。
クエリの作成(PDO::prepare)
実行例:
$dbh->prepare($sql)
クエリーの文(PDOStatementオブジェクト)が返ってくる
基本的に何が入っててもそのまま文にして返してくるっぽい。SQL文として間違っていてもエラーにはならない。
※失敗したらfalseを返すか、例外を投げるっぽいが、どういう時にそうなるのか・・・
参照: https://www.php.net/manual/ja/pdo.prepare.php
クエリの実行(PDO::execute)
実行例:
$dbh->execute($data)
クエリの実行が成功した場合はtrueを返す
クエリの実行が失敗した場合はfalseを返す
※SELECTの結果のレコードが0件の場合もfalse?と思われる
参照: https://www.php.net/manual/ja/pdostatement.execute.php
クエリの結果取得(PDO::fetch)
実行例
$result = $stmt->fetch(PDO::FETCH_ASSOC);
成功した場合、結果のレコードを連想配列として返す(FETCH_ASSOCの場合)
失敗したばい、falseを返す
連想配列として返ってくるので、最初の値を取得する場合はarray_shiftやcurrentなどで指定したり、キーを指定したりする($result['(キー名)'])
https://www.php.net/manual/ja/pdostatement.fetch.php
おまけ
取得した結果を判定するのに参考にしてるページ
empty(), is_null(), isset()の結果一覧:
https://php.net/manual/ja/types.comparisons.php