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

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

ただいまの
回答率

91.35%

  • Ruby

    5176questions

    Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

  • Ruby on Rails

    5053questions

    Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

RoRでのスクレイピングのやり方がわかりません

解決済

回答 2

投稿 2017/12/05 20:29

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

ninpig04

score 8

Rubyでスクレイピングを試みてますが、全くうまく行きません
50時間試行錯誤しましたが全くうまくいきませんでした。
様々なサイトを見ましたが全く理解できません。

https://vsanna.me/2015/01/26/scraping_start_up/

例えばこのサイトにあるコードをそのまま貼り付けて実行しましたが、何も表示されません。
Ruby on rails で開発したいのですが、XXX.rbのファイルをどこに置けばいいのかも分かりません。
私がやろうとしていることはhttps://www.gakkou.net/chugaku/src/?srcmode=pref&p=2このサイトの各学校のデータ(番号や住所含む)をデータベースに流し込み、ビューで表示することです。そしてそれぞれにリンクを貼って各学校のページに飛びたいです。
どなたか助けてください。。。

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 2

checkベストアンサー

+4

苦労されているようなので、ヒントというか大枠だけ示します。
スクレイピングの前段階として必要な知識が抜けているように思います。

スクレイピングは高度な技術なので、基本的なプログラミングのレベルは必要となります。
また、Rubyを使うのでRubyの文法についてもきちんと知っておかないとけないです。
さらにRailsの知識も必要なので、いきなりスクレイピングだけやりたいというのは実は無理なのです。

それでも、あえて教えるとするとこういう感じかなというのを書きます。
もちろん全部は教えられないので、あくまでも導入部分だけです。

 HTTPアクセスをする方法を知る

まず、スクレイピングの前にHTTPアクセスをするためのライブラリが必要です。
個人的にはhttpclientをおすすめします。

Gemfileにgem 'httpclient'を追記し、ターミナルでbundle installを実行します。
まずは、このhttpclientを使って任意のURLのHTMLを取得できなければいけません。

例えば、こんな感じのメソッドを作って、get_html("http://www.yahoo.co.jp/")という感じに使います。
相手サイト、サーバに負荷をかけないように簡易的なキャッシュ機能を入れます。
rubyではエンコーディングが正しくないと例外で落ちるので、キャッシュファイルの入出力のエンコーディングはbinaryとしておきます。

def get_html(url)
  client = HTTPClient.new
  client.connect_timeout = 10
  client.send_timeout = 10
  client.receive_timeout = 30

  cache_id = Digest::SHA1.hexdigest(url)
  cache_path = "#{Rails.root}/tmp/cache/response/#{cache_id}"
  FileUtils.mkdir_p(File.dirname(cache_path), mode: 0771)

  # using cache
  if File.exist?(cache_path)
    Rails.logger.debug "using cache: url=#{url}"
    return File.read(cache_path, encoding: 'binary')
  end

  response = client.get(url, :follow_redirect => true)
  unless response.status == 200
    raise "request failed: #{response.inspect}"
  end

  # no cache
  Rails.logger.debug "no cache: url=#{url}"
  File.open(cache_path, 'w:binary'){|f|
    f.print response.body
  }

  response.body
end

 どこに置くのか

とりあえずapp/以下であれば自動で読み込み対象となります。
デフォルトでそういう設定になっているはずなので。
良く分からなければ、app/models/crawl.rbというのを作りましょう。
DBと関係なくても、モデルと呼ぶ場合もあるし問題ないかと。

class Crawl

  def get_html(url)
    client = HTTPClient.new
    client.connect_timeout = 10
    client.send_timeout = 10
    client.receive_timeout = 30

    cache_id = Digest::SHA1.hexdigest(url)
    cache_path = "#{Rails.root}/tmp/cache/response/#{cache_id}"
    FileUtils.mkdir_p(File.dirname(cache_path), mode: 0771)

    # using cache
    if File.exist?(cache_path)
      Rails.logger.debug "using cache: url=#{url}"
      return File.read(cache_path, encoding: 'binary')
    end

    response = client.get(url, :follow_redirect => true)
    unless response.status == 200
      raise "request failed: #{response.inspect}"
    end

    # no cache
    Rails.logger.debug "no cache: url=#{url}"
    File.open(cache_path, 'w:binary'){|f|
      f.print response.body
    }

    response.body
  end

end

実行方法は2つあります。
まず、rails consoleを実行する方法。

$ rails console
> Crawl.new.get_html("http://www.yahoo.co.jp/")
...

次に、rails runnerを使う方法。
この場合、画面に何も出ないので、Crawlのコードの中でputsなどを入れてください。

$ rails runner 'Crawl.new.get_html("http://www.yahoo.co.jp/")'

 Nokogiriを使ってみる

ここまでで、とりあえず任意のURLのHTMLを取れるようになりました。
ようやくスクレイピングです。

