【Python】ユニクロの値下げ商品をチェックする

機能

ユニクロの値下げ商品をチェックするPythonプログラムです。

チェックしたい商品を登録し、登録した商品が値下げしたらLINEに通知します。

機能一覧

  • 登録(save):商品URLを元に商品名と価格を登録する
  • 削除(delete):商品名を元に登録されている商品を削除する
  • 表示(show):登録されている商品一覧を表示する
  • チェック(check):登録時の価格と現在の価格を比較し、値下げしている商品をLINEに通知する

サンプル動画

youtu.be

プログラム

#! python3
# 機能
#  ユニクロの値下げ商品をチェックする
# 使い方
#  1.Pythonを実行する
# 実行コマンド
#  python uniqlo_discount_checker.py save URL
#  python uniqlo_discount_checker.py delete 商品名
#  python uniqlo_discount_checker.py show
#  python uniqlo_discount_checker.py check
#  python uniqlo_discount_checker.py save "https://www.uniqlo.com/jp/ja/products/E425974-000/00?colorDisplayCode=02&sizeDisplayCode=004"

import os
import re
import sys
import time
import shelve
from selenium import webdriver
import chromedriver_binary
sys.path.append(os.path.abspath("../.."))
from sns.line_notify import line_notify

# URLから商品名と価格を取得する
def fetch(browser, url):
    browser.get(url)
    time.sleep(1)

    item_selector = ".uq-uikit-template-pdp__main h1"
    item = browser.find_elements_by_css_selector(item_selector)[0].text
    price_selector = ".uq-uikit-template-pdp__main .uq-uikit-price-text"
    price = browser.find_elements_by_css_selector(price_selector)[0].text
    time.sleep(1)

    return item, price


# 商品を登録する
def save(url, shelf):
    browser = webdriver.Chrome()
    item, price = fetch(browser, url)
    shelf[item] = {"price": price, "url": url}
    print("商品を登録しました。")
    print("商品:{}".format(item))
    print("価格:{}".format(price))


# 商品を削除する
def delete(item, shelf):
    if item in shelf:
        del shelf[item]
        print("商品を削除しました。")
    else:
        print("商品は登録されていません。")


# 商品一覧を表示する
def show(shelf):
    for item in shelf.keys():
        print("商品:{} 価格:{}".format(item, shelf[item]["price"]))


# 価格を数値型に変換する
def to_int(price):
    return int(re.sub(r"¥|,|\D", "", price))


# 価格をチェックする
def check(shelf):
    browser = webdriver.Chrome()

    messages = ""
    for item in shelf.keys():
        _, price = fetch(browser, shelf[item]["url"])
        saved_price = shelf[item]["price"]
        if to_int(price) < to_int(saved_price):
            messages += "商品:{}\n登録価格:{}\n現在価格:{}\n".format(item, saved_price, price)

    if messages != "":
        line_notify.notify("以下の商品が値下げしました。\n" + messages)
        print("値下げ商品をLINEに送信しました。")
    else:
        print("値下げ商品はありませんでした。")


# 引数ごとの処理を実行する
os.makedirs("uniqlo", exist_ok=True)
with shelve.open("uniqlo/uniqlo") as shelf:
    if len(sys.argv) == 2:
        if sys.argv[1].lower() == "show":
            show(shelf)
            sys.exit()
        elif sys.argv[1].lower() == "check":
            check(shelf)
            sys.exit()
    elif len(sys.argv) == 3:
        if sys.argv[1].lower() == "save":
            save(sys.argv[2], shelf)
            sys.exit()
        elif sys.argv[1].lower() == "delete":
            delete(sys.argv[2], shelf)
            sys.exit()

print(
    """使い方:
python uniqlo_discount_checker.py save URL
python uniqlo_discount_checker.py delete 商品名
python uniqlo_discount_checker.py show
python uniqlo_discount_checker.py check
"""
)

LINE通知には以下で作成したモジュールを使用しています。

stmtk358.hatenablog.com

注意点として、Pythonは実行ファイルがあるフォルダ配下にしかパスが通らないようです。

私の環境ではプログラムごとにフォルダを分けているため、uniqlo_discount_checker.pyを実行する際にline_notify.pyが参照できません。

..\Python\Scraping\uniqlo_discount_checker\uniqlo_discount_checker.py
..\Python\sns\line_notify\line_notify.py

この問題を回避するため、sys.pathにPythonフォルダ(../..)を追加して、snsフォルダ配下も参照できるようにしています。

sys.path.append(os.path.abspath("../.."))
from sns.line_notify import line_notify

使い方

  1. Pythonを実行する

実行コマンド

python uniqlo_discount_checker.py save URL
python uniqlo_discount_checker.py delete 商品名
python uniqlo_discount_checker.py show
python uniqlo_discount_checker.py check

seleniumとchromedriver-binaryをインストールしていない場合は以下のコマンドを実行して下さい。

pip install selenium
pip install chromedriver-binary

ドライバーのバージョンによっては実行エラーになる場合があります。

また、ログを抑制する方法などもありますので、以下を参考にして下さい。

stmtk358.hatenablog.com

参考文献

www.oreilly.co.jp

var.blog.jp