LoginSignup
14
17

More than 5 years have passed since last update.

ウェブサイトの更新を監視するプログラムを作ってみた

Last updated at Posted at 2016-10-24

Rubyでウェブサイトを取得できるWatirというgemを使って、ウェブサイトの簡易更新チェッカーを作ってみました。

必要なもの

  • Rubyインタプリタ
    • 今回はRuby 2.3.1で試しました。
  • Watir
    • gem install watir
  • PhantomJS

コード

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はデフォルトではページのソース全体を比較しますが、ブロックを渡すとそのブロックの戻り値を比較して更新されたかを判断します。また、updatednot_updatedの引数もこの戻り値が使われます。

ブロック引数browserWatir::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

14
17
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
17