本日もperlネタ。
ブログやニュースサイトから本文だけ抽出したい時に非常に便利なcpanモジュールにHTML::Featureというものがあります。
設計も非常に秀逸で本文を抽出するロジック(エンジン)もモジュールで選ぶことができます。

use HTML::Feature;my $url = "http://hogehoge.com/blog/entry01.html";my $f = HTML::Feature->new(
 
engines => [
'HTML::Feature::Engine::LDRFullFeed',
'HTML::Feature::Engine::GoogleADSection',
'HTML::Feature::Engine::TagStructure',
],
user_agent => 'hogehoge bot',
);
 
my $res = $f->parse($url)->text;
print $res;

本来は、これだけで本文が取得できる… はずが、PODの通りユーザーエージェントを指定すると実は下記のようなエラーが返ってきます。
Can't locate object method "user_agent" via package "LWP::UserAgent" at /usr/lib/perl5/site_perl/5.8.8/HTML/Feature/Fetcher.pm line 23.

内部で使ってるLWP::UserAgentに渡す際にエラーがでてるようです。
LWP::UserAgentではユーザーエージェントを指定するのにuser_agentではなくagentと指定するのでその通りに、Fetcher.pmを少し書き換えます。

# $fetcher->user_agent( $config->{user_agent} );

$fetcher->agent( $config->{user_agent} );

これで再度実行すると問題なくhogehoge botというユーザーエージェントが相手のサーバーログに残ります。

user_agentの指定は必須ではないけど、デフォルトではlibwww-perl/#.###というユーザーエージェント名になってしまいます。
サーバーによってはユーザーエージェントがlibwww-perl/#.###だとリクエストを受け付けないこともあるので独自のユーザーエージェント名を指定しておきます。

最近5年ぶりに本格的にperlを書いてるんだけど、ほんと楽しい。
webアプリ作るのはPHPが一番簡単&早いと思うけど、perlは、”There’s more than one way to do it”と言われる通り色んなやり方があって完成するまでのプロセスが楽しめる言語だと思う。

ただ、他の言語でもよくある問題だけど、perlのUTF8は扱いにくい。
よくわからず書いていると必ず出くわす以下のエラー。
Wide character in print at scraper.pl line 12.

久々にperlを書いてるとUTF8フラグとるのは、Encode::encode? Encode::decode?って時があるのでまとめとく。
他にも色々やり方はあるけど、一つだけです。

perlのデフォルトでは以下は6となります。
print length("モダン");
lengthはバイト数を返すのであながち間違いではないけど、見た目も気持ち悪いし内部的にUTF8で動いてないみたいです。

3を返す為には、下記の通りにします。
use utf8;
print length("モダン");

このuse utf8で内部もutf8で動きます。
use utf8を使うとperlの内部で動いてるutf8にutf8フラグというものがつきます。

ただ残念なのがuse utf8を使うと以下のコードでエラーがでます。
use utf8;
print "モダン";
→Wide character in print at scraper.pl line 12.

これはソース直書きのprint対象の文字列(モダン)にutf8フラグがついているのが原因です。

私の場合はスクリプトにはすべてuse utf8をつけて、出力の際にEncodeモジュールを使ってutf8フラグを除去して出力させています。
encodeという言い方がややこしいけど、utf8除去することがencode、逆にutf8フラグを付与する場合はdecodeとなります。
use utf8;
print Encode::encode("utf8", "モダン");

DBに保存させる時は、utf8フラグを除去して保存してくれます。
DBから値を取得した時もutf8フラグは除去されたままなので、encodeモジュールなしで出力します。

3月 1st, 2010perlでMeCabを使う

久しぶりにMeCabをいれることになったけど超絶簡単になっててびっくりした。
yumでインストールできます。

yum mecab mecab-devel ipadic
ipadicは辞書です。辞書がないとmecabは機能しません。
一昔前までeucだのsjisだとutf8だの言ってたけど、yumで入れるとutf8の辞書ができ上がっています。

perlで弄る為にcpanモジュールもインストール。
cpanのシェルでインストールするとコケるので、無理やりインストール。
force install Text::MeCab

途中で辞書のエンコーディングは何か聞かれるのでデフォルトのutf-8を選択

これでperlからmecabを使う準備が整いました。

#!/usr/bin/perl
 
use strict;
use warnings;
use utf8;
use Text::MeCab;
 
my $m = Text::MeCab->new();
my $text = "このブログは俺のメモです。";
  
for (my $node = $m->parse($text); $node; $node = $node->next) {
print $node->surface, "\t", $node->feature, "\t", $node->cost, "\n";
}

実行するとこんな感じです。

