2015年5月28日木曜日

火事場から逃げ出す方法 もとい、@bbs から記事を引き上げる方法

問題:

無料レンタル掲示板の @bbs  (atbbs.jp) と@bb (www3.atbb.jp) が、5月末でサービスを終了する。
 これらサービスに記事をまとめてダウンロードする機能はない。
 運営側も記事ダウンロードに対応する気はない。なんてこった!

 いかに手間をかけず、月末までに掲示板内の記事を引き上げようか?

解決策:


  1. Anemone (Ruby によるクローラーフレームワーク)で掲示板記事をまとめてダウンロードする
  2. ダウンロードした記事は、とりあえずAnemone経由でMongoDBに突っ込む
  3. とりあえずlocalhost でMongoDBに突っ込んだ記事を読めるよう、Sinatraで簡易Webサーバー作ってこれで読み出す。


 「とりあえず」ばっかである。時間が無くてさあー!

1.Anemoneで掲示板記事をまとめてダウンロード


require 'anemone'
require 'bson'
require 'mongo'

db = Mongo::Connection.new.db('taigen_support_bbs')
opts = {
    delay: 1,
    storage:Anemone::Storage.MongoDB( db ),
    depth_limit: 4 
}

ForumsURL = 'http://bb2.atbb.jp/echizenrnd/'

Anemone.crawl(ForumsURL , opts) do |anemone|
  #クロール対象とするページのURLを指定する。
  anemone.focus_crawl do |page|
    page.links.keep_if {|link|
      link.to_s.match %r"http://bb2.atbb.jp/echizenrnd/(forum|topic)/\d+(\?page=\d+)?$"
    }
  end

#特定のページに対しての処理を記述する。
#  anemone.on_pages_like(%r"/topic/\d+") do |page|
#  ... (今回なにもやっていない)
#  end

#クロール対象となった全ページに対しての処理を記述する。
# anemone.on_every_page do |page|
#  ... (今回なにもやっていない)
# end
end

 これだけである。
 予めMongoDBを起動してから、このスクリプトを動かすだけで、とりあえずMongoDBにクロール結果が一切合切取り込まれる。今回の例では20分くらいかかっただろうか。
 Anemoneがクロール対象とするのはHTMLだけ。画像やスタイルシートは取ってこないので、必要最低限の分だけ手動でダウンロードしておいた。なに、大した数ではない。


2.Sinatraで簡易Webサーバーを書いて、MongoDB内に保存した記事を読めるようにする

取り込んだ記事それぞれをHTMLファイルとして保存しておければ一番シンプルで扱いやすいのだが、フォルダごとに分けたり等の処理が面倒な気がした。
 ので、MongoDB内の記事データをSinatra経由で読めるようにしてみた。

 今回引き上げた掲示板は、各記事へのリンクが絶対URL(http:/bb2.atbb.jp/~)で記載されているため、ブラウザからlocalhost 上の簡易Webサーバーで読もうとすると具合が悪い。そのため、ここはNokogiriで記事内のリンクを相対URLで書き換えている。

 アイコンの類はめんどいので無し。スタイルシートだけは提供して、レイアウト崩れを最低限防ぐ。

gem 'tilt' , '1.4.1' ; require 'tilt' #よくわからんけど、バージョン衝突だかでこれ入れないと動かない。多分今更Ruby1.9環境でやってるせい。
require 'sinatra'
require 'sinatra/reloader'
require 'mongo'
require 'nokogiri'

before do
  db_con = Mongo::Connection.new('localhost', 27017)
  @db    = db_con.db('taigen_support_bbs')
  @pages = @db.collection('pages')
end

BaseURL = 'http://bb2.atbb.jp/'

#各記事へのリンク内に含まれる絶対URLを、全て相対URLで置換する。
def replace_url(content)
  doc = Nokogiri::HTML(content)
  doc.css('a').each do |link|
    if link['href']
      link['href']= link['href'].gsub(/#{BaseURL}/ , '/')
    end
  end
  doc.to_html
end

#掲示板のRoot
get /\/(echizenrnd)?$/ do
  replace_url(@pages.find({url: BaseURL+'echizenrnd/'}).first['body'].to_s)
end

#各フォーラムないし各記事
get %r"/echizenrnd/(forum|topic)/(\d+)?" do |kind , id |
  url = BaseURL + "echizenrnd/#{kind}/#{id}"
  url += "?page=#{params['page']}" if params['page']
  replace_url(@pages.find(url: url).first['body'].to_s)
end

#別途ダウンロードしておいたスタイルシートを読み込んで置く
StylesheetPath = File.join(File.dirname(__FILE__) , 'assets/stylesheet.css')
Stylesheet = open(StylesheetPath).read

#CSSファイル
get /stylesheet.css/ do
  Stylesheet
end


 こんだけ、というにはちょっと書いたが、こんなもんである。 

所見

こんなもんでも作るのに2日かかった。私も衰えたな……などといらん感慨をもったり。
 全ての@bbsユーザーにおいそれと利用できる解決方法ではない(RubyとMongoDBと各種gemをインストールできる人向け)が、まあ何も無いよりはマシだろうか……。


 アイドレスプレイヤーで@bbs終了についてお困りの方へ。

とりあえずこの方法で、黒埼の手元にな記事を保存できるようになりました。あと数日もらえれば、HTMLファイルをZipしたものを渡せるようになるでしょう。
 どうしても自己解決できない場合、黒埼までご相談ください。連絡はTwitter:@kurosaki_koh までどうぞ。  やっつけで使い始めたBlogなので、この記事のコメント欄にかかれても黒埼が気付ける保証はありません。(ひどい)

0 件のコメント:

コメントを投稿