例えば、 https://www.gakkou.net/chugaku/src/?srcmode=pref&p=13 を例にします。

  • ブラウザでhttps://www.gakkou.net/chugaku/src/?srcmode=pref&p=13にアクセス
  • ブラウザのソースを表示で、HTMLを確認する
  • 取得したい部分のHTML構造を把握する

今回の例では、学校名を取りたいと思います。
とりあえず、ソースをながめてdiv.UvsinfoBxの直下のh3タグが学校名っぽいし、繰り返しのパターンになっているなという風に考えます。

<div class="UvsinfoBx">
<a href="../view/index_204110.html">
<h3>愛国中学校</h3>
</a>

これについては、試行錯誤して経験を積むしかないので、どこかのサイトを参考にするという事はできません。
色々試しましょう。

この場合、こういう風にコードを組む事になるでしょう。
とりあえず、プロジェクト直下にcrawl_test.rbとしてそのまま保存します。

html = Crawl.new.get_html("https://www.gakkou.net/chugaku/src/?srcmode=pref&p=13")
doc = Nokogiri::parse(html)
doc.css('div.UvsinfoBx').each do |div|
  puts  div.css('h3').first.text.to_s
end

そして、実行するとこういう感じに出力されます。

$ rails runner ./crawl_test.rb
愛国中学校
青ケ島村立青ケ島中学校
青山学院中等部
...

以上が、基本的なスクレイピングの流れです。
スクレイピング対象のページごとにHTML構造が違うので、取得コードを変える必要がありますし、
URLの一覧を取得する処理も必要です。
この点については、さすがに手取り足取りというわけにはいかないので工夫してみてください。