この 連体詞,*,*,*,*,*,この,コノ,コノ -664
ブログ 名詞,一般,*,*,*,*,* 7643
は 助詞,係助詞,*,*,*,*,は,ハ,ワ 7663
俺 名詞,代名詞,一般,*,*,*,俺,オレ,オレ 11792
の 助詞,連体化,*,*,*,*,の,ノ,ノ 12160
メモ 名詞,サ変接続,*,*,*,*,メモ,メモ,メモ 14654
です 助動詞,*,*,*,特殊・デス,基本形,です,デス,デス 17196
。 記号,句点,*,*,*,*,。,。,。 13806
BOS/EOS,*,*,*,*,*,*,*,* 12270

残念ながらこのままでは「俺のメモ」が分解されてしまいます。
一つの単語として認識させるにはユーザー辞書に登録する必要があります。
登録の仕方はこの記事を参考にしてください。

PCサイトから長らく離れている間にjQueryが1.4になりました。
何が変更されて何が追加されたっていうのは「jQuery 1.4 API Cheat Sheet — Future Colors」というサイトでうまくまとめられています。
bind()で複数イベントが追加できたり、処理を遅らせるdelay()等があったりします。

基本的に互換性は保ってるとのことだけど、そのままのコードだと動かないところもあります。

例えば1.3だとこれでtitleというnameのinputの値がとれたけど1.4ではエラーになります。
$('input[@name=title]').val();

1.4では下記のようにtypeを明示する必要があります。
$('input:text[@name=title]').val();

jqueryのfunction名は直感的でわかりやすいなぁ。

もうだいぶ前の話しになるけど、なんとなくTwitterAPI+OAuthというのが触ってみたくて、こちらのブログを参考にプロトタイプを作りました。
参考にというか、ほぼコピペで。

検索とかポストとかは一通り問題なく行えたのですが、OAuthで認証後の自身のユーザー名の取得で躓きました。ad.lyとかやってるOAuthで認証後にユーザー名を表示してるやつ。

きっとトリッキーな事をしてると思いきやあっさり取れました。
躓いてたのはアクセストークンと同時に取れると思ったから。
もらったアクセストークンで、すぐにverify_credentialsというAPIを叩きユーザー名を含むユーザー情報を取得できます。
http://twitter.com/account/verify_credentials.xml
これでOAuthを行ったユーザーの情報がとれます。


cactiをyumでインストールしすると、そのままだと一部画像が表示されません。
これは画像を生成するRRDtoolのバージョンが違うだけでGUIの設定画面で直すことができます。

左のメニューのsettingsを選択。RRDtool utility versionを1.0から1.2.xにするだけでOK。

cactiは設定がGUIでできるのはいいけど、どうしようもないくらい使いにくいなあ。

mySQLに限らず、バックアップの手段は熟知してても、いざ不測の事態が起こってデータをリストアをしようとしたらやり方がよくわからないってことがあります。
RDSでもインスタンスを作成時、何も指定してなくてもバックアップの設定を行ってくれますが、リストアは当然コマンドを記述しなくてはいけません。

RDSのバックアップには手動によるスナップショット方式と自動でバックアップを行ってくれるものの2種類ありますが、今回の説明は後者です。
バックアップする期間はインスタンス起動時のオプション(backup-retention-period)で指定できるけど、指定しなくても1日間のデータをバックアップとってくれます。
例えば今が2010-02-02 23:30だとしたら 2010-02-01 23:30から2010-02-02 23:25のどのタイミングのデータでもリストアすることができます。
リストアは下記コマンドを使います。

rds-restore-db-instance-to-point-in-time new-db -s kowareta-db -r 2010-01-29T16:00:00Z

リストアは別インスタンスを立ち上げるので第一引数で新しいインスタンス名、
-sはバックアップしたいデータベース名、
-eはどの時間の状態に戻すか(指定はUTCで)
となります。

リストアはデータの量によるけど10分前後かかります。その間statusはcreatingとなります。

ついに始まりました。
モバゲーはmixi同様オープンソーシャルに参画してるので開発手法はmixiと非常に似たものになっています。
オープン初日にリリースされたゲームのほとんどがmixiで人気のあったアプリのモバゲー移植版でした。
3月には正式リリースということで今後が楽しみです。

mixiアプリモバイルはピコピコmixiと差し変わる形で登場したけど、モバゲーの場合既存ゲームにオープンプラットフォームのゲームが加わった形です。
ユーザーのことよく考えてるんが、サイトをみるとこの既存ゲームとオープンプラットフォームのゲームの境がユーザーからしたらほとんどわからいようになってます。
作り手のしては分けといてほしいと思うけど、確かにオープンプラットフォームのゲームをよりすぐって選びたいってのは非常にレアな話なんでこれは非常に素晴らしいこと。
確かに、M1F1層に「こちらのゲームはモバゲーオープンプラットフォームで動作するゲームですよ」とか言われても意味がわからないし、教える必要もないと思う。

どうでもいい事で、一つ気になったのが「モバゲーアプリ」とはいわないんですね。それどころか「アプリ」と呼ばない。「モバゲーオープンプラットフォームで動作するゲーム」という記述ばかりで「アプリ」とはどこにもなくモバゲーでは意識して使ってない感じ。
そういえばPC版では便利ツールや単純にページに貼り付けるだけのアプリはあるけどモバイル版はゲームしかない。
なるほどなーと思ったけどやっぱり短くて呼びやす呼称はほしいな。

