ochalog

RubyとMediaWikiとIRCが好き。

NHK 杯囲碁トーナメントの棋譜ファイルを SGF 形式で入手する:Part 1. 棋譜データの取得

囲碁ファンの日曜日のお楽しみ、NHK杯テレビ囲碁トーナメント。最近は公式サイトから棋譜を閲覧できるようになり、棋譜の入手が容易になったが、サイト独自の棋譜再生画面を通してのみアクセスできるという点が不便。そこで、棋譜管理ソフトでは定番の SGF 形式で棋譜データを得られないかと考え、試行錯誤してみたところうまくできたので、方法を書いてみる。

棋譜データの場所

棋譜再生画面は JavaScript で実装されていて、棋譜データは Ajax で読み込まれている。例えば 2013 年 1 月 27 日の棋譜 http://cgi2.nhk.or.jp/goshogi/kifu/igs.cgi?d=20130127 を開いてソースを読むと、棋譜データとして http://cgi2.nhk.or.jp/goshogi/kifu/score.cgi?d=20130127&t=i が読み込まれている。他の対局の棋譜も調べてみたところ、棋譜データは

http://cgi2.nhk.or.jp/goshogi/kifu/score.cgi?d=(放送年月日 8 桁)&t=i

に保存されていることが分かった。

棋譜データの一括取得

したがって、放送日の一覧を見て URI を打ち込めば、棋譜を見ることができる第 58 期以降の対局の棋譜データはすべて手に入れることができる。とはいえ、1 年で約 50 もある対局について一つ一つダウンロードするのは面倒くさい。そこで、プログラムの力を借りることにする。ここでは Ruby(作業時のバージョンは 1.9.3p362)を使っている。

まず、適当な作業ディレクトリを作る(以下 ./)。

放送日の一覧

放送日の一覧は公式サイトの下部(昨年度以前は過去のトーナメント表のページ)にある。これを手作業で打ち込むのもきついので、./date/ に以下のファイルを置く(「○月×日」を並べただけ。公開情報だし、これの転載は問題ないはず)。

一括取得スクリプト

一括取得スクリプト get-score.rb を以下に示す。./ に置く。

使用法は、例えば第 60 期なら

$ ruby get-score.rb 60

とする。実行すると ./score/score-60/棋譜データがダウンロードされる。

# coding: utf-8
 
require "net/http"
require "fileutils"
 
unless ARGV.length == 1
  puts "usage: ruby get-score.rb EDITION"
  abort
end
 
URL = "http://cgi2.nhk.or.jp/goshogi/kifu/score.cgi"
uri = URI(URL)
param = {t: "i"}
 
edition = ARGV[0].to_i
year_edition = 1952 + edition
score_dir = "./score/score-#{edition}"
FileUtils.mkdir_p(score_dir) unless Dir.exist?(score_dir)
 
s = nil
File.open("./date/date-#{edition}.txt") {|f| s = f.read}
dates = s.scan(/(\d+)(\d+)/).map do |a|
  month = a[0].to_i
  date = a[1].to_i
  year = month >= 4 ? year_edition : year_edition + 1
  sprintf("%04d%02d%02d", year, month, date)
end
 
dates.each do |date_s|
  param[:d] = date_s
  file_name = "#{score_dir}/#{date_s}.txt"
 
  uri.query = URI::encode_www_form(param)
  score = Net::HTTP.get(uri)
 
  File.open(file_name, "w") {|f| f.print(score)}
 
  puts "exported #{file_name}"
  sleep 1
end

行っていることは以下の通り。

  1. n 期の番号から年を求め、URI や出力先を設定する。
  2. ./date/date-n.txt から日付を読み込み、8 桁の番号を作る。
  3. 日付ごとに棋譜データをダウンロードする。過負荷防止のため、終わるごとに 1 秒休む。

このスクリプトを使えば、第 58 期以降のすべての棋譜データを入手することができる。ただ、このデータは独自形式なので、棋譜管理ソフトで扱うためには SGF 形式に変換する必要がある。データの仕組みと変換法は、次回で述べる。