CUI環境でCapybaraを使うときのあれこれ


04/28ちょこっと追記と数カ所修正しました。

What's that?

Capybaraはウェブシステムのテストを補助するRubyのライブラリです。
Mechanizeでほとんどのサイトはクロールできますが、JavaScriptなサイトに対してはJavaScriptが解釈できるようなものでクロールしないといけません。

とくに真新しい単語が入っている訳でもなく、これを読んだだけだと別に何もピンと来たりはしないかもしれない。
GUI環境なのかCUI環境なのかという問題は、それと同じくらい普段は意識しないことだと思いますが、何も明記していない場合はGUI環境なんだよ〜というのは、もしかすると初めてだったかもしれないくらい。
今回はわりと大きな問題だったようです。

インストール

参考サイト
github.com/thoughtbot/capybara-webkit

CapybaraとCapybara-webkitというものをインストールします。
Gemでインストール可能ですが、Capybara-webkitのインストールにはQT(キュート)というものが必要なようで、まずはそこから。

Capybara-webkitはCapybaraが利用するドライバーのうちの1つで、他にもRackTest、Poltergeist、Selenium などがあります。
参考書籍だとPoltergeist+PhantomJSが人気らしく、書籍の中でもこの組み合わせでの説明になってます。ウェブの情報もそれなりに多いCapybara-webkitで進めてみたいと思います。
その辺りは置き換えて読んでいく必要がありますが、まぁ何とかなります。

では、参考サイトとCapybara-webkitのインストールに戻りませう。
ザーッとマニュアルと読んでみると、その時に使っていたOSがCentos6だったのでRHELのところが目についた。

ってことで

sudo yum search qtwebkit-devel

警告: 一致するものが見つかりません: qt-webkit-devel
見つかりませんでした

sudo yum search qtwebkit-devel
qtwebkit-devel.x86_64 : Development files for qtwebkit

という感じに、あまり深く考えずにRHEL16のところで進めていくと。

sudo yum install qtwebkit-devel

tail -2 ~/.zshrc                                                          [~/ruby]
export EDITOR=/usr/bin/vim

exec $SHELL -l

qmake-qt4 -v                                                              [~/ruby]
QMake version 2.01a
Using Qt version 4.6.2 in /usr/lib64

っつーか、これだとダメみたい。

Capybara-webkitのインストールは失敗しました。
と出ます。

この件から得る教訓は、急がば回れということらしい。

気を取り直してCent6の手順でインストール

RHELのところから下に下がって良く見てみるとCentos6の手順がちゃんと書いてありました。

この辺は参考サイトと同じです。

sudo yum install libxcb libxcb-devel xcb-util xcb-util-devel
sudo yum install flex bison gperf libicu-devel libxslt-devel ruby
sudo yum install libXrender-devel

cd ~/tmp
wget http://download.qt-project.org/official_releases/qt/4.8/4.8.6/qt-everywhere-opensource-src-4.8.6.tar.gz 


cd qt-everywhere-opensource-src-4.8.6

選択肢の部分は参考サイトから少し変わった様子?
さきほどの教訓がぜんぜん活かされていない気がしますが、Yesを選択してみました。

./configure -opensource -nomake examples -nomake tests

This is the  Open Source Edition.

You are licensed to use this software under the terms of
the Lesser GNU General Public License (LGPL) versions 2.1.
You are also licensed to use this software under the terms of
the GNU General Public License (GPL) versions 3.

Do you accept the terms of either license? yes

しばらく待っていると以下のメッセージが表示されました。どうやら残りは普通に同じように進められそうですね。

Qt is now configured for building. Just run 'gmake'.
Once everything is built, you must run 'gmake install'.
Qt will be installed into /usr/local/Trolltech/Qt-4.8.6

To reconfigure, run 'gmake confclean' and 'configure'.

あとはgmakeでフィニッシュ。
なんですが、Gmakeがめちゃ長いので時間がない時は避けておくのをオススメ。

sudo gmake
sudo gmake install
sudo ln -s /usr/local/Trolltech/Qt-4.8.6/bin/qmake /usr/bin/qmake

gem install capybara-webkit              [/tmp/qt-everywhere-opensource-src-4.8.6]
Building native extensions.  This could take a while...
Successfully installed capybara-webkit-1.5.1
1 gem installed

できた〜!と思ったら?

簡単なテストスクリプトを実行してみると

Capybara::Webkit::ConnectionError

ここでようやく参考にしていたサイト全てがGUI環境を前提にしていたことに気づいた。

・・・なんということでしょう。

