質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.77%

【Rails】Rakeタスクでのスクレイピングと普通のRubyで結果が異なる理由がわかりません。

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 563

score 184

前提・実現したいこと

Ruby on Rails でスクレイピングをして取得したデータをデータベースに格納するRakeタスクを作っています。

発生している問題・エラーメッセージ

まず、Rakeタスクを作る前に、単なるRubyでスクレイピングするプログラムを作りました。それを、Rakeタスクに移植して実行してみたのですが、出力されたデータが異なりました。
おそらく、スクレイピングで取得したHTMLが異なるのかと思うのですが、なぜ異なる結果が返されるのかがわかりません。これについてご教授いただけると幸いです。

該当のソースコード

以下のコードがまず始めにRubyで書いたものです。申し訳ないのですが、スクレイピングしているサイトのアドレスやCSSセレクタはダミーです。

require "mechanize"
agent = Mechanize.new
agent.user_agent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36"
page = agent.get("https://example.com")

price_list = []
item_list = []

replace = {
  "\n" => "",
  "\r" => "",
  "\t" => "",
  " " => ""
}
items = page.search("td.item")
items.each do |d|
  d = d.text
  replace.each{|before, after| d.gsub!(before, after)}
  item_list << d
end

4.times do |i|
  prices = page.search("table.price0#{i+1} td")
  prices.each_with_index do |p, j|
    next unless j % 10 == 0
    price_list << p.text.gsub(/[^0-9]/,"").to_i
  end
end

p item_list.zip(price_list).to_h

これをRakeタスクにしたものが以下です。

namespace :site do
  desc "サイトから値段を取得"

  task :get_prices => :environment do
    prices = get_prices
    p prices
    p prices.length
  end

  def get_prices
    agent = Mechanize.new
    agent.user_agent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36"
    page = agent.get("https://www.onamae.com/service/d-regist/price.html")

    price_list = []
    item_list = []

    replace = {
      "\n" => "",
      "\r" => "",
      "\t" => "",
      " " => ""
    }
    items = page.search("td.item")
    items.each do |d|
      item = d.text
      replace.each{|before, after| item.gsub!(before, after)}
      item_list << item
    end

    4.times do |i|
      prices = page.search("table.price0#{i+1} td")
      prices.each_with_index do |p, j|
        next unless j % 10 == 0
        price_list << p.text.gsub(/[^0-9]/,"").to_i
      end
    end

    item_list.zip(price_list).to_h
  end
end

試したこと

ユーザーエージェントがRailsか何かに書き換えられているのではと思い、明示的に指定するようしました。
Mechanizeのユーザーエージェントを変更する。=>変わらず

補足情報(FW/ツールのバージョンなど)

mechanize 
Rails 6.0.1
ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-darwin19]
Mechanize 2.7.6

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • otn

    2019/12/24 14:11

    どう異なるのでしょうか?

    キャンセル

  • otn

    2019/12/24 14:13

    中間結果HTMLをファイルに書き出して、比較して調査してはどうでしょうか。

    キャンセル

  • s_eric

    2019/12/24 14:35

    申し訳ありません。完全に説明不足でした。
    上記の2つのコードでどちらもスクレイピングで得た商品名と商品名の価格を、ハッシュにして表示させています。どちらのコードでも、同じ内容のハッシュが出力されることを期待しているのですが、Rakeタスクでは、Ruby単体のプログラムの結果にはない、商品名と価格の組み合わせが含まれていました。

    中間結果の書き出しですが、
    file = File.open("tmp.html","w")
    file.puts(page.body)
    file.close
    というコードを挿入して、試したのですが、2つのコードのうちRuby単体のものではHTMLファイルが書き出されたのですが、Rakeタスクのほうではエラーも出ず、書き出されないという状況になっており、比較することができませんでした。

    キャンセル

  • s_eric

    2019/12/24 14:36

    宜しくお願いいたします。

    キャンセル

回答 2

check解決した方法

0

文字コードをASCII-8BITからUTF-8に変換することで、どちらも期待値が得られることがわかりました。
回答をくださった方々、ありがとうございました。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

出力されたデータが異なりました。

標準出力のことでしょうか?
Rubyスクリプトは標準出力している箇所( puts とか pとか)がないように見えますが、具体的にどのように異なりますか?

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/12/24 14:51

    出力しているハッシュの内容の差異についてです。
    具体的には上記の2つのコードでどちらもスクレイピングで得た商品名と商品の価格を、ハッシュにして表示させています。どちらのコードでも、同じ内容のハッシュが出力されることを期待しているのですが、Rakeタスクでは、Ruby単体のプログラムの結果にはない、商品名と価格の組み合わせが含まれていました。

    キャンセル

  • 2019/12/24 14:56

    スクレイピング先のサイトが変更になった可能性とかはありませんかねー
    何回試行しても、必ず出力が同じように異なるとかはありませんか?

    キャンセル

  • 2019/12/24 15:02

    どちらのコードもかなりの回数実行して内容を比べたのですが、いつもRakeタスクのほうに見慣れない主賓名と価格がセットされているという感じですね。
    ブラウザで直接確認したのですが、その見慣れない商品名は見つけられなかったので、そもそもレスポンスされているHTMLがRakeタスクと純粋なRubyスクリプトで異なるのかなと考えている状況です。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.77%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る