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で使うなりご自由に。