GASでセブンイレブンの今週の新商品をスクレイピングして通知する

普段コンビニでお昼を取らないのですが、最近何度か足を運びまして。
いざ昼食を選ぼうとするとその商品の量に圧倒されます。
さらに驚くべきことに毎週のように新商品がでるんです!
店頭では見分けがつかないので、ネットで追うにしても毎週は大変だぁ…(公式アプリがあるそうですが)

というわけで、毎週更新なら週一回スクリプトを走らせて普段見ているSlackに投げちゃいましょう。

GASは手軽に定期実行が出来ていいですね!

今週の新商品|セブン‐イレブン~近くて便利~

スクリーンショット

対象は
http://www.sej.co.jp/i/products/thisweek/kinki/
です。

image.png

コード

var REGION = '近畿'
var REGIONS = {
  '北海道':      'hokkaido',
  '東北':        'tohoku',
  '関東':        'kanto',
  '甲信越・北陸': 'koshinetsu',
  '東海':        'tokai',
  '近畿':        'kinki',
  '中国・四国':   'chugoku',
  '九州':        'kyushu'
}
var ORIGIN = 'http://www.sej.co.jp'
var NEW_ITEM_DIR = '/i/products/thisweek/'
var NEW_ITEM_URL    = ORIGIN + NEW_ITEM_DIR
var QUERY  = '?page=1&sort=f&limit=100' // sortがf n で新商品 おすすめ なのだが、規則がわからない

var SLACK_INCOMING_URL = 'https://hooks.slack.com/services/~'


// 色彩からなる商標をCMYからRGB変換
// http://www.sej.co.jp/dbps_data/_material_/_files/000/000/019/198/20170301shikisai-sej.pdf
// …しようとしたらかなりかけ離れている気がするのでロゴをスポイトツールでRGB取得します。
var SEVEN_COLOR = [
  '#f58220', // セブンオレンジ
  '#00a54f', // セブングリーン
  '#ee1c23', // セブンレッド
]

function main() {
    var attachments = []

    var html = UrlFetchApp.fetch(NEW_ITEM_URL + REGIONS[REGION] + QUERY).getContentText()
    var items = Parser.data(html).from('<li class="item">').to('</div>\n</li>').iterate()
    for(i=0;i<items.length;++i){      
      var link   = ORIGIN + items[i].match(/<a href="(.+)">/)[1]
      var image  = items[i].match(/src="([^"]+)" alt="商品画像"/)[1]
      var name   = items[i].match(/<div class="itemName">.+">(.+?)<\/a><\/strong>/)[1]
      var price  = items[i].match(/<li class="price">(.+?)<\/li>/)[1]  
      var launch = items[i].match(/<li class="launch">(.+?)<\/li>/)[1]
      var region = items[i].match(/<li class="region">(.+?)<\/li>/)[1].replace(/<\/?em>/g, ' ')
      attachments.push(makeAttachment(link, image, name, price, launch, region, i))
    }
  sendSlack(attachments)
}


function makeAttachment(link, image, name, price, launch, region, i) {
  return {
    color: SEVEN_COLOR[i % SEVEN_COLOR.length],
    title: name,
    title_link: link,
//    image_url: image, // thumb_urlより大きい画像
    thumb_url: image, // 大きな画像は邪魔な場合に。image_urlとお好みで
    fields: [
      {
        title: '値段',
        value: price,
        short: true,
      },
      {
        title: '販売時期',
        value: launch,
        short: true,
      },
      {
        title: '販売地域',
        value: region,
        short: true,
      }
    ]
  }
}

function sendSlack(attachments) {
  var jsonData = {
    username:   '新商品通知BOT',
    icon_emoji: ':711:',
    channel:    '711',
    text: '今週の新商品です',
    attachments: attachments,
  }
  payload = JSON.stringify(jsonData);
  options =
  {
    "method" : "post",
    "contentType" : "application/json",
    "payload" : payload
  };
  UrlFetchApp.fetch(SLACK_INCOMING_URL, options)
}

ライブラリは
Parserを使っています。
Easy data scraping with Google Apps Script in 5 minutes ~ kutil.org
といっても商品をがばっとイテレーターでとってくるのに使って、値だけの取得には正規表現を使用してます。

Slack側はライブラリは使ってません。
Slack API Tokenを用意していなくて、いつもIncoming Webhooksを使いまわしています…。

たまにGASから見てSlackへのfetchがエラーになるのですが(タイムアウト?)Slack側にはちゃんとポストされています。

参考