Created
August 6, 2017 15:45
Ploom の予約を受け付けている店舗を検索し、Slackで通知します。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- coding: utf-8 -*- | |
""" | |
Ploom の予約を受け付けている店舗を検索し、Slackで通知します。 | |
実行コマンドサンプル | |
SLACK_TOKEN=xoxp-xxxx... \ | |
SLACK_CHANNEL_FOUND=@your_id \ | |
SLACK_CHANNEL_LOG=@your_id \ | |
SLACK_MENTION_ID=@UXXXXX \ | |
PLOOM_ACCOUNTUID=id \ | |
PLOOM_PASSWORD=password \ | |
PLOOM_PREFECTURE=東京都 \ | |
PLOOM_CITY=新宿区 \ | |
PLOOM_SHOP='Ploom Shop 新宿三丁目店' \ | |
python ploom.py | |
実行時に必要な環境変数 | |
SLACK_TOKEN: Slack の token | |
SLACK_CHANNEL_FOUND: 店舗が見つかった時に送る Slack のチャンネル | |
SLACK_CHANNEL_LOG: 検索ログを送る Slack のチャンネル | |
SLACK_MENTION_ID: メッセージにつけるメンション | |
PLOOM_ACCOUNTUID: 「JTスモーカーズID」もしくはメールアドレス | |
PLOOM_PASSWORD: パスワード | |
PLOOM_PREFECTURE: 予約を受け付けている店舗がある都道府県(現状 '東京都' もしくは '福岡県' のみ) | |
任意指定の環境変数 | |
PLOOM_CITY: 予約を受け付けている店舗がある市区町村('港区' などの市区町村名。未指定の場合には 'すべて選択' 扱い) | |
PLOOM_SHOP: 店舗を限定したい場合に店舗名を指定 | |
実行に必要なpythonモジュール | |
pip install selene --pre | |
pip install slackclient | |
""" | |
import os | |
import traceback | |
from selene import config | |
from selene.browsers import BrowserName | |
from selene.api import * | |
from selenium import webdriver | |
from slackclient import SlackClient | |
SLACK_TOKEN = os.environ['SLACK_TOKEN'] | |
SLACK_CHANNEL_LOG = os.environ['SLACK_CHANNEL_LOG'] | |
SLACK_CHANNEL_FOUND = os.environ['SLACK_CHANNEL_FOUND'] | |
SLACK_MENTION_ID = os.environ['SLACK_MENTION_ID'] | |
PLOOM_ACCOUNTUID = os.environ['PLOOM_ACCOUNTUID'] | |
PLOOM_PASSWORD = os.environ['PLOOM_PASSWORD'] | |
PLOOM_PREFECTURE = os.environ['PLOOM_PREFECTURE'] | |
PLOOM_CITY = os.getenv('PLOOM_CITY', 'すべて選択') | |
PLOOM_SHOP = os.getenv('PLOOM_SHOP', None) | |
SLACK_METHOD = 'chat.postMessage' | |
PLOOM_URL = 'https://www.ploom.jp/tech/reserve/' | |
def main(): | |
""" | |
1. 検索開始を os.environ['SLACK_CHANNEL'] に通知 | |
2. os.environ['PLOOM_ACCOUNTUID'] / os.environ['PLOOM_PASSWORD'] でログイン | |
3. os.environ['PLOOM_PREFECTURE'] 及び os.environ['PLOOM_CITY'] で検索 | |
4. 検索結果を os.environ['SLACK_CHANNEL'] に通知 | |
""" | |
slack_client = SlackClient(SLACK_TOKEN) | |
slack_client.api_call( | |
SLACK_METHOD, | |
channel=SLACK_CHANNEL_LOG, | |
text='Ploom の予約を受け付けている店舗を検索しています...\n都道府県 `{0}` 市区町村 `{1}` 店舗名 `{2}`' | |
.format(PLOOM_PREFECTURE, PLOOM_CITY, PLOOM_SHOP) | |
) | |
try: | |
# open ploom site | |
config.browser_name = BrowserName.PHANTOMJS | |
config.desired_capabilities = webdriver.DesiredCapabilities.PHANTOMJS | |
browser.open_url(PLOOM_URL) | |
# login | |
s('input[name="ACCOUNTUID"]').set_value(PLOOM_ACCOUNTUID) | |
s('input[name="PASSWORD"]').set_value(PLOOM_PASSWORD) | |
s('input[type="SUBMIT"]').click() | |
# confirm | |
s('input[type="checkbox"]').click() | |
s('input[type="submit"]').click() | |
# select prefecture | |
s(by.xpath('//label[text()="上記内容を確認しました"]')).click() | |
s(by.xpath('//label[text()="{0}"]'.format(PLOOM_PREFECTURE))).click() | |
s(by.xpath('//a[text()="予約を申し込む"]')).click() | |
# select city | |
s(by.xpath('//label[text()="{0}"]'.format(PLOOM_CITY))).click() | |
s(by.xpath('//a[text()="店舗選択へ"]')).click() | |
# list | |
message = None | |
if PLOOM_SHOP is None: | |
shops = ss(by.xpath('//a[contains(@class,"is-gold")]/../../..')) | |
if shops.size() > 0: | |
message = u'<{0}> 以下の店舗が予約を受け付けています。 :smile:\n'.format(SLACK_MENTION_ID) | |
for shop in shops: | |
shop_name = shop.s('h2.shop-name').text | |
shop_address = shop.s('p.address').text | |
message += u'店舗名: `{0}`, 住所: `{1}`\n'.format(shop_name, shop_address) | |
else: | |
xpath = '//h2[@class="shop-name"][text()="{0}"]/..//p[@class="submit"]/a[contains(@class,"is-gold")]' | |
# shop = s(by.xpath(xpath.format(PLOOM_SHOP))) | |
# if shop.is_displayed() is True: # is_displayed throws TimeoutException | |
shop = ss(by.xpath(xpath.format(PLOOM_SHOP))) | |
if shop.size() > 0: | |
message = '<{0}> '.format(SLACK_MENTION_ID) | |
message += '`{0}` が予約を受け付けています。 :smile:\n'.format(PLOOM_SHOP) | |
if message is None: | |
slack_client.api_call( | |
SLACK_METHOD, | |
channel=SLACK_CHANNEL_LOG, | |
text='検索条件に該当する店舗は予約を受け付けていませんでした。 :cry:' | |
) | |
else: | |
message += PLOOM_URL | |
slack_client.api_call( | |
SLACK_METHOD, | |
channel=SLACK_CHANNEL_FOUND, | |
text=message | |
) | |
slack_client.api_call( | |
SLACK_METHOD, | |
channel=SLACK_CHANNEL_LOG, | |
text='検索条件に該当する店舗が予約を受け付けています。 :smile:' | |
) | |
except: | |
slack_client.api_call( | |
SLACK_METHOD, | |
channel=SLACK_CHANNEL_LOG, | |
text='<{0}> 店舗検索に失敗しました。 :angry:\n```{1}```' | |
.format(SLACK_MENTION_ID, traceback.format_exc()) | |
) | |
raise | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment