- 公開日:2017-10-13 最終更新日:2017-10-10
- プロスタTOP / プログラミング初心者向け技術系ノウハウ・まとめ

はじめに
スクレイピングをご存じですか?
スクレイピングは、ウェブページなどから情報を抜き出すことをいいます。
近年では、ビッグデータや機械学習などの人気の高まりにより、大量のデータを必要としています。
今ではウェブ上には1ゼタバイト(約1兆ギガバイト)以上のデータが存在すると言われています。
スクレイピングを行えば、大量のデータを入手できることが想像できるでしょう。
この記事では、Ruby初心者の方向けに、Rubyによるウェブページのダウンロード方法とスクレイピングについてお伝えしていきます。
順を追って説明していくので、ぜひコードを書きながら読んでみて下さい。
1:ウェブページをダウンロードする
まずは、スクレイピングの対象となるウェブページをダウンロードすることから始めましょう。
ここでは、Yahoo! JAPANのトップページを取得して、現在のニュースの一覧と本文を取得するプログラムを考えてみます。
ページのダウンロードは、次のようにとても簡単です。
例:
1 2 3 4 5 6 7 |
require 'open-uri' top_page = open("https://www.yahoo.co.jp/") top_page_html = top_page.read top_page.close puts top_page_html |
Rubyには、標準ライブラリとして「open-uriモジュール」が組み込まれています。
これを使えば、例のようにわずか3行でウェブページがダウンロードできます。
HTMLが出力されていることが確認できますね。
次に、このHTMLからニュースのURLを抽出してみましょう。
2:URLの抽出
次に、先ほど取得したトップページのHTMLからニュースのURLを抽出してみます。
ニュースのURLはユニークなため、次のように正規表現を使うと簡単に抜き出せます。
例:
1 2 3 4 5 6 7 8 9 |
require 'open-uri' top_page = open("https://www.yahoo.co.jp/") top_page_html = top_page.read top_page.close news_urls = top_page_html.scan(/https:\/\/news\.yahoo\.co\.jp\/pickup\/[0-9]+/) puts news_urls |
例はかなり安直な正規表現ですが、目的を達するには必要十分です。
正規表現中の特殊文字を「\」でエスケープすることを忘れないようにしましょう。
さて、ニュースのURLは取得できましたが、このURLではニュースの本文を得られません。
そのため、次のようにさらにニュースの詳細のURLを取得する必要があります。
例:
1 2 3 4 5 6 7 8 9 |
news_detail_urls = news_urls.map do |url| news_page = open(url) news_page_html = news_page.read news_page.close news_page_html.match(/<a .*href="(.+?)".*>\[.+\]<\/a>/)[1] end puts news_detail_urls |
この例では、「mapメソッド」を使って、配列(news_urls)の要素を別の配列(news_detail_urls)へと変換しています。
処理内容としては、それぞれのニュースのHTMLを取得し、そこからニュースの詳細のURLを抜き出しています。
正規表現に使われている「()」はグループ化といって、これを使うと「matchメソッド」から返されるマッチオブジェクトで、カッコ内でマッチした文字列にアクセスできます。
実行すると、ニュースの詳細のURLのみが返ってくることが確認できますね。
3:HTMLの解析
ここまで、HTMLからURLを抜き出してきました。
最後に、ニュースの詳細のHTMLから「記事タイトル」と「記事本文」を抜き出してみましょう。
次の例をみて下さい。
例:
1 2 3 4 5 6 7 8 9 10 11 |
news_detail_urls.each do |url| news_detail_page = open(url) news_detail_page_html = news_detail_page.read news_detail_page.close title = news_detail_page_html.match(/<h1>(.+)<\/h1>/m)[1] body = news_detail_page_html.match(/<p class="ynDetailText">(.+?)<\/p>/m)[1] puts "■#{title}--------------------------------------------------" puts body end |
流れ的には、URLを抜き出す処理とほとんど同じです。
注意しておきたいのは、HTMLには改行が含まれていることがあることです。
正規表現はデフォルトで、行単位で処理されます。
つまり、マッチするはずの文字列の途中に改行が含まれているとマッチしなくなってしまうのです。
このため、改行が含まれる文字列に対するマッチングには、正規表現に”m”オプションをつけます。
これは、例のようにパターン文字列の後ろに記述すればOKです。
これでスクレイピングは完了です。
とはいえ、ウェブ上の情報は変更されるのが常ですから、今までうまくいっていたものが動かなくなることもあります。
その都度、対象のHTML似合わせて修正していきましょう。
まとめ
Rubyによるスクレイピング方法がお分かりになりましたか?
今回は標準ライブラリだけを使って、HTML解析部分は独自に行いました。
単純なHTMLなら問題ありませんが、複雑なHTMLではかなり面倒です。
そんなときは、外部ライブラリのHTMLパーサー(Nokogiriなど)を使うと楽にできます。
根底にある仕組みを理解したら、ライブラリに頼ってもよいでしょう。