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

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

新規登録して質問してみよう
ただいま回答率
85.50%
Ruby

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

Ruby on Rails

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

Q&A

解決済

2回答

370閲覧

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

ninpig04

総合スコア33

Ruby

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

Ruby on Rails

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

0グッド

0クリップ

投稿2017/12/05 11:29

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このサイトの各学校のデータ(番号や住所含む)をデータベースに流し込み、ビューで表示することです。そしてそれぞれにリンクを貼って各学校のページに飛びたいです。
どなたか助けてください。。。

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

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

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

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

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

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

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

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

ruby

1def get_html(url) 2 client = HTTPClient.new 3 client.connect_timeout = 10 4 client.send_timeout = 10 5 client.receive_timeout = 30 6 7 cache_id = Digest::SHA1.hexdigest(url) 8 cache_path = "#{Rails.root}/tmp/cache/response/#{cache_id}" 9 FileUtils.mkdir_p(File.dirname(cache_path), mode: 0771) 10 11 # using cache 12 if File.exist?(cache_path) 13 Rails.logger.debug "using cache: url=#{url}" 14 return File.read(cache_path, encoding: 'binary') 15 end 16 17 response = client.get(url, :follow_redirect => true) 18 unless response.status == 200 19 raise "request failed: #{response.inspect}" 20 end 21 22 # no cache 23 Rails.logger.debug "no cache: url=#{url}" 24 File.open(cache_path, 'w:binary'){|f| 25 f.print response.body 26 } 27 28 response.body 29end

どこに置くのか

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

ruby

1class Crawl 2 3 def get_html(url) 4 client = HTTPClient.new 5 client.connect_timeout = 10 6 client.send_timeout = 10 7 client.receive_timeout = 30 8 9 cache_id = Digest::SHA1.hexdigest(url) 10 cache_path = "#{Rails.root}/tmp/cache/response/#{cache_id}" 11 FileUtils.mkdir_p(File.dirname(cache_path), mode: 0771) 12 13 # using cache 14 if File.exist?(cache_path) 15 Rails.logger.debug "using cache: url=#{url}" 16 return File.read(cache_path, encoding: 'binary') 17 end 18 19 response = client.get(url, :follow_redirect => true) 20 unless response.status == 200 21 raise "request failed: #{response.inspect}" 22 end 23 24 # no cache 25 Rails.logger.debug "no cache: url=#{url}" 26 File.open(cache_path, 'w:binary'){|f| 27 f.print response.body 28 } 29 30 response.body 31 end 32 33end

実行方法は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 を例にします。

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

html

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

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

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

ruby

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

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

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

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

投稿2017/12/05 12:37

mingos

総合スコア4025

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ninpig04

2017/12/05 18:08

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

2017/12/05 18:11

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

2017/12/05 22: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クラスを使ったときは良く分からなくてググって、いろいろ試して覚えました。
mingos

2017/12/06 22:14

はい、やっている事は同じです。 プログラムというのはいろいろなやり方がありますので、1つの正解しかないというわけではないです。 スクレイピングは、ざっくり言うとこの2つの工程の繰り返しです。 (1) HTTPアクセス(GET,POST)で対象ページにアクセスして、HTMLを取得する (2) 取得したHTMLから目的の情報を取得する (1)、(2)が出来るのであればどんな方法(ライブラリ)を使ってもOKです。
guest

0

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

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

投稿2017/12/05 11:43

Yatima

総合スコア1159

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ninpig04

2017/12/06 16:42

全部やりました
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問