CUIの場合はHeadlessとXvfbが必要ということらしい。
本来?という言い方はおかしいですが、本来はウェブサイトのテストに使ってたものらしいので、GUIを前提としていてもおかしくないのかなぁと振り返ってみるとそう思ったりして。

$ gem install headless                                        [~/ruby/Capybara_test]
Fetching: headless-2.0.0.gem (100%)
Successfully installed headless-2.0.0
1 gem installed

エラー内容が変わる。
どうにもこうにもX環境がない場合は、Xvfbとやらを使えということらしい。

Xvfb not found on your system (Headless::Exception)

yum search Xvfb

======================================== N/S Matched: Xvfb ========================================
xorg-x11-server-Xvfb.x86_64 : A X Windows System virtual framebuffer X server.

Headlessという単語は以前にも見覚えがあり

Vagrant+VirtualBoxとpackerで検証環境を作ろう

VirtualBoxのテストでCUIだけで操作したいときはHeadless=Trueというオプションを使っていました。そんな感じということですね。

ではスクリプトを使ってテストしてみます

#!/usr/bin/env ruby
# coding: utf-8

require 'capybara'
require 'capybara-webkit'
require 'uri'
require 'nokogiri'
require 'headless'

headless = Headless.new
headless.start

Capybara.javascript_driver = :webkit
client = Capybara::Session.new(:webkit)
client.visit 'https://www.google.com/'

client.save_screenshot 'google.png'

headless.destroy

Googleに接続して画面キャプチャを取るだけのスクリプトです。

$ ls google.png                                               [~/ruby/Capybara_test]
google.png

無事に動作したようです。
ではサイバーダック君を使って、サーバーとSFTPで繋いでDLしてチェックしてみませう。

google

04/28追記ここから
今回はこれで終わろうと思いましたが、2回に分けようと思っていた事がそれほど大きくなさげなので一緒にしてしまいます。

DSLタイプとインスタンスメソッドタイプ

使えるメソッドは同じなようで少し違っているみたいですが、細かいとこは置いておいて視覚的にはDSLの方が綺麗かな?
参考書籍のAmazonのサンプルを参考にしてCapybara-webkitの場合で、DSLを使ったタイプとインスタンスメソッドを使った2タイプで書いてみました。
最初に両方やってみてDSLの方が良さそうなのでこの後はずっとDSLで進めています。書籍もDSLですしね。こちらはCapybara-webkitで進めているとこもそれほど気にならないで進めれています。

インスタンスメソッドを使ったケース

require 'capybara'
require 'capybara-webkit'
require 'headless'

headless = Headless.new
headless.start
# スクリプトの終わりを告げるhoge
END { headless.destroy ; p "hoge" }

module Crawler
  class Amazon
    def initialize
      Capybara.javascript_driver = :webkit
      @client = Capybara::Session.new(:webkit)
      @client.visit 'https://affiliate.amazon.co.jp/'
      @client.fill_in :username, with: 'YourAccountName'
      @client.fill_in :password, with: 'YourPassword'
      @client.click_button 'サインイン'
    end

    def portal
      @client.select('昨日', :from => 'preSelectedPeriod')
      @client.first('.line-item-links').click_link("レポート全体を表示")
      @client.within(:xpath, "//*[@class='totals']") do
        puts "発送すみ:"+@client.all('td')[1].text
      end
    end
  end
end

DSLを使ったケース

require 'capybara'
require 'capybara/dsl'
require 'capybara-webkit'
require 'headless'

headless = Headless.new
headless.start
# スクリプトの終わりを告げるhoge
END { headless.destroy ; p "hoge" }

module Crawler
  class Amazon
    include Capybara::DSL

      Capybara.javascript_driver = :webkit
      Capybara.current_driver = :webkit
      Capybara.app_host = "https://affiliate.amazon.co.jp/"

    def initialize
      visit ''
      fill_in :username, with: 'YourAccountname'
      fill_in :password, with: 'YourPassword'
      click_button 'サインイン'
    end

    def portal
      select('昨日', :from => 'preSelectedPeriod')
      first('.line-item-links').click_link("レポート全体を表示")
      within(:xpath, "//*[@class='totals']") do
        puts "発送すみ:"+all('td')[1].text
      end
    end
  end
end

Xpathなんかも使ってスクレイピングできるようなので、Mechanizeで蓄えていたことも使えそうですね。

全く関係ない話ですが

今回からKobitoを使って下書きしてマークダウン式にしてみました。

参考書籍
Rubyによるクローラー開発技法
佐々木拓郎 るびきち 著
ソフトバンククリエイティブ

Similar Posts:


Leave a Reply

Your email address will not be published. Required fields are marked *