MTで書き出されたファイルからコメントデータを復元

MT-column > Tips
| | コメント(0) | トラックバック(0)

これはどんな話か

Webサイトデータのバックアップの重要性はいくら強調しても強調しすぎということはないのですが、とはいえ、何らかのアクシデントでデータが失われてしまうこともあるものです。

今回はそのようなアクシデントに見舞われた状態において、MTで書き出されたHTMLとメールのデータから、コメントデータをデータベースに復元した際の手順をご紹介します。

前提条件とスタートライン

前提条件は以下の通りです。

  • 書き出されたHTMLは最新のデータのバックアップがある
  • データベースのバックアップはあるものの、最新のデータではない
  • 更新したブログ記事は、ローカルのPCにデータとして残されている
  • コメントを受け付けた際に送信されるメールは全て Gmail に残っている

この状況からまず最初に、

  1. HTMLをバックアップデータから復元する
  2. データベースをバックアップデータから復元する
  3. ローカルのPCに残っていた投稿済みの記事のデータを、再度投稿する

という作業を行い、ここをコメントデータの復元のスタートラインとします。

復元手順

コメントデータの復元は以下のような手順で行いました。

  1. 書き出されたHTMLファイルからコメントデータを抜き出す
    1. 全てのブログ記事アーカイブのファイルを検査し、内容に「id="entry-xxx」が含まれていれば、それが「xxx」をIDにもつブログ記事のファイルだと判断する
    2. ファイルの中の「class="comment"」を抜き出し、コメントのデータの一覧を作成する
  2. コメントを受け付けた際に送信されるメールから、「投稿者名」「メールアドレス」「URL」「IPアドレス」のデータを抜き出し、一覧を作成する
  3. HTMLファイルから抜き出したコメントデータと、メールから抜き出した投稿者のメールアドレスなどのデータを突き合わせる
  4. (3)で突き合わせたデータをデータベースに保存する

プログラム

上記の復元手順を行うプログラムがこちらになります。書き捨てのスクリプトなので完全ではない部分もありますが、このプログラムで概ね期待通りの結果を得ることができました。
※ プログラムを動かすためには Ruby のセットアップが必要ですがその手順については割愛します
※ この記事はプログラムの動作結果を保証するものではありません。実行する場合には自己の責任において行ってください

#!/usr/bin/env ruby
# -*- encoding: utf-8 -*-
require 'pp'
require 'json'
require 'date'
require 'nokogiri'
require 'mail'
require 'pit'
require 'active_record'
target_dir = ARGV.shift or raise 'Usage: ' + $0 + ' target-directory'
config = Pit.get('restore-comment-data-from-entry', :require => {
:gmail => {
:address => "imap.gmail.com",
:port => 993,
:user_name => 'username',
:password => 'password',
:enable_ssl => true
},
:database => {
:adapter => 'mysql2',
:host => 'localhost',
:username => 'username',
:password => 'password',
:database => 'database',
},
:threshold => '2011-1-1',
:adminname => 'MT User',
})
users_file = './users.js'
users = {}
if File.exists? users_file
users = JSON.parse(open(users_file).read)
else
Mail.defaults do
retriever_method :imap, config[:gmail]
end
Mail.all(:delete_after_find => false).each do |email|
begin
body = email.body.to_s.encode("UTF-8", "ISO-2022-JP")
user = body.match(/^コメント投稿者: (.*)/)[1].sub(/\s*\z/, '')
next if user == ''
users[user] ||= {'name' => user}
users[user]['mail'] ||= body.match(/^メールアドレス: (.*)/)[1]
users[user]['url'] ||= body.match(/^URL: (.*)/)[1]
users[user]['ip'] ||= body.match(/^IPアドレス: (.*)/)[1]
rescue => e
# ignore
end
end
open(users_file, 'w').write(users.to_json)
end
comments = []
Dir[File.join(target_dir, '**/**.html')].each do |f|
content = open(f).read
begin
m = content.match(/id="entry-(\d+)"/)
rescue => e
next
end
next unless m
doc = Nokogiri.HTML(content)
th = DateTime.new(*(config[:threshold].split(/\D+/).map(&:to_i)))
doc.search('.comment').each do |comment|
date = DateTime.new(*(
comment.search('.comment-footer a').text.split(/\D+/).map(&:to_i)
))
next if date < th
name = comment
.search('.comment-header').text.sub(/\A\s*/, '').sub(/\s*:\s*$/, '')
u = users[name] || {}
comments << {
:comment_blog_id => 1,
:comment_entry_id => m[1],
:comment_author => name,
:comment_commenter_id => name == config[:adminname] ? 1 : nil,
:comment_email => u['mail'],
:comment_url => u['url'],
:comment_ip => u['ip'],
:comment_text => comment
.search('.comment-content > p')
.map{|p| p.inner_html.gsub(/<br\s*\/?>\n?/, "\n")}
.join("\n\n"),
:comment_modified_on => date.strftime("%Y-%m-%d %H:%M:%S"),
:comment_created_on => date.strftime("%Y-%m-%d %H:%M:%S")
}
end
end
comments.sort! {|a, b| a[:date] <=> b[:date]}
ActiveRecord::Base.establish_connection(config[:database])
class Comment < ActiveRecord::Base
self.table_name = 'mt_comment'
end
raise 'Please comment out this line if you really want to save comments'
comments.each do |c|
c = Comment.new c
c.save or raise 'Can not save'
end
view raw comment-data.rb hosted with ❤ by GitHub

結び

「バックアップ重要!」に尽きる話ではあるのですが、書き出されたファイルが残っていれば多くのデータが復元できたりもします。また今回のケースでは、書き出されていることにより復旧作業中もサイトを公開することができたので、その点でもファイルに助けられました。

トラックバック(0)

このブログ記事を参照しているブログ一覧: MTで書き出されたファイルからコメントデータを復元

このブログ記事に対するトラックバックURL: https://tec.toi-planning.net/mtos/mt-tb.cgi/974

コメントする

Created by ToI企画
Powered by Movable Type 5.2.2