継続的ブログ

主にweb系の技術について書いています

クローラー(スクレイピング)をRspecでテスト

今回初めて、個人用にクローラーを開発してみました。
JavaScript多めのサイトのため、「Capybara + Poltergeist」を使用しました。

順調に開発は進んだのですが、テストってどう書けばいいんだろうと思い、知り合いに相談したところ、下記方針に決まりました。

  • feature_specとして書く
  • 毎回アクセスするのはよろしくないので、用意したHTMLファイルを解析する

やり方

CapybaraのHTTPリクエストをstub化する

毎回アクセスしないように、CapybaraのHTTPリクエストをstub化し、用意したローカルのHTMLファイルを返却するようにします。

HTTPリクエストをスタブ化するGemとして「webmock」は有名だと思います。

github.com

しかし、これはCapybaraでは使えません。
代わりに「puffing-billy」を使います。

github.com

Gemをインストールして、設定を追加します。
README通りだと、jsのエラーが無視されずRspecが失敗してしまうため、私は以下のように設定しました。

Capybara.register_driver :pg_billy do |app|
  options = {
    js_errors: false,
    phantomjs_options: [
      '--ignore-ssl-errors=yes',
      "--proxy=#{Billy.proxy.host}:#{Billy.proxy.port}"
    ]
  }
  Capybara::Poltergeist::Driver.new(app, options)
end
Capybara.configure do |config|
  config.default_driver = :pg_billy
  config.javascript_driver = :pg_billy
end

テストを書いてみる

テストコードはこんな感じです。

require 'rails_helper'

feature 'Login' do
  background do
    Billy.config.record_stub_requests = true
  end

  given(:url) { "http://www.example.com" }
  
  scenario 'login' do
    proxy.stub(url).and_return(body: File.read("spec/features/htmls/login.html"))
    visit url

    within("#form") do
      fill_in 'id', with: 'id'
      fill_in 'password', with: 'password'
    end

    stub = proxy.stub(url, method: 'post').and_return(
      headers: { 'Access-Control-Allow-Origin' => '*' },
      code: 200,
      text: "Success"
    )
    click_button('ログイン')

    request_params = stub.requests.shift[:body].split("&")
    expect(page).to have_content("Success")
    expect(request_params).to include("id=id", "password=password")
  end
end

ポイント1

Billy.config.record_stub_requests = true

フィールドに値が入って、ちゃんとPostされているかチェックするため、リクエスト情報を記録するようにしています。

ポイント2

proxy.stub(url).and_return(body: File.read("spec/features/htmls/login.html"))

指定のURLにアクセスした際に、用意したHTMLをbodyに入れて返すようにしています。

ポイント3

stub = proxy.stub(url, method: 'post').and_return(
      headers: { 'Access-Control-Allow-Origin' => '*' },
      code: 200,
      text: "Success"
    )

ログイン処理をstub化しています。

最後に、フィールドに値がちゃんと入っていること、ログインボタンが押されたことをチェックして、テストは完了です。

なかなか情報もなく、いろいろ悩んだ末、今回このようにテストしてみました。
「うちはこうやってるよ」とかアドバイスいただけるとありがたいです!

参考

Rubyでやるならこの本はオススメです!

Rubyによるクローラー開発技法 巡回・解析機能の実装と21の運用例

Rubyによるクローラー開発技法 巡回・解析機能の実装と21の運用例

メール受信 → 解析(Postfix + Rails)

Railsアプリと連携して下記のことをしたい。

  1. メール受信でRailsアプリ内プログラム実行
  2. メールの中身を確認

今回はMacのローカル環境で検証します。

環境

手順

まずはメール受信できるように

1. Postfixの起動(元々入っている)

$ sudo postfix start

2.メール送信

$ mail <Macユーザー名>

件名入力 → 本文入力 → 最後にEnterで改行して、'.'を入力してEnter

3.メール確認

$ mail

メールを受信することができました!

メール受信→プログラム実行してみる

1.プログラム作成

  • mailin
$ vim /Users/fakiyer/rails_project/script/mailin
#! /usr/bin/env bash
cd /Users/fakiyer/rails_project
/Users/fakiyer/.rbenv/shims/rails runner -e development ‘Mailer.receive(STDIN.read)'
$ chmod 777 /Users/fakiyer/rails_project/script/mailin
  • Mailer
