2014年 04月08日(Tue) [長年日記]
_ [TCG][ruby][プログラム]ブシロードTCG Scraper
以前似たようなプログラムを日記に載せてたけど、古いのでメンテを兼ねて使いやすくしてみた。
プログラムはこんな感じ
- bushiroad-tcg-scraper.rb
#coding: utf-8
require 'thor'
require 'mechanize'
require 'watir-webdriver'
require 'yaml'
#
#= ブシロード製TCGのカードリストをスクレイピングしてYAMLデータを出力するツール
#
#Authors:: ねくろん(@necron)
#Version:: 1.0 2014-04-07 necron
#Copyright:: Copyright (C) necron-web.com, 2014. All rights reserved.
#
module BushiroadTCGScraper
class CLI < Thor
#
#=== エキスパンションのリストを取得する
#
#入力:: config.yml
# proxy: [proxy, port]
# uri: カードリストのURI (例: http://ws-tcg.com/jsp/cardlist)
#
#出力:: expansion_list.yml
# text: エキスパンション名
# onclick: (同名エキスパンション対策用データ)
#
desc "get_expansion_list", "エキスパンションのリストを取得する"
def get_expansion_list
config = YAML.load_file("config.yml")
list = []
agent = Mechanize.new
agent.set_proxy(*config["proxy"]) if config["proxy"]
puts "connecting #{config["uri"]} ..."
page = agent.get(config["uri"])
(page/"div[@id='expansionList'] a").to_a.each do |link|
puts text = link.inner_text.strip
list << {"text" => text, "onclick" => link["onclick"]}
end
File.open("expansion_list.yml", "w") do |file|
file << YAML.dump(list)
end
end
#
#=== エクスパンションリストからカードのリンクリストを取得する
#
#入力:: config.yml
# expansion_list.yml
#
#出力:: card_link_list.yml
# エキスパンション名: [個々のカードのURI,...]
#
desc "get_card_link_list",
"エクスパンションリストからカードのリンクリストを取得する"
def get_card_link_list
config = YAML.load_file("config.yml")
expansion_list = YAML.load_file("expansion_list.yml")
puts "connecting #{config["uri"]} ..."
browser = Watir::Browser.new
browser.goto config["uri"]
list = {}
title = nil
begin
expansion_list.each do |expansion|
title = expansion["text"]
link = nil
browser.links.each do |i|
link = i if i.onclick == "#{expansion["onclick"]}"
end
link.click
array = []
n = 0
begin
sleep 1
flag = false
browser.links.each do |i|
if i.href =~ /cardno/
array << i.href
puts i.href
end
if i.text == '≫'
flag = true
end
end
browser.link(:text, '≫').click if flag
end while flag
list[title] = array
end
ensure
browser.close
File.open("card_link_list.yml", 'w') do |file|
file << YAML.dump(list)
end
end
end
#
#=== カードのリンクリストから個々のカード情報を取得する
#
#入力:: config.yml
# card_link_list.yml
#
#出力:: card_list.yml
#
desc "get_card", "カードのリンクリストから個々のカード情報を取得する"
def get_card
config = YAML.load_file("config.yml")
card_link_list = YAML.load_file("card_link_list.yml")
agent = Mechanize.new
agent.set_proxy(*config["proxy"]) if config["proxy"]
output = {}
card_link_list.each do |expansion, link_list|
list = []
link_list.each do |card_uri|
puts "connecting #{card_uri} ..."
page = agent.get card_uri
array = (page/'table.status td').to_a.inject([]) do |array, e|
array << e.inner_html
end
card = {}
if config["format"]
config["format"].each do |i|
card[i["key"]] = if i["regexp"].to_s.empty?
array[i["line"]]
else
Regexp.new(i["regexp"]).match(array[i["line"]]).to_a[1]
end
end
else
card["debug"] = array
end
list << card
end
output[expansion] = list
end
File.open("card_list.yml", 'w') do |file|
file << YAML.dump(output)
end
end
end
end
module Watir
class Anchor
attributes(:string => [:'onclick'])
end
end
BushiroadTCGScraper::CLI.start(ARGV)
使い方。
まずrubyがインストールされてることが大前提。あとFirefoxブラウザが必要。 他のブラウザ使う場合は各自でプログラムを修正しよう。 一応 ruby2.0.0-p195 で動作確認している。
あと、MechanizeとWatirとThorが必要なので、
gem install Mechanize gem install Watir gem install Thor
とかしておこう。
1. config.ymlの用意 configファイルに
--- uri: http://ws-tcg.com/jsp/cardlist
のようにブシロードのカードリストがあるURIを記載する。proxyが必要な人は下記のようにIPとportを指定可能。必要なければ書く必要はない。
proxy: - 128.0.0.1 - 8080
2. get_expansion_listを実行
ruby ./bushiroad-tcg-scraper.rb get_expansion_list
とコマンドラインを打ち込んで実行。するとexpansion_list.ymlという中間ファイルが出力される。
中身はこんな感じ
---
- text: D.C. D.C.II
onclick: showExpansionDetail('1',''); return false;
- text: リトルバスターズ!
onclick: showExpansionDetail('2',''); return false;
- text: ゼロの使い魔
onclick: showExpansionDetail('3',''); return false;
- text: なのはStrikerS
onclick: showExpansionDetail('6',''); return false;
(以下略)
textがエキスパンションの名前。onclickは同名エキスパンションを区別するためのメタ情報。
3. get_card_link_listを実行
ruby ./bushiroad-tcg-scraper.rb get_card_link_list
とコマンドラインを打ち込んで実行。すると勝手にFirefoxブラウザが起動して、エキスパンション毎に個々のカードのリンクリスト(card_link_list.yml)を作成してくれる。
……のだけど、相当時間かかるので注意。expansion_list.ymlの中身を修正して、欲しいエキスパンションだけとかにした方が良いかも。
例えばexpansion_list.ymlの中身を修正して以下のようにしたら、
---
- text: なのはStrikerS
onclick: showExpansionDetail('6',''); return false;
結果はこうなる。
--- なのはStrikerS: - http://ws-tcg.com/jsp/cardlist?cardno=NS/W04-001 - http://ws-tcg.com/jsp/cardlist?cardno=NS/W04-001S - http://ws-tcg.com/jsp/cardlist?cardno=NS/W04-002 - http://ws-tcg.com/jsp/cardlist?cardno=NS/W04-002S - http://ws-tcg.com/jsp/cardlist?cardno=NS/W04-003 (以下略)
4.get_cardを実行して取得されるカードのデータを確認する。
カードのリンクリストができたら後はget_cardを実行して終了。
……だったら良いんだけど、そう簡単ではない。このツールはブシロードのTCG汎用として作っているので、取得したいカードゲーム毎にそれに合わせたパラメータファイルを作ってやらないといけない。
パラメータはconfig.ymlにformatというキーで指定するんだけど、config.ymlにformatキーが記述されていない場合、Webページに表示されているデータをそのまま取ってくるようになっている。
例えば、card_link_list.ymlを編集して
--- なのはStrikerS: - http://ws-tcg.com/jsp/cardlist?cardno=NS/W04-001
以下のように実行してみると、
ruby ./bushiroad-tcg-scraper.rb get_card
結果のcard_list.ymlファイルの中身はこうなる。
---
なのはStrikerS:
- debug:
- <img src="../cardlist/cardimages/ns_w04_001.gif" alt="カード"><br><a href="javascript:void(0);"
onclick="showQuestion('NS/W04-001'); return false;">≫ このカードに関するQ&A</a>
- "\r\nキャロ・ル・ルシエ<br><span class=\"kana\">キャロルルシエ</span>\r\n"
- NS/W04-001
- RR
- なのはStrikerS
- "\r\n<img src=\"/cardlist/partimages/w.gif\">"
- キャラ
- <img src="../cardlist/partimages/yellow.gif">
- '1'
- '1'
- '5000'
- <img src="../cardlist/partimages/soul.gif">
- <img src="../cardlist/partimages/soul.gif">
- "\r\n魔法 ・ 竜\r\n"
- 【自】 このカードがアタックした時、あなたは自分の舞台にいる「エリオ・モンディアル」を1枚選び、手札に戻す。<br>【自】 アンコール [手札のキャラを1枚控え室に置く]
(このカードが舞台から控え室に置かれた時、あなたはコストを払ってよい。そうしたら、このカードがいた枠に【レスト】して置く)<br>
- 若き槍騎士に駆け抜ける力を!<br>
5. config.ymlにformatキーを追加する。 上の結果を見ながらformatキーを作成する。WSの場合はこんな感じ(もちろんUTF-8で書くように)。
format:
- key: カード画像
line: 0
regexp: <img src="../cardlist/cardimages/(.+\.gif)"
- key: カード名
line: 1
regexp: \s*(.+)<br><span class="kana">.*</span>
- key: カード名(カナ)
line: 1
regexp: .+<br><span class="kana">(.*)</span>
- key: カード番号
line: 2
regexp:
- key: レアリティ
line: 3
regexp:
- key: エクスパンション
line: 4
regexp:
- key: サイド
line: 5
regexp: \s*(.+)
- key: 種類
line: 6
regexp:
- key: 色
line: 7
regexp:
- key: レベル
line: 8
regexp:
- key: コスト
line: 9
regexp:
- key: パワー
line: 10
regexp:
- key: ソウル
line: 11
regexp:
- key: トリガー
line: 12
regexp:
- key: 特徴
line: 13
regexp: \s*(.+)\s\s
- key: テキスト
line: 14
regexp:
- key: フレーバー
line: 15
regexp:
regexpに正規表現を記述し、取り出したい部分を()で囲む。一行全部取り出す場合はregexpは何も書かなくて構わない。
6. 再度get_cardでカードデータを取得する。 実際に上の記述をconfig.ymlに追加して、get_cardを実行すると、
---
なのはStrikerS:
- カード画像: ns_w04_001.gif
カード名: キャロ・ル・ルシエ
カード名(カナ): キャロルルシエ
カード番号: NS/W04-001
レアリティ: RR
エクスパンション: なのはStrikerS
サイド: <img src="/cardlist/partimages/w.gif">
種類: キャラ
色: <img src="../cardlist/partimages/yellow.gif">
レベル: '1'
コスト: '1'
パワー: '5000'
ソウル: <img src="../cardlist/partimages/soul.gif">
トリガー: <img src="../cardlist/partimages/soul.gif">
特徴: 魔法 ・ 竜
テキスト: 【自】 このカードがアタックした時、あなたは自分の舞台にいる「エリオ・モンディアル」を1枚選び、手札に戻す。<br>【自】 アンコール [手札のキャラを1枚控え室に置く]
(このカードが舞台から控え室に置かれた時、あなたはコストを払ってよい。そうしたら、このカードがいた枠に【レスト】して置く)<br>
フレーバー: 若き槍騎士に駆け抜ける力を!<br>
こんな内容のYAMLが出力される。後はエクセルに変換するなり、Javascriptで使うなりご自由に。