Help us understand the problem. What is going on with this article?

hubotでslackに天気予報を投げる

More than 1 year has passed since last update.

やりたいこと

  • slackにyahoo!天気予報のスクリーンショットを毎日表示させたい

方針

  • hubotにやらせる
  • nightmareでスクリーンショットを撮る
  • 画像はgyazoにアップする
  • pm2でデーモン化する

実装

nodeインストール

nodebrewを使用します。
8系を選んだのはなんとなくです。

nodebrew ls-remote
nodebrew install v8.11.3
nodebrew use v8.11.3
node -v

hubotインストール&セットアップ

npm i -g hubot yo generator-hubot coffee-script

mkdir slack_hubot
cd slack_hubot
yo hubot

あとでpm2使ってデーモン化するとき用に
bin/hubot を bin/hubot.sh にリネームしておきます。
参考1
参考2

mv bin/hubot bin/hubot.sh

nightmareインストール

npm i coffee-script
npm i electron
npm i nightmare

nightmareが使用しているerectronのために
xvfbを用意しておきます。

sudo yum -y install gtk2
sudo yum -y install libXScrnSaver
sudo yum -y install GConf2

sudo yum -y install xorg-x11-server-Xvfb

sudo yum -y install xorg-x11-server-Xorg xterm
sudo yum -y install xorg-x11-drv-vesa xorg-x11-drv-evdev xorg-x11-drv-evdev-devel

そのほかインストール

npm i gyazo-api
npm i cron

スクリプト

script/weather.coffee
# Description:
#   weather.
#

Nightmare = require 'nightmare'
Gyazo = require 'gyazo-api'
cron = require('cron').CronJob

url = 'https://weather.yahoo.co.jp/weather/13/4410.html'
filename = "/tmp/_weather.png"
client = new Gyazo(process.env.GYAZO_TOKEN)

module.exports = (robot) ->
  job = new cron '0 0 10 * * *', () =>
    nightmare = new Nightmare({ show: true })

    nightmare
      .viewport(1000,1000)
      .goto(url)
      .wait("body")
      .evaluate ()=>
        rect = document.querySelector('.forecastCity').getBoundingClientRect()
        return {
          left:   Math.round(rect.left)
          top:    Math.round(rect.top)
          right:  Math.round(rect.right)
          bottom: Math.round(rect.bottom)
          width:  Math.round(rect.width)
          height: Math.round(rect.height)
        }
      .then (rect)=>
        return nightmare
          .screenshot(filename, {
            x: rect.left,
            y: rect.top - 38,
            width: rect.width,
            height: rect.height + 38
          })
          .end()
      .then () =>
        client.upload(filename)
          .then (res) =>
             robot.send {room: "random"}, "東京の天気:" + res.data.permalink_url
  job.start()

動作テスト

テスト前にスクリプトのcron設定は
job = new cron '0 * * * * *', () => などにしておいて下さい。

export HUBOT_LOG_LEVEL=debug
export HUBOT_SLACK_TOKEN=xxxxxxxxxxxxxxxxxxxxxxxx
export GYAZO_TOKEN=xxxxxxxxxxxxxxxxxxxxxxxx

xvfb-run ./bin/hubot.sh -a slack -n [bot名]

#randomにこんな感じの絵が表示されれば成功です。

slack.png

pm2を使ってデーモン化する

このままだと
コンソールを落とすとスクリプトが止まってしまうので
pm2を使用します。

npm i -g pm2

pm2 start --interpreter xvfb-run -f ./bin/hubot.sh -x --name [pm2プロセス名] -- -a slack -n [bot名]

簡単な補足

  • 毎朝10時にpostされます。
  • .forecastCity が天気予報部分に当たってるstyleです。38というマジックナンバーは「今日明日の天気」分の高さです。
  • styleに対して getBoundingClientRect() して切り出し位置を算出しているので、yahoo!天気予報がstyle名変えたりすると対応が必要になります。

激闘の記録

  • 最初はcentos6上で実装しようとしていたが、electronが動作しないことが判明
  • nightmare1.x系だとelectronを使用しないので、そちらで実装しようとしたが、screenshotを行う時にcropができなかったので、諦めてcentos7系に移行
  • pm2上でxvfb-runさせる方法にたどり着くまでの長く険しい道のり

あとがき

「こうすればもっと簡単にできる」とか
あれば是非教えて下さるとうれしいです。

snbk
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away