def self.receive(mail)
  email = Mail.new(mail)
  body = email.body.decoded
  charset = email.charset
  body = body.force_encoding(charset).encode('utf-8')

  logger.info body
end

2.Postfixのaliases設定

$ sudo vim /etc/aliases
...
  <Macユーザー名>
  fakiyer: "| /Users/fakiyer/rails_project/script/mailin”
$ sudo newaliases

3.Postfix実行ユーザー変更

  • main.cf
#default_privs = nobody
default_privs = fakiyer
$ sudo postfix start

4.メール送信

$ mail <Macユーザー名>

railsログにbodyの内容が出力されているはずです!

参考

New RelicでDockerコンテナ監視 - Elastic Beanstalk

現在Elastic BeanstalkのMulti-Container Docker環境を使っています。

New Relicを使ってコンテナを監視するようにしたので設定をメモ。
公式のドキュメントがだいぶ丁寧なので、ほとんどその通りなのですが。。。

設定ファイルを追加するだけ

  • .ebextensions/newrelic.config
packages:
  yum:
    newrelic-sysmond: []
  rpm:
    newrelic: http://yum.newrelic.com/pub/newrelic/el5/x86_64/newrelic-repo-5-3.noarch.rpm
commands:
  "01":
    command: usermod -a -G docker newrelic
  "02":
    command: nrsysmond-config --set license_key=YourNewRelicLicense 
  "03":
    command: echo hostname=NameOfYourServer >> /etc/newrelic/nrsysmond.cfg
  "04":
    command: /etc/init.d/newrelic-sysmond start

あとは.ebextensionsとDockerrun.aws.jsonをzipにしてdeployするだけです!

参考

DockerでWhenever(gem)が動かなくてハマった話

久々の更新です。
最低でも月1で書きたいなあと思ってたのですが、2ヶ月以上も空いてしまいました。
最近はRailsはもちろんのこと、React NativeやDockerもバリバリ使ってます!

さて、標題の件ですが、いやー、かなりハマりました。

現在、開発環境にDocker(Docker Compose)を使って、Railsアプリを開発しています。
そして、crontab管理にwheneverというgemを使っています。

コンテナでcronを動かしたいなと思ったのですが、なかなかうまくいかない。。。
cronをインストールして、起動して、wheneverのコマンドでcrontabの設定も完了したのですが、実行時間になるとwheneverのログにエラーが。

Could not find rake-10.5.0 in any of the sources (Bundler::GemNotFound)

crontabに設定されているコマンドをdocker-compose run等で実行すると正常に実行される。

いろいろ調べて下記サイトに辿り付きました。

support.aptible.com

qiita.com

環境変数を渡してあげなきゃいけないみたいです。

一番目のリンクの通り、config/schedule.rbにENV.each { |k, v| env(k, v) }を追記したらうまくいきました。

ghq + peco!じゃなくて fzf連携

対象

ghq + fzf

よく ghq + peco でやってる記事が挙がってますが、それのfzf 版です。
ghq で管理しているリポジトリのパスをインクリメンタルサーチして、選択すると、cdするスクリプトです。

frepo() {
  local dir
  dir=$(ghq list > /dev/null | fzf-tmux --reverse +m) &&
    cd $(ghq root)/$dir
}

f:id:akiza:20160129142308g:plain

私も最近 fzf 使い始めたばかりなので、fzf 使いの方、良い情報あったら教えてください!

最後に

おい、peco もいいけど fzf 使えよ - Qiita

この記事を見てから、fzfを使うようになりました。
素晴らしい記事をありがとうございました!

Docker QuickStart Terminal(Docker Toolbox)でi/o timeout

環境

最近Docker Toolbox使ってDocker触ってないなあということで、久しぶりに触ってみました!
Docker QuickStart TerminalがiTermにも対応したらしいので、VirtualBoxと併せてアップデートして、Docker QuickStart Terminalを起動!
したのですが、下記エラーが出てうまく動かなくなってしまいました。。。

Error checking TLS connection: Error checking and/or regenerating the certs: There was an error validating certificates for host "192.168.99.100:2376": dial tcp 192.168.99.100:2376: i/o timeout

いろいろ調べて、なんとか下記手順で動くようになりました!

$ docker-machine rm default
$ docker-machine create --driver virtualbox default
# .zshrcに追記
eval $(docker-machine env default)

ご参考まで。

参考