old « 鎌倉アルプスの天園ハイキングコースを歩いた | メイン | 盤上の敵 » new

Charm Watchが更新されなくなったので代わりのサイトを作った

2016年05月09日

作ったのはこれ。
チャーム価格調査

とりあえずアクセスして何も入力せずにポチッと押すと、何となく結果が出るからどんなサイトかは分かるかも。

<背景>
「Charm Watch」っていうサイトがありまして。
アクアリウム用品・生体・水草とかペット用品なんかを取り扱ってる通販サイト「チャーム」の価格情報をデータベース化して、今現在の価格がお買い得なのかどうかを調べられるサイト。
水草とか生体って相場もよく分からないし、同じチャームでも日によって結講値段が変わったりするから、価格変動の履歴が見られるのはとても良かった。

でも、2016/03/22以降ずっと更新されてない。
チャームのHTMLレイアウトが変わったからかもしれない。

なくても困りはしないんだけどあると便利だったので、ちょっと残念に思ってた。

そんなこんなで、なければ作ろう的な発想で、試しに作ってみたのが「チャーム価格調査」。

自分の勉強にもなるし良い機会かなと思ったから作った。

<概要>
ざっくり言うと、チャームのサイトをクロールして価格情報を集めてDBに登録しておいて、検索フォームに入力された文字列に合致する商品の価格履歴を表示するだけ。

<技術的な話>
クローラーの実装にはrubyのanemoneっていうgem(ライブラリ)を使った。
ただ、anemoneもそのまま使うと無駄に同じページをクロールしたり、無駄にページ情報をメモリに溜めたりするから、anemone自体をカスタマイズして、効率よく動くようにした。

チャームの商品数は万単位で、クロールするだけでも物凄く時間がかかる。
もちろん、並列実行なんかをすれば高速化は可能だけど、チャーム側への負担が大きいから、並列実行無しで、1回1回ちゃんとディレイを入れてあまり負荷がかからないようにしてる。
ただあまりディレイを入れ過ぎてもクロールが終わるのに何日もかかっちゃう。
なので、クロール対象を制限することで対処した。
あと、ローカルにプロキシサーバを立てて、同じページはキャッシュから取得するようにして、少しでもチャーム側への負担がかからないように配慮した。
(2016/5/21追記)
キャッシュ使ったらデータ収集の意味ないのでやめた。
チャームはASPの動的ページで条件付きGETも対応してないので仕方なく毎回取得することにした。

DBにはSQLite3を採用した。
SQLite3はDBがファイル形式だから、ローカルでクロールして、DBファイルをぽいっとサーバーにアップロードすれば良い。
最初はサーバー側でクローラーを動かすことを考えたけど、共有の安いXREAサーバーで長時間のスクリプトなんて当然動かせない(動かしても多分強制停止させられる)

クローラーと言えば、JavaにNutchっていうApatchだかJakartaだかのライブラリがあって、昔大学時代に使ったこともある。
ただ、最初はサーバーで動かすことも考えてたから、当然Javaはダメで、rubyで実装することにした。
rubyは文法が特殊だったりデバッグがしにくかったりするけど、プログラミング自体は直感的で書きやすいしね。

DB操作にはRailsにも組み込まれてる、ActiveRecordを採用した。
メソッドチェーンでSQLを書かずにSQL実行が出来る素敵なO/Rマッパー。
ただこれ、パフォーマンスはあんまりよろしくない。
簡単に使えるけど上手く使わないと性能が落ちるって言われてるみたいだけど、確かにJOINしてSELECTした結果をオブジェクトで受け取ったりするとかなり性能悪い。
なので、検索結果を配列で取得するpluckメソッドを使ったりなんかして、なるべく高速化はしてみた。
これでもまだ遅いけど、LIMIT100を付けることでどうにかした(逃げた)。

サイトのフレームワークには、Sinatraっていう軽量フレームワークを採用した。
元々フレームワークなんて使う予定もなかったんだけど、たまたま見つけたSinatra。
Railsみたいなルーティング機能を持ってる。
eRubyテンプレートでViewとController処理を分けられるし、何となく使いやすそうだったから使ってみた。

ただこれも問題があって、ローカルで動かす分にはSinatra自体のWEBrickサーバを立ち上げれば良いんだけど、レンタルサーバーで動かすにはCGI起動しないといけない。
CGI起動だとフレームワークの初期処理的な処理が毎回走るから、レスポンスが遅い。
大体3秒くらい待たされるかな。
Webの応答時間の許容範囲は3秒だってよく言われるから、ギリギリ。
まあでも、ちょろっと使う分には大して問題じゃない。
トップページから検索するだけだから、ページ遷移も1回だけだし。
(2016/5/21追記)
CGI起動はやっぱりいけてないのでSinatraは使わずにERBテンプレートを使えるようにロジックを組んだ。

<制限的な話>
そんな感じで色々訳あって、今のところ以下のような制限がある。

クロール対象のカテゴリが「アクア用品」「熱帯魚」「エビ」「金魚」「メダカ」「水草」限定。
犬猫昆虫爬虫類両生類はばっさり切って、海水魚も切った。
こうでもしないと、多量の商品数のデータを取ってくることなんて出来ない。
Charm Watchは毎日更新してたけど、相当チャーム側に負荷がかかってたのでは…?

データ更新は不定期で、ローカルで回してる。
あれだけカテゴリ絞ってもまだ大量の商品があるから、4階層クロールするのに丸2日はかかる感じ。
4階層で網羅出来てるのかは怪しいけどね。
抜けがあったりしたら対処法は後で考える。

検索機能としては、ワード検索のみ。(AND検索は出来る)
Charm Watchでは何%オフとか検索出来り、一時的にかごに入れて合計値を求めたり出来たみたいだけど、今のところそんな機能は付ける予定はなし。
個人用途としては、単純にワード検索して商品の価格変動さえ分かればそれで十分かな、と。

検索件数は100件まで。
DBの検索にちょっと時間かかってるから、とりあえずリミット付けることで対処した。
100件超えて目的の商品が見つからないなら検索ワード変えれば良い。

<参考書籍>
クローラー「anemone」については以下の書籍を参考にした。
といっても、本を買う前に殆どの情報はネットで調べちゃったけど。
それでも、ちゃんと情報がまとまってるって言う意味では本のほうが良いね。

このエントリーをはてなブックマークに追加

old « 鎌倉アルプスの天園ハイキングコースを歩いた | メイン | 盤上の敵 » new

トラックバックURL

このエントリーのトラックバックURL:
http://blog.hp-improve.com/mt/mt-tb.cgi/1514

コメントする