Yahoo!ショッピングでお目当の商品があったら通知するPythonコード

Yahooショッピングで訳あり缶コーヒーを買うのですが、訳ありというだけあって数が少ないのかすぐに無くなることもあるので、お目当の商品があったら通知が来るPythonコードを書きました。
### 環境

* Python3.7

### 事前準備

次の2つを利用するための準備をします。

* [Yahoo!ショッピングAPI](https://developer.yahoo.co.jp/webapi/shopping/)
* [LINE notify API](https://notify-bot.line.me/ja/)

商品の情報を取得するために[Yahoo!デベロッパーネットワーク](https://developer.yahoo.co.jp/start/)に登録し[Yahoo!ショッピングAPI](https://developer.yahoo.co.jp/webapi/shopping/)を利用します。登録後に、API利用に必要なアプリケーションIDを登録します。今回利用するAPIは[商品検索API](https://developer.yahoo.co.jp/webapi/shopping/shopping/v1/itemsearch.html)です。様々な検索条件で商品を検索した結果を取得することができます。
※Yahoo!デベロッパーネットワーク、Yahoo!ショッピングAPIのガイドやマニュアルは利用前に目を通しましょう。

LINE notify APIは検索結果を通知するのに利用します。登録後に、通知に必要アクセストークンを発行してメモしておきます。

### コード

yahoo_shop_notifier.py

```python3
import re
import bs4
import yaml
from urllib import request, parse


class YahooShopNotifier(object):

    def __init__(self):
        self.soup_result = None
        # 検索や通知に必要なプロパティの読み込み＆設定
        with open('./config.yml', 'rt') as fp:
            text = fp.read()
        property_dict = yaml.safe_load(text)['yahoo_shop_notifier']
        self.YAHOO_SHOP_SEARCH_API = property_dict['yahoo_shop_search_api']
        self.YAHOO_APPID = property_dict['yahoo_appid']
        self.QUERY = property_dict['query']
        self.PRICE_FROM = property_dict['price_from']
        self.LINE_NOTIFY_API = property_dict['line_notify_api']
        self.LINE_NOTIFY_TOKEN = property_dict['line_notify_token']

    def get_search_result(self):
        # 検索条件の設定
        # 参考: https://developer.yahoo.co.jp/webapi/shopping/shopping/v1/itemsearch.html
        params = parse.urlencode({'appid': self.YAHOO_APPID,
                                  'query': self.QUERY,
                                  'price_from': self.PRICE_FROM})
        req = request.Request(self.YAHOO_SHOP_SEARCH_API + params)
        page = request.urlopen(req)
        html = page.read().decode('utf-8')
        self.soup_result = bs4.BeautifulSoup(html, "lxml")

    def need_notice(self):
        if self.soup_result.find('hit').get('index') is not None:
            if int(self.soup_result.find('hit').get('index')) > 0:
                # 検索結果の数が0より大きければ通知をする
                return True
        else:
            return False

    def _build_notification_message(self):
        # 対象商品のURLを通知メッセージに追加する
        product_urls = ''
        for link in self.soup_result.find_all('url', text=re.compile('.html$')):
            product_urls += link.text + '\n'
        return product_urls + '以上'

    def notice_to_line(self):
        message_base = '希望の商品アリ!'
        product_urls = self._build_notification_message()
        message = '\n' + message_base + '\n' + product_urls
        payload = {'message': message}
        headers = {'Authorization': 'Bearer ' + self.LINE_NOTIFY_TOKEN}
        response = request.Request(self.LINE_NOTIFY_API, data=parse.urlencode(payload).encode('utf-8'),
                                   headers=headers, method='POST')
        with request.urlopen(response) as res:
            res.read()


def main():
    notifier = YahooShopNotifier()
    notifier.get_search_result()
    if notifier.need_notice():
        notifier.notice_to_line()


if __name__ == '__main__':
    main()
```

設定ファイル: config.yml

```yaml
yahoo_shop_notifier:
  yahoo_shop_search_api: 'http://shopping.yahooapis.jp/ShoppingWebService/V1/itemSearch?'
  yahoo_appid: '<your_app_ip>'
  query: '缶コーヒー 訳あり 24本'
  price_from: 1000
  line_notify_api: 'https://notify-api.line.me/api/notify'
  line_notify_token: '<your_line_notiry_token>'
```


### 通知結果

こんな感じで通知が来ました。
自動実行設定して一定時間おきにチェックし通知を受け取れるようにしています。

<img width="375" alt="IMG_0746.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/434323/49ea07ea-f237-efa6-f9c2-3d7ccd053b8e.jpeg">


<img width="375" alt="IMG_0748.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/434323/e830c082-1964-4725-a657-e463103d438d.jpeg">