読者です 読者をやめる 読者になる 読者になる

ほんじゃら堂

めんどくさい仕事をラクにする作業自動化レシピ集

テレビの映画放映情報を定期的にチェックする

clojure IT系・技術系 通知自動化 スクレイピング

f:id:piro_suke:20160722000409j:plain

映画鑑賞は割と好きなのだけど、

なかなか映画館にはいけないし、

DVDを借りてもレンタル中に観る時間が取れるとは限らないし、

ということでもっぱらテレビで面白そうな映画をやってたら録画して

時間のある時に観ている。

しかしそうそうテレビ欄をチェックしているわけでもないので、

気づいたら観たかった映画が昨日放映されてて悔しがる、なんてことがよくある。

放映予定の映画をまとめて確認する方法はないのか、と探してみたら

良いページが見つかった。

cinema.pia.co.jp

2週間分の放映予定をチャンネル関係なく教えてくれる。

素晴らしい。目的達成。

定期的にチェックする

まだ終わりじゃない。

大事なのは見逃さないように定期的にプッシュしてくれる仕組みを作ること。

残念ながらこの放映予定はRSS配信されていないようなので、

いつものように定期的にページの内容を取得して

チャットワークに通知してくれる自動化スクリプトを作る。

放映予定通知スクリプト(Clojure)

今はClojureに夢中なので、Clojure+Leiningenでスクリプトを書いてみる。

処理内容としては、

  1. ページ内容を取得して放映情報のリストを生成する
  2. 放映情報のリストを1つの文字列に整形してチャットワークに送信する

という流れにした。

tv-moviesという名前のプロジェクトとして作成する。

まずは依存ライブラリを書いただけのproject.clj:

(defproject tv-movies "0.1.0-SNAPSHOT"
  :description "FIXME: write description"
  :url "http://example.com/FIXME"
  :license {:name "Eclipse Public License"
            :url "http://www.eclipse.org/legal/epl-v10.html"}
  :dependencies [[org.clojure/clojure "1.8.0"]
                 [enlive "1.1.6"]
                 [clj-http "2.0.0"]]
  :main ^:skip-aot tv-movies.core
  :target-path "target/%s"
  :profiles {:uberjar {:aot :all}})

続いて、メインクラスのcore.clj:

(ns tv-movies.core
  (:gen-class)
  (:require [net.cgrand.enlive-html :as html])
  (:require [clojure.java.io :as io])
  (:require [clj-http.client :as http]))

(defn fetch-movie-list
  "映画情報を取得してリスト化"
  []  
  (let [target-url  "http://cinema.pia.co.jp/title/tvlist/"
        rows (-> (io/reader target-url :encoding "Shift_JIS")
               (html/html-resource)
               (html/select [:div#mainTvSchedule :tr]))]
    (for [row rows 
          :let [title (-> (html/select row [:h3 :a]) first :content first)
                date (-> (html/select row [:th.date]) first :content first)
                start (-> (html/select row [:td.time :span.start]) first :content first)
                end (-> (html/select row [:td.time :span.end]) first :content first)
                ch (-> (html/select row [:span.star :strong]) first :content first)
                caps (for [cap (html/select row [:span.commonCaption])] (-> cap :content first (clojure.string/replace #"[\t\s\n]+" " ")))]]
      {:title title 
       :date date
       :start start 
       :end end 
       :ch ch  
       :caps caps})))

(defn post-chatwork
  "チャットワークにメッセージ送信"
  [message]
  (let [endpoint-base "https://api.chatwork.com/v1/"
        room-id "<ルームID>"
        api-key "<APIキー>"
        url (str endpoint-base "rooms/" room-id "/messages")]
    (http/post url 
               {:form-params {:body message}
                :headers {"Content-type" "application/x-www-form-urlencoded"
                          "X-ChatWorkToken" api-key}})))

(defn stringify-movie
  "映画情報を文字列に整形"
  [movie]
  (str (:date movie) " " (:start movie) "-" (:end movie) " (" (:ch movie) ")\n"
       (:title movie) "\n"
       (clojure.string/join "\n" (:caps movie))))

(defn post-movie-list-to-chatwork
  "映画情報を取得してチャットワークに送信"
  []  
  (let [movie-list (fetch-movie-list)
        message (clojure.string/join "\n\n" (for [movie movie-list] 
                                              (stringify-movie movie)))]
    (post-chatwork message)))

(defn -main
  [& args]
  (post-movie-list-to-chatwork))

HTMLの解析にはenliveを使用した。

github.com

実行すると、下記のようなメッセージがチャットワークに投稿される:

23 14:00-17:00 (BS 日テレ)
悪魔の手毬唄〈1977年〉
監督: 市川崑  
出演: 石坂浩二  岸恵子  

  21:00-22:59 (BS朝日)
イエスマン “YES“は人生のパスワード
監督: ペイトン・リード  
出演: ジム・キャリー  ズーイー・デシャネル  

...

うまくチャットワークに投稿されることを確認したら、

lein uberjar

でjar化して、

cronなりタスクスケジューラなりに登録すれば定期処理化できる。

これでもう見逃さない。

おわり

Clojure楽しいのでしばらく使いそう。

プログラミングClojure 第2版

プログラミングClojure 第2版