投稿 2017/12/05 21:37

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/12/06 03:08

    返信ありがとうございます。
    回答の中でも分からなかったことがあるので質問します。

    ⑴簡易的なキャッシュとは何ですか?キャッシュといえば一時的な記憶という認識があるのですが、これを入れるとなぜサーバに負荷がかからないようになるのですか?
    ⑵「キャッシュファイルの入出力のエンコーディングはbinaryとしておきます。」というのがよく分かりませんでした。
    ⑶貼っていただいたコードをコピペしてアプリの中に起き、コマンドを実行しましたが、-bash: syntax error near unexpected token `"http://www.yahoo.co.jp/"'と表示されてしまいました。何がいけなかったのでしょうか?

    加えて、ドットインストールもprogateも5周くらいして頭に入れていますが、この手の話が全くわかるようになりません
    どうすれば良いですか?

    キャンセル

  • 2017/12/06 03:11

    あと、取得した学校の名前をデータベースに流し込みたいのですが、どうすればいいでしょうか?
    私がわかるのは、
    ①rails g model School name:string address:string
    ②rails db:migrate この二つを実行するというのは分かります
    このカラムに取得したデータを流し込む方法がわかりません

    キャンセル

  • 2017/12/06 07:42 編集

    (1) について
    そうですね。一時的な記憶という意味でいいです。
    プログラムにおけるキャッシュ、特にHTTPアクセスのキャッシュといった場合、今回のように正常にアクセスできた場合にローカルのファイルにHTMLを保存しておき、同じURLの場合にはHTTPアクセスをせずにローカルのファイルを使用する事を指します。
    get_htmlのコードを見てもらえれば分かりますよね。

    前の回答でも述べたのですが、スクレイピングは試行錯誤の連続なので何度も同じURLにアクセスしてHTMLの解析(Nokogiriの操作)をする事になります。
    そうすると、以下のようにget_html()を繰り返す必要があるのです。
    もし、キャッシュ機能を作っておかないと、何度も相手のサーバへアクセスしてしまいます。

    get_html("http://www.yahoo.co.jp") 1回目。キャッシュなしなので、相手のサーバにアクセスする
    get_html("http://www.yahoo.co.jp") 2回目。キャッシュありなので、相手サーバにはアクセスしない
    get_html("http://www.yahoo.co.jp") 3回目。キャッシュありなので、相手サーバにはアクセスしない

    相手のサーバへアクセスする事自体が負担を与える事になります。
    その回数が少なければ良いのですが、キャッシュ機能を作らないと何度も何度もアクセスする事になります。

    (2) について
    File.open("パス", 'w:utf-8'){|f| f.print response.body}
    という処理において、もしresponse.bodyの内容がutf-8以外のエンコーディングである場合、例外が起きてしまうのです。
    その対処として、encodingをbinaryとします。
    これはもう実際にそういうエラーを経験し、対策を身に着ける必要がありますし、その結果として私は書いています。
    出来上がったコードだけを見てもなぜそうするのか分からないという事は、プログラムを始めた頃はよくあります。

    (3)について
    今回の回答は、実際に私の環境で動作している事を確認しています。
    syntax errorと出た場合、文法エラーという意味なのでコピペミスなどが考えられます。

    まず、app/model/crawl.rbですが、そのままコピーして、rails consoleで、
    Crawl.new.get_html("http://www.yahoo.co.jp") と打った時に動きますか?
    まずそれを確認してください。
    私の環境では全て動いています。

    > あと、取得した学校の名前をデータベースに流し込みたいのですが、どうすればいいでしょうか?

    取得したデータをDBに入れるというのは、Railsの入門書なり入門サイトの内容をしっかり理解する事が出来れば応用で出来ます。
    これについては、申し訳ないのですが悩んで時間をかけて自分で身に着けないと行けない部分です。

    > ①rails g model School name:string address:string
    > ②rails db:migrate この二つを実行するというのは分かります

    例えば、①の部分をみたら、私はこのような事を頭の中で一瞬で考えます。

    学校名と住所のセットが欲しいのだな(name, address)。
    では学校名、住所のCSVをスクレイピングで作る必要がある。
    それは、だいたいこういう形式になる。
    学校名,住所
    xxx中学校,東京都xxx区xxx
    xxx中学校,東京都xxx区xxx

    そのCSVが出来たとすると、こういう感じで登録できるはず。
    require 'csv'

    CSV.foreach("作ったcsvのパス", encoding: 'utf-8'){|row|
    school = School.new(name: row[0], address: row[1])
    school.save!
    puts "school saved: name=#{school.name}, address=#{school.address}"
    }

    CSVの読み込みはRuby単体の機能です。
    これはRuby CSVでググると出てきます。
    もちろん私も初めてCSVクラスを使ったときは良く分からなくてググって、いろいろ試して覚えました。

    キャンセル

  • 2017/12/07 02:50

    いろいろ検索しているのですが、このページのやり方ではhttpclientをつkっていませんが、やっていることは同じと考えていいですか?
    https://vsanna.me/2015/01/26/scraping_start_up3/

    キャンセル

  • 2017/12/07 07:14

    はい、やっている事は同じです。
    プログラムというのはいろいろなやり方がありますので、1つの正解しかないというわけではないです。

    スクレイピングは、ざっくり言うとこの2つの工程の繰り返しです。
    (1) HTTPアクセス(GET,POST)で対象ページにアクセスして、HTMLを取得する
    (2) 取得したHTMLから目的の情報を取得する

    (1)、(2)が出来るのであればどんな方法(ライブラリ)を使ってもOKです。

    キャンセル

+3

まずはRubyやRoRの基礎からしっかり勉強していきましょう.
それが結局は一番の近道です.

ドットインストールなどが手軽でいいかもしれません.
RubyRoR

投稿 2017/12/05 20:43

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/12/07 01:42

    全部やりました

    キャンセル

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

ただいまの回答率

91.35%

関連した質問

  • 受付中

    RubyによるWebスクレイピングでの404エラー対策

    RubyにてWebスクレイピングをおこないたいと思っております。 対象のURLは末尾の7桁の数字を変更して、変更した先のh2要素を抜くというものです。 初回のアクセス時にbasic

  • 解決済

    Rubyでのスクレイピング時のエラー

    前提・実現したいこと Rubyでスクレイピングをしたいのですが映画.comで現在上映中の作品名のスクレイピングがエラーになってしまいます。ターミナル上で 超高速!参勤交代 

  • 受付中

    Ruby on Railsで無限スクロールサイトのスクレイピング方法について

    前提・実現したいこと Railsでスクレイピングの練習をしているのですが、twitterのようにページ下部で無限スクロールするサイトでツイートのテキストを拾おうとすると最初の20

  • 解決済

    RubyでのWebスクレイピング

    前提・実現したいこと RubyでWebスクレイピングのコードを書いてます。 ライブラリのnokogiriとopen-uriを使って歌詞サイトに行きあるアーティストの歌詞をすべて

  • 解決済

    Ruby openuri スクレイピング

    Rubyで画像ダウンロードを行うコードを書いています。 chromedriverを使いbing検索を行い画像URLを所得し、open可能なURLを厳選するコードなのですが、厳選する

  • 解決済

    [Ruby] Nokogiriでスクレイピング

    RubyのNokogoriでweb上から特定の情報を抜き出す作業をしています。 HTMLがとてもシンプルで、 <html> <body> <h1>It works!</h1

  • 解決済

    [Ruby]webスクレイピング

    webスクレイピングで、<span>の中身をとりだしたいんですが、上手く実行されません。 HTML内で求めるspanが何番目にあるか数えたり、検索機能で調べたり、コード内の変数

  • 解決済

    [Ruby]Webスクレイピングについて

    度々質問失礼します。 Webスクレイピングにおいて、JavaScriptが作動しているHTMLから特定の情報を取得することができません。 こちらのサイトの、Relat

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

  • Ruby

    5176questions

    Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

  • Ruby on Rails

    5053questions

    Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。