Ruby

【スクレイピング】RubyでWebサイトからテキスト文字を抜き取るやり方(open-uri、nokogiriを使用)

scraping_icatch
対象者

本記事は「プログラミング初心者」を対象にしています。

スクレイピングとは?

キヨシ
キヨシ
フォッフォッフォッ、キヨシ(@kiyothink12)じゃ^^ 今日はRubyを使って”スクレイピング”をしてみようと思うよ。
ケイタ
ケイタ
スクレイピングって??
キヨシ
キヨシ
まあ簡単に言えば、指定したWebサイトのページ内にある文字を抜き取ってくることじゃな。百聞は一見に如かず。難しくないからやってみるぞい^^

スクレイピング環境構築

環  境

Mac OS X: 10.13.6

ruby: 2.2.2

nokogiri: 1.8.4

キヨシ
キヨシ
まずは”nokogiri”というHTMLの構造を解析して、特定の要素を指定しやすい形に加工してくれる便利なものをインストールじゃ。

nokogiriをインストール

ターミナルを開いて下記コマンドを打ち込む($は打ち込み不要)

$gem install nokogiri

インストールが正しく完了しているかバージョン情報を調べてチェック。バージョン情報が出力されればOK!

$nokogiri -v

スクレイピングのコードを書いてみよう

サンプルコード(コピペOK)

スクレイピングコード各行の解説

1行目 nokogiriライブラリを読み込む

require ‘nokogiri’
これは先ほどインストールしたライブラリのnokogiriを使いますよ〜という宣言(読み込み)です。requireしないとインストールしただけでは使えません。

2行目 open-uriを読み込む

require ‘open-uri’
おや?これは先ほどインストールしてないですね?実はこれはRubyに標準でついてくる標準添付ライブラリというものです。Rubyプログラムであればinstallせずとも自然と付いてきちゃうんですね。(参考:標準添付ライブラリドキュメント)

4行目  取得対象のURLを指定

url = “http://kiyothink.starfree.jp/test_scraping/”
urlという変数にテキストを取りたいページのurlを格納しています。

5行目〜9行目 指定したURLを読み込む

charset = nil
html = open(url) do |f|
charset = f.charset
f.read
end
5行目〜9行目では2行目でrequireして読み込んだopen-uriライブラリを使っています。ここは”おまじない”のように書くところと思って今はあまり深く考えずにコピペでokです。一応説明すると、f.charsetで文字種別を取得し、f.readでhtmlを読み込み、変数htmlに格納しています。

nokogiriドキュメントにパースして取得

doc = Nokogiri::HTML.parse(html, nil, charset)
10行目では1行目でrequireしているnokogiriの出番です。取得したhtmlを解析(パース)し、nokogiriドキュメントにして変数docに格納しています。この作業によってcssセレクタを指定して、ページ内のテキストを抜き出せるようになるのです。(cssセレクタの説明、指定の方法は後ほど説明します。)

取得したnokogiriドキュメントのタイトルを出力

p doc.title
11行目では取得したnokogiriドキュメントのタイトル名に指定されたテキストを”p”で出力しています。ターミナルを開き、カレントディクレトリをscraper.rbのあるディクレトリにし(cd 移動したいしディレクトリへのパス)、ruby scraper.rbで実行してみましょう。

$ruby scraper.rb

<実行後 出力内容>
“カレーを作ろう!|kiyothink_scraping”

上記のように”カレーを作ろう!|kiyothink_scraping”と、ページタイトルは出力されたでしょうか?
出力されていればスクレイピングは成功です。

ページコンテンツをスクレイピング。cssセレクタを指定。

さて、タイトル名だけ取得できても仕方ありません。ページコンテンツの方も取得してみましょう。

ここでcssセレクタの登場です。これも説明より実際にやってもらった方がわかりやすいですね。

まずは先ほどのカレーレシピのページGoogle Chromeで開き、右クリックをしましょう。

すると「検証」があるのでクリック

「 option + command + I (アイ) 」の3つ同時押しでも検証機能が始動します。

デベロッパーツール1

この検証機能は別名デベロッパーツールとも言います。

Web制作をしている人やスクレイピング時には欠かせない便利ツールなので覚えておきましょう。

左上の四角いボタンをクリック

デベロッパーツール2

 

webページのスクレイピングで抜き出したい箇所をクリック

デベロッパーツール3

デベロッパーツールの青くハイライトされた部分にカーソルを合わせて右クリックし、Copy → Copy selectorをクリック

デベロッパーツール4

はい、これでこの青い部分のcssセレクターが取得されたので、コードに組み込んで書いていきます。

doc.css(“コピーしたcssセレクター”).text

これを日本語にすると、、

「取得したhtmlを、nokogiriドキュメントにパースしたdocの、cssセレクターで抜き出したい箇所を、特定したところのテキスト」という感じになります。(長ったらしくて余計わかりづらいですかね、、すみません。)

それでは実行して出力してみましょう。

$ruby scraper.rb

<実行後 出力内容>
“–タイトル–”
“カレーを作ろう!|kiyothink_scraping”
“–野菜レシピの一番上–”
“にんじん/2本”

カレーレシピの野菜の一番上に書かれているテキスト文”にんじん/2本”が取得されていますでしょうか?
取得されていれば成功です。

複数タグをスクレイピングで一挙に取得

次は全ての野菜を取得して出力してみましょう。
ulタグのvegクラスの中にliタグが複数あり並んでいます。その場合はeachメソッドを使い取得します。

$ruby scraper.rb

<実行後 出力内容>
“–タイトル–”
“カレーを作ろう!|kiyothink_scraping”
“–野菜レシピの一番上–”
“にんじん/2本”
“–野菜レシピ全て–”
“にんじん/2本”
“たまねぎ/3個”
“じゃがいも/4個”

全ての野菜が出力できたでしょうか?

このようにして出力したものを加工して(ex.野菜と個数を分けて)、DBに突っ込んだり、cronで実行スケジュールを設定して自動化したりしながら活用の幅が広がりますね。

キヨシ
キヨシ
と、いうことじゃ^^わかったかい?
ケイタ
ケイタ
わかった気がしますキヨシさん!面白そうですね!でもこれってどのWebサイトでもテキスト取れるんですか?
キヨシ
キヨシ
うむ、良い点に気づいたのう。実は全てのサイトでcssセレクタで指定した文字がスクレイピングで取れるわけじゃない。javascriptで動的に生成されているものなどは取れずにcssセレクタで指定したのに””と空白で取得されている場合もある。
ケイタ
ケイタ
へ〜そうなんだ。その場合はどうするんですか?
キヨシ
キヨシ
その場合は”selenium”を使って取得したりするのう。それはまた次の機会に説明しようかの。フォッフォッフォッ

 

・サーバーに負荷をかけてはいけない
アクセス過多を起こすとサーバーへの攻撃となりえます。1アクセス毎のsleep処理は必須。岡崎市立中央図書館事件
※サイト利用規約でスクレイピング自体が禁止されている場合もあります。

・著作権侵害
【スクレイピングと法律】スクレイピングって法律的に何がOKで何がOUTなのかを弁護士が解説。

 

ABOUT ME
キヨシ
キヨシ
キヨシじゃよ^^ 30歳を超えてからエンジニアに転身。現在はリモートワークしながら海外と日本を行き来して自由気ままに暮らしておるよ( ^ω^ ) フォッフォッフォッ