巷でtwitterのbot作りが流行ってるみたいなので便乗してみた。
次の給料日までの残日数をカウントダウンして朝の9時にお知らせする給料日bot。

給料日が10日ver.
http://twitter.com/kyuryobi_10

給料日が25日ver.
http://twitter.com/kyuryobi_25

探せば同じのがありそうな気がするけど見つける作る気が失せるので探してません。
これは何かを作る上で重要かも。

3年前にも実はtwitterAPIを使って色々仕事してたけど、その時は認証はOAuthなんてなくベーシック認証でした。
twitterではOAuthを押してるらしく、今回はOAuthを使いました。
mixiやモバゲーの2-legged OAuthに慣れてしまってたので一瞬戸惑ったけど、今ではphpのライブラリが整備されてて導入はあっさりいけまいした。
OAuthを使ってうれしいことが投稿クライアント名が入れれること。

about 20 hours前 from 【10日】給料日bot

といった具合に任意の投稿クライアント名(アプリケーション名)とリンクが埋め込めます。
これがベーシック認証だとすべて「from API」になってしまいます。

今度はまともなbotを作ってみよう。

EC2のインスタンスのバックアップは前回の通りS3にイメージ化して保存しておくのがいいと思うけど、/mnt以下のイメージ化の対象外ファイルをバックアップするにはEBSの方が便利です。
EC2とS3の関係はそんな密なものでもなく、EC2にS3を直接マウントすることができません。(擬似的には可能かも)
しかもS3へのアクセスはhttp経由ということでrsyncも使えず速度が遅い。

そもそもEBSが何かというと外付け可能な永続的ブロックストレージです。わかりやすく言うとUSB接続の外付けハードディスクみたいなものです。
料金はインスタンスにマウントするしないに関わらず、EBSを借りた時点で1Gにつき一ヶ月当たり$0.1 + 100万リクエストにつき$0.1です。

一度マウントしてしまうと後はローカルドライブ同様に扱えます。
EBSの素晴らしいところは、一旦アンマウントして別のインスタンスにデータはそのままマウントすることが可能ということ。
これで万が一カーネルパニックでインスタンスが動かなくなってもデータの救出が可能です。
但し、一つ残念なのが同時に複数からのマウントはできません。これができたらNFSとも決別できて、かなり幸せになれそうだけど現時点では不可能です。
直接データをEBSに保存してもいいと思うけど、私の場合、データは/mntに保存しておいて定期的にEBSにrsyncしてバックアップストレージとして使っています。

使い方

扱い方は以下の通り。今回はAWS management consoleを使ってます。
ELASTIC BLOCK STORE→ Volumes → create Volumeを選択
Sizeは1G以上、Availability ZoneはEC2のインスタンスのゾーンと合わしておく。

しばらくしてStatusが「available」になれば使用可能です。

次の作成したこのボリュームをインスタンスに関連付けします。
上メニューのAttach Volumeを選択するだけです。

Instancesを関連付けたインスタンスをDeviceを適当なものに(本例では/dev/sdb)を選択。

これでAWS management consoleの設定が終了。
残念ながらこの時点ではマウントする準備が出来ただけです。
続けてECのインスタンスでの作業です。

# mkfs -t ext3 /dev/sdb
ke2fs 1.40.4 (31-Dec-2007)
/dev/sdb is entire device, not just one partition!
Proceed anyway? (y,n) y
Filesystem label=
OS type: Linux
Block size=4096 (log=2)
Fragment size=4096 (log=2)
26214400 inodes, 52428800 blocks
2621440 blocks (5.00%) reserved for the super user
First data block=0
Maximum filesystem blocks=0
1600 block groups
32768 blocks per group, 32768 fragments per group
16384 inodes per group
Superblock backups stored on blocks:
32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208,
4096000, 7962624, 11239424, 20480000, 23887872
 
Writing inode tables: done
Creating journal (32768 blocks): done
Writing superblocks and filesystem accounting information: done
 
This filesystem will be automatically checked every 34 mounts or
180 days, whichever comes first. Use tune2fs -c or -i to override.

ディレクトリを生成
# mkdir /vol

マウント実行
# mount /dev/sdb /vol

確認
# df -h
Filesystem サイズ 使用 残り 使用% マウント位置
/dev/sda1 9.9G 5.8G 3.6G 62% /
/dev/sda2 147G 38G 102G 27% /mnt
none 854M 0 854M 0% /dev/shm
/dev/sdb 197G 188M 187G 1% /vol

これでマウントは完了です。
あとは必要に応じてバックアップ用rsyncのcron設定する。
0 */3 * * * rsync -avz --delete /mnt /vol/backup/ 1> /dev/null