日記帳

プログラミングのことをつぶやく日記です。

遊戯王OCGのカードを一枚ランダムにツイートさせる

このようにランダムにカードを画像付きで一枚つぶやくTwitter botRubyで作成します。コードは以下です。Twitterの投稿部分については特に説明を記述しません。このRubyスクリプトをcronで12:00 JSTに実行しています。

require "twitter"
require "net/http"
require "open-uri"
require "nokogiri"

def post(client)
  begin
    uri = URI.parse("https://db.ygoprodeck.com/api/v7/randomcard.php")

    https = Net::HTTP.new(uri.host, uri.port)
    https.use_ssl = true
    res = https.start {
      https.get(uri.request_uri)
    }
    card = JSON.parse res.body
    uri = URI.parse(card["card_images"][0]["image_url"])
    img = uri.open

    name = card["name"].gsub(" ", "_")
    card_uri = "https://yugioh.fandom.com/wiki/#{name}"
    html = URI.open(card_uri).read

    # 取得したhtmlをNokogiriでパースする
    doc = Nokogiri::HTML.parse(html)
    name_ja = doc.xpath("//th[contains(., '(base)')]")[0].parent.children[1].children[1].text

    client.update_with_media("今日の最強カードは『#{name_ja}", img)
  rescue
    false
  end
end

client = Twitter::REST::Client.new do |config|
  config.consumer_key = ""
  config.consumer_secret = ""
  config.access_token = ""
  config.access_token_secret = ""
end

while true
  break if post(client)
end

カード画像を取得する

GET https://db.ygoprodeck.com/api/v7/randomcard.php はランダムでカードを一枚返却してくれるJSON APIです。Net::HTTPを使用してリクエストして、返却されたJSONをparseしています。["card_images"][0]["image_url"]にカード画像のuriがあるので、それをopenします。

    uri = URI.parse("https://db.ygoprodeck.com/api/v7/randomcard.php")

    https = Net::HTTP.new(uri.host, uri.port)
    https.use_ssl = true
    res = https.start {
      https.get(uri.request_uri)
    }
    card = JSON.parse res.body
    uri = URI.parse(card["card_images"][0]["image_url"])
    img = uri.open

カード名の日本語名を取得する

GET https://db.ygoprodeck.com/api/v7/randomcard.phpで取得するカード名は英語です。そのため下記のコードが、カード名を日本語に翻訳します。まずカード名のスペースを_(アンダースコア)に変換します。https://yugioh.fandom.com/wiki/[変換後の英語カード名]で日本語のカード名を取得することができます。カード情報のHTMLを取得した後にNokogiriを用いてパースします。カードの日本語名は<th>タグのJapanese (base)が値のとき、それのいとこの要素に日本語のカード名を持っています。そのためコードはdoc.xpath("//th[contains(., '(base)')]")[0].parent.children[1].children[1].text のように魔術的な書き方をしています。ここはもっと良い書き方があると思います。興味があれば、該当HPのdomの構造を見てみてください。

    name = card["name"].gsub(" ", "_")
    card_uri = "https://yugioh.fandom.com/wiki/#{name}"
    html = URI.open(card_uri).read

    # 取得したhtmlをNokogiriでパースする
    doc = Nokogiri::HTML.parse(html)
    name_ja = doc.xpath("//th[contains(., '(base)')]")[0].parent.children[1].children[1].text

例外処理

下記のコードでは、Twitterに画像を投稿するpostメソッドがtrueになるまでwhileで繰り返しています。理由はGET https://db.ygoprodeck.com/api/v7/randomcard.phpトークンカードやラッシュデュエルのカードの情報を返却するためです。https://yugioh.fandom.com/wiki/[英語のカード名]は、TCG、OCGのformatのカードのみ対応していると推測されるため、404が返却されて例外が発生します。したがってpostメソッドで例外処理を行います。postメソッドが正常実行できるまで繰り返し実行します。

while true
  break if post(client)
end

今後の開発予定

メンションをしてくれたアカウントにランダムに1枚、カード画像をリプライしたいと考えます。