5分でRailsでクローラーを作る。【その1】【xpath】
今回は、Railsでクローラーアプリを作成します。
抽出対象はテーブルです。
自治体の選挙開票結果を抽出してくれるクローラーを作れたりします。
nokogiriのインストール
gem "nokogiri" bundle
nokogiriはHTML解析をしてくれるライブラリです。
MVCの作成
rails g model bot name:text url:text xpath word1:text word2:text word3:text upper:text lower:text rails g controller bots rake db:migrate
カラムの量が尋常じゃなく多いのは、テーブル取得のアプローチを複数用意して柔軟に対応できるためです。
自治体のテーブルは我流で書かれていたり、とりあえずよくわからない構造で書かれてることが多くそういったものに対応するために必要になってくるんですね。
基本のアクションをさっと用意します。
class BotsController < ApplicationController require 'open-uri' #Gem入れたんですが require 'nokogiri' #なぜか動かなかったので一応 def new @bot = Bot.new end def create @bot = Bot.new(bot_params) @bot.save redirect_to bots_path end def index @bots = Bot.all end private def bot_params params.require(:bot).permit(:name, :url, :xpath) end end
ルーティングです。
resources :bots, only: [:create, :index, :new]
次にビューです。
<div class="col-xs-12"> <table class="type07"> <thead> <tr> <th scope="cols"></th> <th scope="cols">サイト名</th> <th scope="cols">URL</th> <th scope="cols">Xpath</th> </tr> </thead> <tbody> <% @bots.each do |bot| %> <tr> <th scope="row"><%= bot.id %></th> <td><%= bot.name %></td> <td><%= bot.url.truncate(20) %></td> <td><%= bot.xpath %></td> </tr> <% end %> </tbody> </table> </div>
new
index
とりあえずこんな感じまでパパッと作ります。
xpathで取得 ---- 精度70%
def crawl @bot = Bot.find(params[:id]) #保存した抽出対象データを呼び出す。 doc = Nokogiri::HTML(open("#{@bot.url}")) #url先のHTML開放 @crawl = doc.xpath("#{@bot.xpath}").inner_html #xpathで取得、HTMLで出力 end
<div class="form align"> <div class="jumbotron font"> 取得に成功しました! </div> 取得した内容 <div class="jumbotron padding height"> <%= @crawl.encode("UTF-8") %> </div> プレビュー <div class="jumbotron"> <%= simple_format("<table>" + @crawl.encode("UTF-8") + "</table>") %> </div> プレビュー2 <%= "<table>#{@crawl.encode("UTF-8")}</table>".html_safe %> #htmlとして表示したい場合 </div>
<div class="col-xs-12"> <table class="type07"> <thead> <tr> <th scope="cols"></th> <th scope="cols">選挙名</th> <th scope="cols">URL</th> <th scope="cols">Xpath</th> <th scope="cols">取得方法</th> #追加 </tr> </thead> <tbody> <% @bots.each do |bot| %> <tr> <th scope="row"><%= bot.id %></th> <td><%= bot.name %></td> <td><%= bot.url.truncate(20) %></td> <td><%= bot.xpath %></td> <td><%= link_to "crawl", bots_crawl_path(id: bot.id) %></td> #追加 </tr> <% end %> </tbody> </table> </div>
get 'bots/crawl', to: 'bots#crawl'