Mac OS X El CapitanでOga(大鋸)を使ったRubyのWebスクレイピング
記事の概要
Rubyとチャットボットの学習に使用している書籍に、Google検索を利用して、チャットボットの応答文を生成する方法が出てきたので、RubyでWebスクレイピングする方法を調べました。
恋するプログラム―Rubyでつくる人工無脳 (Mynavi Advanced Library)
- 作者: 秋山智俊
- 出版社/メーカー: マイナビ出版
- 発売日: 2014/12/04
- メディア: Kindle版
- この商品を含むブログを見る
目次
大鋸の準備
RubyでWebスクレイピングだとNokogiri
(鋸)が有名らしいのですが、少し前のPOSTDの記事でOga
(大鋸)が推奨されていた事を思い出し、Nokogiri
を使ったことが無く、Nokogiri
の有用さを知らない私は、Oga
を使うことにしました。
そんなわけで、oga
をインストールします。
$gem install oga Fetching: ast-2.2.0.gem (100%) Successfully installed ast-2.2.0 Fetching: ansi-1.5.0.gem (100%) Successfully installed ansi-1.5.0 Fetching: ruby-ll-2.1.2.gem (100%) Building native extensions. This could take a while... Successfully installed ruby-ll-2.1.2 Fetching: oga-2.2.gem (100%) Building native extensions. This could take a while... Successfully installed oga-2.2 4 gems installed
ちなみに、nokogiri
は何かの折にインストールされていたらしく、既に入ってました。
$gem list nokogiri *** LOCAL GEMS *** nokogiri (1.6.6.2)
大鋸でHTMLを切り出す
oga
のインストールができたので、試しに、『スクレイピング』をGoogleで検索した場合のURLからopen-uri
でHTMLを読み込み、Oga
でパースしてみます。
$pry [1] pry(main)> require 'open-uri' => true [2] pry(main)> require 'Oga' => true [3] pry(main)> url = 'https://www.google.co.jp/search?q=%E3%82%B9%E3%82%AF%E3%83%AC%E3%82%A4%E3%83%94%E3%83%B3%E3%82%B0&ie=utf-8&oe=utf-8&hl=ja' => "https://www.google.co.jp/search?q=%E3%82%B9%E3%82%AF%E3%83%AC%E3%82%A4%E3%83%94%E3%83%B3%E3%82%B0&ie=utf-8&oe=utf-8&hl=ja" [4] pry(main)> html = open(url) do |f| [4] pry(main)* f.read [4] pry(main)* end => "<!doctype html><html itemscope=\"\" itemtype=\"http://schema.org/SearchResultsPage\" lang=\"ja\"><head><meta content=\"text/html; charset=UTF-8\" http-equiv=\"Content-Type\"><meta content=\"/images/branding/googleg/1x/googleg_standard_color_128dp.png\" itemprop=\"image \"><link href=\"/images/branding/product/ico/googleg_lodp.ico\" rel=\"shortcut icon\"><title>スクレイピング - Google 検索</title>" [5] pry(main)> doc = Oga.parse_html(html) => Document( doctype: Doctype(name: "html") children: NodeSet(Element(name: "html" attributes: [Attribute(name: "itemscope" value: ""), Attribute(name: "itemtype" value: [6] pry(main)>
無事にパースできたようなので、XPath
を使った要素の探査を利用して『検索結果のリンク』を切り出してみます。
ブラウザの開発ツールを使って調べてみると、
『検索結果のリンク』はh3
タグ内のa
タグに記述されているようなので、XPath
の//h3/a
からhref
属性の値の取得を試みます。
[6] pry(main)> doc.xpath('//h3/a').each do |node| [6] pry(main)* puts node.get('href') [6] pry(main)* end /url?q=https://ja.wikipedia.org/wiki/%25E3%2582%25A6%25E3%2582%25A7%25E3%2583%2596%25E3%2582%25B9%25E3%2582%25AF%25E3%2583%25AC%25E3%2582%25A4%25E3%2583%2594%25E3%2583%25B3%25E3%2582%25B0&sa=U&ved=0ahUKEwjr7M-nzNDLAhWClZQKHVtnDdQQFggYMAE&usg=AFQjCNHZAORThLyskf3nDxY9SlIMZY3Mvg /url?q=https://ja.wikipedia.org/wiki/%25E3%2582%25A6%25E3%2582%25A7%25E3%2583%2596%25E3%2582%25B9%25E3%2582%25AF%25E3%2583%25AC%25E3%2582%25A4%25E3%2583%2594%25E3%2583%25B3%25E3%2582%25B0&sa=U&ved=0ahUKEwjr7M-nzNDLAhWClZQKHVtnDdQQFggcMAI&usg=AFQjCNHZAORThLyskf3nDxY9SlIMZY3Mvg /url?q=http://vsanna.sakura.ne.jp/wp/2015/01/scraping_start_up/&sa=U&ved=0ahUKEwjr7M-nzNDLAhWClZQKHVtnDdQQFggmMAM&usg=AFQjCNHXVN2xrEYNm28Ku2s7nwGVPdAiSQ /url?q=http://nelog.jp/import-io&sa=U&ved=0ahUKEwjr7M-nzNDLAhWClZQKHVtnDdQQFggtMAQ&usg=AFQjCNGVG386yqDmhygjyhbNdhZtEMWuKg /url?q=http://qiita.com/tags/%25E3%2582%25B9%25E3%2582%25AF%25E3%2583%25AC%25E3%2582%25A4%25E3%2583%2594%25E3%2583%25B3%25E3%2582%25B0&sa=U&ved=0ahUKEwjr7M-nzNDLAhWClZQKHVtnDdQQFggzMAU&usg=AFQjCNF90oue6qE9iY7-7aX18l3_xbGTCg /url?q=http://qiita.com/advent-calendar/2015/crawler&sa=U&ved=0ahUKEwjr7M-nzNDLAhWClZQKHVtnDdQQFgg5MAY&usg=AFQjCNH1d8pi6VFqXc05SoGLgmnWA7sUxQ /url?q=http://qiita.com/muran001/items/7a76a1c70aa12ed68cb6&sa=U&ved=0ahUKEwjr7M-nzNDLAhWClZQKHVtnDdQQFgg-MAc&usg=AFQjCNFp7u_XDLi3XxSR3puErDpJ3TEHfw /url?q=http://www.sophia-it.com/content/Web%25E3%2582%25B9%25E3%2582%25AF%25E3%2583%25AC%25E3%2582%25A4%25E3%2583%2594%25E3%2583%25B3%25E3%2582%25B0&sa=U&ved=0ahUKEwjr7M-nzNDLAhWClZQKHVtnDdQQFghEMAg&usg=AFQjCNFwJP1ZWTJYT-PdMBKsWpM2L69prw /url?q=http://tech.respect-pal.jp/web-scraping/&sa=U&ved=0ahUKEwjr7M-nzNDLAhWClZQKHVtnDdQQFghKMAk&usg=AFQjCNHFBm-FNZQClN7ssKveEsjz3GD4eQ /url?q=http://www.usamimi.info/~ryouchi/scraping/&sa=U&ved=0ahUKEwjr7M-nzNDLAhWClZQKHVtnDdQQFghQMAo&usg=AFQjCNF5l0OwwjJCYUnJZTTiTXN9DZLQOQ [7] pry(main)>
なんか、ようさん変なんが出てきた…大丈夫やろか(´・ω・`)
大鋸で切り出した部分を加工する
『検索結果のリンク』らしきものがたくさん出てきましたが、今のところ『検索結果のリンク』は1つあれば事足りるので、最初の値だけ取得します。
[7] pry(main)> link = doc.xpath('//h3/a').first.get('href') => "/url?q=https://ja.wikipedia.org/wiki/%25E3%2582%25A6%25E3%2582%25A7%25E3%2583%2596%25E3%2582%25B9%25E3%2582%25AF%25E3%2583%25AC%25E3%2582%25A4%25E3%2583%2594%25E3%2583%25B3%25E3%2582%25B0&sa=U&ved=0ahUKEwjr7M-nzNDLAhWClZQKHVtnDdQQFggYMAE&usg=AFQjCNHZAORThLyskf3nDxY9SlIMZY3Mvg" [8] pry(main)>
取得した値を見てると、/url?q=
が記述されていて、https://www.google.co.jp
とかを付け加えたら『検索結果のリンク』になりそうな気がしてきたので、試してみます。
[8] pry(main)> process_link = "https://www.google.co.jp" + link => "https://www.google.co.jp/url?q=https://ja.wikipedia.org/wiki/%25E3%2582%25A6%25E3%2582%25A7%25E3%2583%2596%25E3%2582%25B9%25E3%2582%25AF%25E3%2583%25AC%25E3%2582%25A4%25E3%2583%2594%25E3%2583%25B3%25E3%2582%25B0&sa=U&ved=0ahUKEwjr7M-nzNDLAhWClZQKHVtnDdQQFggYMAE&usg=AFQjCNHZAORThLyskf3nDxY9SlIMZY3Mvg" [9] pry(main)> process_link_html = open(process_link) do |f| [9] pry(main)* f.read [9] pry(main)* end => "<!DOCTYPE html>\n<html lang=\"ja\" dir=\"ltr\" class=\"client-nojs\">\n<head>\n<meta charset=\"UTF-8\" />\n<title> ウェブスクレイピング - Wikipedia</title>\n<script>document.documentElement.className = document.documentElement.className.replace( /(^|\\s)client-nojs(\\s|$)/, \"$1client-js$2\" );</script>\n<script>(window.RLQ = window.RLQ || []).push(fu" [10] pry(main)>
やった!リンクが開けた!適当に思いつきやってみたらうまくいったヽ(・ω・)/
大鋸を使ったWebスクレイピング
上述のpry*1で試した手順で、なんとか、『検索結果のリンク』を取得することが出来ましたので、これに手を加えて、スクリプトファイルにまとめてみます。
# gugulu.rb require 'open-uri' # URLを開く require 'Oga' # HTMLやXMLをパースする require 'cgi' # 日本語をURLエンコード google_url = "https://www.google.co.jp" # Google検索開始 loop do # 検索文字列をURLエンコードして取得 # 文字の入力が無ければ検索を終了 print("Search Word: ") search_word = CGI.escape(gets.chomp) break if search_word.empty? # Google検索の結果のリンクを作成 begin link = [] # 検索結果のURLからHTMLを取得 url = "#{google_url}/search?q=#{search_word}" html = open(url) do |f| f.read end # HTMLをパースしてhref属性の値を取得 doc = Oga.parse_html(html) doc.xpath('//h3/a').each do |node| link.push(node.get('href')) end # 取得した値から検索結果のリンクを作成 process_link = "#{google_url}#{link.shift}" rescue => e # Google検索ができなかった場合はエラーを表示 puts("Search Error: #{e.message}") end # 検索結果のリンクを開く begin # 開いたリンクのURLを表示 process_link_html = open(process_link) do |f| f.read end puts("Link Open Success: #{process_link}") rescue => e # リンクが開けない場合は次の値からリンクを作成 puts("Link Open Error: #{e.message}") if link process_link = "#{google_url}#{link.shift}" retry end # 作成したリンクが全て開けない場合は諦める puts("Please Try Other Word") end end
"動けば良い"の精神で作成しましたので、エラー処理とか推敲する余地がありまくりな気がしますが、こいつを使って『スクレイピング』を検索してみます。
$ruby gugulu.rb Search Word: スクレイピング Link Open Success: https://www.google.co.jp/url?q=https://ja.wikipedia.org/wiki/%25E3%2582%25A6%25E3%2582%25A7%25E3%2583%2596%25E3%2582%25B9%25E3%2582%25AF%25E3%2583%25AC%25E3%2582%25A4%25E3%2583%2594%25E3%2583%25B3%25E3%2582%25B0&sa=U&ved=0ahUKEwi6mtK7itHLAhVBFZQKHXqJDUYQFggYMAE&usg=AFQjCNHZAORThLyskf3nDxY9SlIMZY3Mvg Search Word:
おお、リンクが取得できた良かった(´;ω;`)
参考記事
RubyのWebスクレイピングとXPathについては、こちらの記事を参考にさせていただきました。
- Nokogiri を使った Rubyスクレイピング [初心者向けチュートリアル] - 酒と泪とRubyとRailsと
- GitHub - YorickPeterse/oga: Oga is an XML/HTML parser written in Ruby.
- 十章第一回 XPathとは — JavaScript初級者から中級者になろう — uhyohyo.net