はてなダイアリーからのトラックバックの移行(途中)

はてなダイアリーからのトラックバックの移行のための作業を続けています。まだ準備段階ですが作業メモとして。

動機

先日はてなから「はてなブログへの移行に関するお知らせ」なるメールが届いて、ダイアリーからブログへ早く移行しろとのことなのですが、移行されない情報としてトラックバックが挙げられていました。

上記以外の、以下のような項目は対象となりません。また、ドメインは自動で決定させていただくため、お選びいただくこともできません。

以前問い合わせた際にはトラックバックの移行も検討するとのことでしたが無理だったようです… というわけで自力でなんとかしなくてはならなくなりました。

トラックバックデータの取得

まず問題はトラックバックデータをどうやって取得するか、です。これはおそらくダイアリーをまるごとダウンロードしてエントリの HTML をスクレイピングするしかなさそうです。当然はてなブログへの移行後には取得できなくなるので移行前に実施する必要があります。

ダイアリーの編集画面からトラックバックの管理ができるので、そこからスクレイピングしようかとも思ったのですが、表形式の表示の関係か長いタイトルが削られた状態で表示されているようで、実際にエントリに表示される内容そのままでは取得できないようです。

ということで、wget コマンドを使って以下のようなコマンドラインでダウンロード(ミラー)しようとしたのですが…

wget --mirror --page-requisites --no-parent --convert-links --adjust-extension --random-wait http://d.hatena.ne.jp/rna

なんか変なリンクを踏んでダウンロードが止まらなくなりました。

どこから始まったのかは不明ですが、http://d.hatena.ne.jp/rna?of=-1234 みたいにオフセットパラメータがマイナス値になったURLのページをダウンロードし始めて、そのページにはオフセット値をデクリメントしたリンクが入っていて、それを辿って延々とダウンロードが続いてしまいました。

仕方がないので Ctrl-C で止めましたが、どうやら各エントリページはダウンロードできたようなのでやり直しはしませんでした。強制終了したせいか --convert-links は機能していなかったようですが、スクレイピング用には問題なさそう。というか --convert-links しないほうが都合がよいかも。

実際には --accept-regex とか --reject-regex とか上手く使ってダウンロードが正常に完了するようにするべきでしょう。あと、--random-wait ってたいした wait かからないみたいですごいスピードでダウンロードしていました。サーバの負荷を考えると --wait=1 とかにしたほうがよい?

トラックバックデータの抽出

なにはともあれ各エントリの HTML が取得できたのでスクレイピングトラックバックデータを抽出します。ruby の nokogiri を使って以下のようなスクリプトで抽出できました。*1

2019-01-24: 以下のスクリプトにはバグがありました。その3 に修正版を掲載しました。

#!/usr/bin/env ruby
# coding: utf-8

require 'nokogiri'

URL_BASE = "http://d.hatena.ne.jp"

def parse_entry_html_file (file)
  f = File.open(file, "r:euc-jp")
  html = f.read().encode("utf-8", { :invalid => :replace, :undef => :replace })
  f.close
  doc = Nokogiri::HTML::Document.parse(html)
  path = doc.css("div.body > div.section > h3 > a").attribute("href")
  puts "- url: " + URL_BASE + path
  doc.css("div.refererlist").each { |div|
    type = div.css("div.caption > a").attribute("name")
    puts "  #{type}:"
    div.css("ul > li").each { |li|
      puts '    - ' + li.css("a").to_s
    }
  }
end

ARGV.each { |file|
  begin
    parse_entry_html_file(file)
  rescue => e
    STDERR.puts "#{file}: #{e}"
  end
}

引数には HTML ファイル名を列挙して、出力は以下のような YAML 形式です。

- url: http://d.hatena.ne.jp/rna/20040701/p1
  tb:
    - <a href="http://d.hatena.ne.jp/rna/20060731" rel="nofollow">http://d.hatena.ne.jp/rna/20060731</a>
  idtb:
    - <a href="http://d.hatena.ne.jp/contractio/20040701" rel="nofollow">http://d.hatena.ne.jp/contractio/20040701</a>
    - <a href="http://macska.org/index.php?p=27" title="わたしが書いた「Fahrenheit 9/11」への批判的な感想を読んだなんばりょうすけ氏がマイケル・ムーア擁護を書かれているので、それにお返事。…の前に、わたしの「Fahrenheit 9/11」批判について確認しておく。単に「こいつはムーアより左側の立場からアフガン戦争容認のム..." rel="nofollow">ムーア監督への愛情を込めた(?)注文</a>
    - <a href="http://d.hatena.ne.jp/hotsuma/20040701" rel="nofollow">http://d.hatena.ne.jp/hotsuma/20040701</a>
    - <a href="http://d.hatena.ne.jp/hotsuma/20040629" rel="nofollow">http://d.hatena.ne.jp/hotsuma/20040629</a>
    - <a href="http://d.hatena.ne.jp/rna/20051015" rel="nofollow">http://d.hatena.ne.jp/rna/20051015</a>

上のスクリプトではブログモードで記述した場合の各エントリページのファイルが指定されることを想定しています。

ちなみに文字コード変換で encode のオプション { :invalid => :replace, :undef => :replace } を指定していますが、これがないと変換できないエントリが複数ありました。どうもトラックバックの a 要素の title 属性値が文字化けしたものがあるようで、InvalidByteSequenceError とかで落ちてしまいます。

今後の作業予定

  • 全エントリのTBが取得できているか確認
    • エクスポートしたものとエントリ件数を比較して抜けがないか確認
      • 数えたら12件抜けがある。ダウンロード漏れ? どれが抜けているか特定するまで移行できない…
  • はてなブログへのインポート実行
  • はてなブログライター形式でブログエントリを全件ダウンロード
  • ダウンロードしたエントリファイルの末尾にトラックバックを追加
  • はてなブログライターでエントリを更新

*1:出力されるURLが完全なURLになるよう修正しました。(2019-01-23)