PoltergeistのURL Blacklisting/Whitelistingを活用してAjaxスクレイピングを速くする

よくお魚の「脂ののりが良い」といいますが、実際例えば体脂肪率という形で計測するとどうなるのでしょうか。実はそれを測定するためにフィッシュアナライザ™という製品があり、人間用の体脂肪率計と同じ仕組みで非侵襲的な計測が可能なんだそうです。アジなどでは10%とかいうオーダーの数字とのことで、意外とスリム。

さて、Rubyを使ってWebスクレイピングをするときは、個人的にはNokogiriをよく使っています。
通常はNet::HTTPでとってきたHTMLをそのままNokogiriにぶち込めばOKなのですが、非同期での描画を行うAjaxのサイトの解析はそのままではできません。
そこで、PhantomJSのRubyフロントエンドであるPoltergeistをドライバとしてCapybaraを組み合わせると、深く考えることなく静的ページと同じ感覚で解析ができてしまいます。要は、見えないところでまるっとブラウザを動かしてしまって、DOMから仮想的なHTMLを生成させちゃってNokogiriにぶち込む…というようなアプローチです。

require 'nokogiri'
require 'capybara'
require 'capybara/poltergeist'

def wait_for_ajax(session)
  # https://robots.thoughtbot.com/automatically-wait-for-ajax-with-capybara
  Timeout.timeout(Capybara.default_wait_time) do
    return if session.evaluate_script('jQuery.active').blank?
    loop until session.evaluate_script('jQuery.active').zero?
  end
end

def access(url)
  Capybara.register_driver(:poltergeist) do |app|
    Capybara::Poltergeist::Driver.new(app, {
      js_errors: false  #JSに問題があったとき例外を吐かせない。スクレイピングの際は常にfalseがいいです。
    })
  end
  s = Capybara::Session.new(:poltergeist)
  s.visit(url)
  wait_for_ajax(s)
  s
end

def get_html(url)
  s = access(url)
  html = s.html
  s.reset!
  s.driver.quit
  html
end

#あとは普通にNokogiriにぶっこんでゴリゴリやってくだけ!
page = Nokogiri::HTML.parse(get_html(url))
page.css('body')

ちなみに、Capybara::Sessionのインスタンス(accessメソッドの戻り値)に対して、ちょうどfeature specで書くようなマッチャを使ってページに対する操作ができるので、例えば「ここをクリックすると出てくる情報を解析したい」という作業も簡単にできます。

s = access(url)
s.click('Submit')
s.find('.text')  #findを呼ぶとマッチする要素が現れるまで再描画を(デフォルトで2秒間)待ってくれます。
s.html #これをNokogiriにぶち込めばOK

後ろでブラウザがまるごと動いていることの弊害と言ってはあれですが、スクレイピングにあたっては必要ではない情報も非同期でゴリゴリ取ってくることになり、負荷や時間などが増大します。
ということで、そういった必要でない情報は取ってこないようにして少しでも時間と相手サーバの負荷を低減する方法について。

Continue reading

Sidekiq::Schedulerで動的にタスクをぶち込む

お魚の中でもメバルやタチウオなどは夜行性のものとして有名で、特にタチウオなどは昼間沖の深めにいて夜には岸辺の浅いところにくるなど、かなり規則的なパターンで活動するのだそうです。

さて、rubyで野良アプリ書くときバッチ処理エンジンにはSidekiqを好んで使っています。
Sidekiqには日次処理などを簡単に行うため(*1)にSidekiq::Schedulerという拡張gemがあり(*2)、任意の定義済みワーカを例えばcronライクに繰り返し実行することができます。
基本的には各ワーカの実行条件やパラメータをYAMLの形で全て静的に記述し起動時に読み込むというスタイルなのですが、時には動的にワーカをスケジュールに突っ込みたいことがあります。

Sidekiq::Schedulerはもちろんそれもサポートしています。
ただmoove-it/sidekiq-schedulerの説明がいまいちだったので、備忘録も兼ねてまとめました(*3)。

Continue reading

【翻訳】自動テストをすべき5つの理由

最近まで知らなかったのですが、さかな検定(通称ととけん)という検定試験があり、すでに6回実施されているのだそうです。ご推察の通り、さかなクンさんが一枚噛んでいらっしゃるようです。

さて、さいきん仕事でテストを全く書かないチームにジョインしたのですが、やはりこのままではつらい未来しか見えないため、なんとかテストを書くチームに変えていこうとテストをバリバリ書く先輩と一緒に活動を始めつつあります。

ところがいざテストを書くモチベーションを話そうとしてみると、19歳でTDDに出会い初配属部署も「テストは呼吸であり」「テストは義務教育であり」「テスト書けて初めて法の下の平等と基本的人権が主張できる」環境で過ごしてきた今になって言葉に集めるのも骨が折れそうだったので、ちょうど見つけた短めでわかりやすい英語記事を紹介することにしました。
今回はそれを和訳したものを紹介します。

