ひよっこエンジニアの雑多な日記

なんとかWeb系のエンジニアをやっています。

スクレイピングで必要なデータを取得する

Railsを使ってスクレイピングを行います。

今回はプロ野球の試合結果を取得するプログラムを作成してみます。

今回はスポーツナビプロ野球速報を対象とします。

baseball.yahoo.co.jp

rakeタスクを準備

今回はバッチ的な処理を想定してrakeタスクを使って実装していきます。

Railsプロジェクトは作成されている前提です。

まずはrakeタスクを作成します。

$ rails g task game_result

lib/tasks配下にgame_result.rakeが作成されます。

まずは動作確認するためgame_result.rakeを書き換えます。

namespace :game_result do
  desc "試合結果を取得する"
  task :fetch do
    puts "fetch"
  end
end

動作確認するためrails game_result:fetchを実行します。

fetchという文字列が表示されればうまく作成できています。

データを取得する対象を特定する

スクレイピングで取得したいデータを確認します。

https://baseball.yahoo.co.jp/npb/schedule/ にアクセスすると最新の試合結果がわかります。

f:id:kimuraysp:20210117180554p:plain

赤枠の部分を操作することで試合結果が取得できそうです。

f:id:kimuraysp:20210117182539p:plain

class="bb-score__content"となっている要素を取得すれば結果が取れそうです。

htmlを取得する

まずは試しにスポーツナビのHTMLを取得してtitleを表示してみましょう。

Nokogiriを使ったRubyスクレイピング [初心者向けチュートリアル] | 酒と涙とRubyとRailsと

こちらのサイトのコードを参考に書いてみます。

desc "試合結果を取得する"
  task :fetch do
    url = "https://baseball.yahoo.co.jp/npb/schedule/"

    charset = nil
    html = URI.open(url) do |f|
      charset = f.charset
      f.read
    end

    doc = Nokogiri::HTML.parse(html, nil, charset)
    p doc.title
  end
end

この状態でrails game_result:fetchを実行しましょう。

プロ野球 日程・結果 - スポーツナビが表示されていればうまく取得できています。

試合結果を取得する

試合結果を取得したいのでGoogle Chromeの検証ツールを使用してチーム名と得点付近のDOMに特徴がないか確認してみます。

f:id:kimuraysp:20210117202651p:plain f:id:kimuraysp:20210117202741p:plain

確認してみるとホームのチーム名にはbb-score__homeLogo、ビジターのチーム名にはbb-score__awayLogoというclassが付与されています。

スコアの方にはホーム側はbb-score__score--left、ビジター側にはbb-score__score--rightというclassが付与されています。

これらを使って欲しい値が取得できそうです。

スクレイピングのコードに次のコードを追加します。
先ほどのコードのp doc.titleの部分を以下に置き換えましょう。

doc.css(".bb-score__content").each do |node|
  home_team = node.css(".bb-score__homeLogo").first.content
  away_team = node.css(".bb-score__awayLogo").first.content
  home_score = node.css(".bb-score__score--left").first.content
  away_score = node.css(".bb-score__score--right").first.content

  p "#{home_team} #{home_score}"
  p "#{away_team} #{away_score}"
end

試合結果が記載されているカードのパーツにはbb-score__contentというclassがついているので、それを起点に値を取得していきます。

cssメソッドを使うことでclass名やid名、タグ名を指定することで合致した要素が配列で取得できます。

bb-score__contentが存在するclassの中にあるチーム名、得点を取得したいので、先ほど検証ツールで見つけたclass名をcssメソッドを使って指定していきます。

cssメソッドは配列が返ってくるため、firstメソッドを使って要素を取り出します。

そしてcontentメソッドを使うことによってタグの中に記載されている文字列を取得することができます。

コードがかけたらrails game_result:fetchを実行してみましょう。

$ rails game_result:fetch
"ソフトバンク 4"
"巨人 1"

上記のような形でスコアとチーム名を取得できたら成功です。

あとは自分の書いているプログラムで取得した値を使ってやりたいことを実現しましょう。

ぼやき

スポーツナビCSSがBEMで設計されているのでスクレイピングやりやすいですね。