Rubyでウェブサイトを取得できるWatirというgemを使って、ウェブサイトの簡易更新チェッカーを作ってみました。
必要なもの
- Rubyインタプリタ
- 今回はRuby 2.3.1で試しました。
- Watir
gem install watir
- PhantomJS
- http://phantomjs.org/ からダウンロード
コード
update_checker.rb
# !/usr/bin/env ruby
require 'watir'
class UpdateChecker
def initialize(url, interval = 180)
@browser = Watir::Browser.start(url, :phantomjs)
@interval = interval
@old = nil
end
def start(&block)
Thread.new do
loop do
s_time = Time.now
check(&block)
sleep [0, @interval - (Time.now - s_time)].max
end
end
end
def check
new = nil
@browser.refresh
if block_given?
new = yield(@browser)
else
new = @browser.html
end
unless @old.nil?
if @old == new
not_updated(@old)
else
updated(@old, new)
end
end
@old = new
end
def updated(old, new)
puts "#{@browser.title} updated on #{Time.now}"
puts new
end
def not_updated(old)
puts "#{@browser.title} not updated"
end
end
使い方
例
Yahoo! Japanのトップページのニュースの更新をチェックする例です。
checker = UpdateChecker.new("http://www.yahoo.co.jp/")
def checker.updated(old, new)
puts "latest news!"
puts new
end
thread = checker.start do |browser|
browser.div(id: "topicsboxfb").ul(class: "emphasis").text
end
thread.join
解説
- UpdateChecker.new
-
UpdateChecker.new(url, interval)
でオブジェクトを作成します。url
は監視するサイトのURL、interval
はチェックする間隔(秒)です。interval
を省略すると3分ごとにチェックしに行きます。 - def checker.updated(old, new) 〜 end
- チェックの結果、更新があった時には
UpdateChecker#updated(old, new)
が、なかった時にはUpdateChecker#not_updated(old)
が呼び出されます。 なので、継承や特異メソッドなどでこれらのメソッドを再定義すればチェック後の挙動を変更することができます。例えばメールを送るようにしたりなども可能ですね(・∀・)
ちなみに引数のold,newは更新前と更新後のページのソースです。 - checker.start
-
checker.start
で監視を開始します。戻り値は監視を行うThreadオブジェクトです。 - do |browser| 〜 end
-
checker.start
はデフォルトではページのソース全体を比較しますが、ブロックを渡すとそのブロックの戻り値を比較して更新されたかを判断します。また、updated
やnot_updated
の引数もこの戻り値が使われます。
ブロック引数browser
はWatir::Browser
オブジェクトになります。詳しい使い方は述べません(というか僕もよくわかってません)が、たとえばbrowser.div(id: "hoge")
とすると<div id="hoge">〜</div>
を表すWatir::Element
オブジェクトが取得できます。このオブジェクトに対してさらにメソッドをチェーンすると子要素や孫要素が取得できます。
id以外にもclassなどどんな属性でも検索できるようですが、同じタグが複数あった場合は最初に見つかったものが返ります。またXpathやCSSセレクタも使えるようです。
上の例ではidでdiv要素を検索し、その子孫要素(直接の子要素でなくても可)のul要素を取っています。text
メソッドは子テキストノード(すべてのテキストノードを連結したもの)を取得します。結果、ブロックの戻り値はこんな感じです。(2016/10/24 15:30頃のヤフーニュース)石原氏にヒアリング再要請へ動画 保育士殺害 被害者の家狙った動画NEW ハロウィン 法に触れる仮装は写真 小柴さん設立 科学財団解散へ iPhone7 Plus モデムで速度差NEW 兵役対応 鳥栖主将Kリーグへ写真NEW 平岳大 父死去でコメント写真 肝付さん死去 声優仲間ら追悼写真NEW
- thread.join
- そのままだとRubyインタプリタが終了してしまうので、
checker.start
が返したスレッドをThread#join
します。
できること
- 通常のページの更新チェック
- Javascriptで動的に生成されるページの更新チェック
できないこと
- プログラム終了時から次回起動時までの間の更新のチェック
参考
APIのドキュメント : http://www.rubydoc.info/gems/watir-webdriver