るびまスクレーピング

るびま記事をローカルにスクラップするとき、サイドバーとか外したいなぁと
思った。
なので、まず全体像を把握してみる。

parsehiki.rb

名前ほど対したことはしないし、るびま以外に通用するかも知らない。

require 'htmlutils'
require 'shellwords'

class Tag
  def self.parse(str)
    inner = str.match(/\A<(.*)>\Z/m)[1]
    m = inner.match(/\A\//) and inner = m.post_match
    is_open_tag = !!!m
    m = inner.match(/\A\S+\b/)
    tagname = m[0]
    attrs = {}
    attrs_str = m.post_match.strip
    Shellwords.shellwords(attrs_str).map{|x|
      x.split('=', 2)
    }.each{|attr_name, val|
      attrs[attr_name] = val
    }
    new(tagname, is_open_tag, attrs)
  end
  
  def initialize(name, is_open_tag, attributes)
    @name = name
    @is_open_tag = is_open_tag
    @attributes = attributes.dup
  end
  
  attr_reader :name, :attributes
  
  def [](key)
    @attributes[key]
  end
  
  def opener?
    @is_open_tag
  end
  
  def closer?
    !opener?
  end
end



div_tags = []

HTMLUtils.tokenize(ARGF.read) do |type, str|
  case type
  when :comment, :plain
    ;
  when :tag
    tag = Tag.parse(str)
    div_tags << tag if tag.name == 'div'
  end
end



def put_class(klass, level)
  puts "#{'  ' * level}#{klass}"
end

level = 0
stack = []

div_tags.each do |tag|
  if tag.opener?
    klass = tag['class'] || '*nil*'
    stack.push(klass)
    put_class(klass, level)
    level += 1
  else
    level -= 1
    klass = stack.pop || '*nil*'
    put_class("/#{klass}", level)
  end
end

parsehiki.rbの出力(一部加工)

カッコ書きは手作業による加工の結果。*nil*はclass属性のないdivタグのことです。

main
  adminmenu
  /adminmenu
  note
  /note
  *nil*
    (ここから任意の繰り返し)
    day
      body
        section
        /section
      /body
    /day
    (ここまで繰り返し)
  /*nil*
  day
    comment
      caption
      /caption
    /comment
  /day
/main
sidebar
/sidebar
footer
/footer

parsehiki.rbの結果まとめ

つまり、

main----------------------------------------------------+
	|                                                     |
  | +--------------+                                    |
  | | adminmenu    |                                    |
  | +--------------+                                    |
  | [ note ]                                            |
  |                                                     |
  |============ *nil* (day iteration) ==================|
  | day                                                 |
  |   body                                              |
  |     section-------------------------+               |
  |      |         …………             |               |
  |      +------------------------------+               |
  |                                                     |
  |=====================================================|
  |                                                     |
  | day                                                 |
  |   comment                                           |
  |     caption--------------------------+              |
  |       |         …………             |              |
  |       +------------------------------+              |
  |                                                     |
  +-----------------------------------------------------+

sidebar-------------------------------------------------+
  |                     …………                        |
  +-----------------------------------------------------+

footer--------------------------------------------------+
  |                     …………                        |
  +-----------------------------------------------------+

こうか。
いや、divしかみてないから適当なんだけど。