この度翻訳した記事はこちら。
5 advantages of automated testing vs. manual testing.

Continue reading

ndarrayとPySideのQImageとの相互変換

魚類はあまり変態しない(生まれた姿のまま大きくなる)ことが一般的で、カレイなどのように左右対称形から非対称になる…など、昆虫や両生類のそれに比べると控えめな程度にとどまるようです。

さてnumpyと愉快な仲間たちにおいて画像はndarrayとして表現されていて、それを表示するのに使うmatplotlibはちょっとしたGUI機能(widgetsモジュール)をもっています。
ただこれコード的にも絵的にもクセが強くごく単純なデモ以上のことは難しいので、何かしたいときはQtのPythonラッパーであるPySideを使っています。

んで、そのPySideで画像はQImageで扱われるので、裏っかわでndarrayで処理をしているならそれをQImageとの間で相互変換できる必要があります。

そのやり方はこちら。

(参考: python – QImage to Numpy Array using PySide – Stack Overflow

画素毎にループしてコピーするとかイケてないことしなくて済むから簡単だね!
QImageに持ってきてしまえばQPixmapにしてQLabelに突っ込んで表示するなりQPainterでお絵かきするなり、自由です。

matplotlibやskimageのimshowとかでウィンドウが全く表示されないならbackendを変えてみよう

サメはいわゆる魚類(分類学的には魚類というのは無いんだそうですね)に含まれますが、普通に「さかな」と言ってイメージするような魚を指す場合、「硬骨魚綱」と呼ぶとだいたい一致するんだそうです。サメやエイは「軟骨魚綱」になります。ただし、タツノオトシゴも硬骨魚綱に含まれます。

さて、matplotlibやskimageなどを使っていて、どんな描画結果をウィンドウに出そうとしてもでないとき。
X周りはちゃんとしているのに、例えばこんなコードを実行しても、ウィンドウが表示されない場合。

import skimage.io
img = skimage.io.imread('/path/to/image.png')
skimage.io.imshow(img)

Render backendを疑ってみてください。
matplotlibが何をベースに描画を行っているかにより、絵の質や出力方式や出力先が変わります。
現在のRender backendを調べてみましょう。

>>> print matplotlib.get_backend()
agg

無印のAGGは、画面への出力には対応していません。
このようなbackendsを、”noninteractive backends”と呼んでいます。

Here is a summary of the matplotlib renderers (there is an eponymous backed for each; these are non-interactive backends, capable of writing to a file):
Usage — Matplotlib 1.4.3 documentation

ということで、画面への出力にも使えるもの”interactive backends”をrender backendにしてしまいましょう。
backendの変更はスクリプト内でもできますが、ホントに最初にやらないといけないので面倒です。
そこで、デフォルト設定を変更してしまいます。

matplotlibの設定ファイルを探し出します。例えばpyenvを使っていたら下記のようなかんじで出力されます。

>>> matplotlib.matplotlib_fname()
u'/your/home/.pyenv/versions/2.7.9/lib/python2.7/site-packages/matplotlib-1.4.2-py2.7-linux-x86_64.egg/matplotlib/mpl-data/matplotlibrc'

で、このファイルを書き換えます。

 - backend      : agg
 + backend      : Qt4Agg

interactive backendであれば何でもOKです。Aggがついてるやつがおすすめです。
また依存ライブラリは事前に入れる必要があります。
例えばQt4Aggの場合はPyQtやPySideが、GTKAggの場合はPyGTKのインストールが必要です。

調べればすぐなんですけども、backendにはinteractiveとnoninteractiveがあり、デフォルトになっている無印AggがGUIをサポートしていないというのがハマりポイントでした。
pyenv環境にpipで入れたわけですが、配布しているパッケージによっては最初からinteractive backendがデフォルトになっていることもあるようです。

Pythonのargparseからzsh補完スクリプトを吐いてくれるgenzshcompでQoLが上がった

タツノオトシゴって、あの見た目なのですが、実は魚類だったんです。なんとなく甲殻類と思っていた。最大の種は30cmを超えるそうで、あの姿でその大きさというのを想像するとちょっとこわい。。

Pythonでは、かなり強力なコマンド引数パーサとしてargparseが使えます。
いろんなオプションをもつコマンドを作ったら、引数の入力も面倒。
ということで、自分の作ったPythonスクリプト専用の補完がzshで効くようにしたいなーと思っていたら、genzshcompというパッケージがありました。

Continue reading

MacからLinuxにssh X11Forwardingする

スズキは出世魚ということで有名ですが、結局何種類の呼び方があるかご存知でしょうか?地方によるようですがなんと4〜5種類。上には上がいて、ボラは6種類。おぼえきれんわ!

さて、MacからLinuxなPCにX転送でsshしたいときの設定、ググればすぐわかるのですが自分の備忘録がてらにメモ。

前提として、普通にLinux同士でのSSH XForwardingまではできてると想定します。
(入り先のsshd_configのX11Forwardingをyesに)

Mac用X端末XQuartzの導入

MacではXが動いてないので、導入する必要があります。
brewでは入れられない模様。

XQuartz download

ダウンロードしてインストールしてください。

これでOK!

% ssh -X foobar@hoge.jp
$ DISPLAY=localhost:10.0 chrominum-browser

高速化Tips

Macに限ったことではないですがX転送を快適にする設定。

.ssh/configを編集して、

Host *
  Compression yes
  CompressionLevel 9
  Ciphers arcfour256

なる設定を追加すると、結構速くなります。
上2つの項目は説明不要でしょう。Ciphersは暗号化方式で、
How to speed up X11 forwarding in SSH – Xmodulo
等に記述がある通り、arcfour256でかなり高速になります。

イマドキなCUDA 6.5のインストール手順@Ubuntu

現在確認されている深海魚として最も深いところでは8,000メートルを超えるところで見つかったヨミノアシロという種だそうです。8,000メートルって。800気圧って。

さて、CUDAの開発環境の構築は昔から少々面倒で、多少のLinuxの知識と折れない心と英語力が必要です。
自分もこのたびわりと久しぶりに自宅PCにCUDA環境を構築したら、やり方も変わっていて躓いたので備忘録としてメモ。

Continue reading

zsh(やshやbash)でパス系環境変数の重複を除去する

魚へんのつく漢字は非常にたくさんあって、よく雑学問題とかになるんですが、実際のところいくつあるんでしょう。Unicodeの文字表で調べてみたところ、魚へんのつく漢字は394種類ありました。実際はもっとあるんでしょうが、すごいですね。

さて、tmuxを使っていたり、シェル設定を書き換えてsourceしたりなど、PATHやLD_LIBRARY_PATHなどのパス系環境変数の記述が重複してしまうことがよくあります。
これを解決するためのメモ。
参考はこちら。というか完全にそのまま。
zsh で環境変数 LD_LIBRARY_PATH、INCLUDE などの重複パスを除去する – キーボードをたたくとき

zshrcやzshenvに下記のような記述をすればOKです。

typeset -T LD_LIBRARY_PATH ld_library_path; typeset -U ld_library_path
typeset -T LIBRARY_PATH library_path; typeset -U library_path
typeset -T CPATH cpath; typeset -U cpath

どういう意味かは参考サイトの通りです。

また、特にPATHなどに関しては以下の記述で重複除去ができます。

typeset -U path cdpath fpath manpath

ところで、パス記述の重複ってパフォーマンスには影響するのかな。
つまり、実際のパス探索の段階で、すでに見たところをまた見に行ったりするんでしょうか。
だとすると重複除去は絶対必要ですねー。

あと、bashで同じことをしたい場合はどうすればいいんでしょう。
こんなかんじで重複除去自体はできなくはないですが、

$ PATH=c:b:c:a:b:a
$ PATH=`echo $PATH | sed "s/:/\n/g" | sort -u | paste -sd ":"`
$ echo $PATH
a:b:c

記述順が変化してしまい、実際のパス探索の順序が変わってしまい、イケてないかんじです。
力技でできないことはないけど・・・スマートにできないものか。

追記。bashやshでの重複除去を力づくでやってみたので、興味があれば続きを参照。

Continue reading

ssh XForwardingを速くする設定

おさかなさんも先日,24歳を迎えました.もう若くはないです.
しかしキャビアで有名なチョウザメは寿命が150年〜200年にも達するそうです.

手元の環境でssh XForwardingするとき速度が遅くて困っていたのですが,ちょっと調べると高速化Tipsがあり,効果覿面でしたのでメモがてらに.
How to speed up X11 forwarding in SSH – Linux FAQ

~/.ssh/configに

Host *
    Compression yes
    CompressionLevel 9
    TCPKeepAlive yes
    Ciphers blowfish-cbc,arcfou

こんな感じの記述を追加します.

ふつう

% ssh -YC hogehoge@fugafuga

とするとX転送とCompressionが有効な状態になりますが,暗号化処理が結構重たく遅くなるようです.そこでこの設定をすると暗号化処理が軽くなりトータルでも速くなるという理屈のようです.

個人的な印象ですが,WWWブラウザとか画像ビューア(geeqie)まるごとX転送して遠隔操作するぶんには,今まで話にならなかったのがこの設定によってまぁ問題ないぐらいまで速くなった気がします.

こちらも読んでておもしろい.
OpenSSH ciphers performance benchmark | /contrib/famzah

sshのXForwardingを速くする設定と題した記事ですが,ssh全般的に速くなる設定ですねこれは.