nDiki : Perl モジュール
Related term
2006年7月29日 (土)
■ Debian GNU/Linux sid 環境を新 HDD へ

朝から ThinkPad X31 の HDD 新しく入れ替えて Debian GNU/Linux sid のインストールを開始。
@ Debian GNU/Linux のインストール
今日は sarge のネットワークインストール CD イメージからブートしてインストール。 今回はブートドライブにできる「ThinkPad USB ポータブルCD-ROMドライブ」があり、またこのイメージで起動して e1000 が認識できるので楽勝である。
(第1回目は USB FDD + PC カード NIC でインストール、第2回目 は HDD 上のインストーラから GRUB からの起動によるインストールだった)
最低限のものを入れたらすぐ sid へアップグレード。
@ 旧 HDD からのコピー
ヤバイ状態の旧 HDD を USB 外付け HDD ケースに詰めて
- /home 全部
- /usr/local で必要なもの
- 参照用に /etc の複製
- /var/www、/var/spool
を新しい HDD にコピー。
次に環境の復旧。 以下備忘録。
@ MADWIFI
以前作った Linux kernel 2.6.15 deb パッケージをインストールした後 module-assistant で madwifi をインストールするも、ビルドした GCC のバージョンが違ってロードできず。 kernel は GCC 4.0 の時にビルドしたもので、madwifi は現在のバージョンである GCC 4.1 によるビルドであることが問題。
まずは前にビルドした 2.6.15 のソースディレクトリでカーネルパッケージを GCC 4.1 で作りなおしてインストールし、あらためて module-assistant。
module-assistant prepare module-assistant auto-install madwifi
で /etc/network/interfaces を書き戻す。
@ SMTP サーバを Postfix に
ここずっと使っていた qmail をこの機会にやめることにした。 Postfix へ。
全体の設定はインストーラに従って設定。
個人設定は、
~/.qmail に
| preline /usr/bin/procmail
として procmail を使っていたので、~/.forward を作って同様に procmail に流すようにする。
"|IFS='' && exec /usr/bin/procmail -f- || exit 75 #naney"
~/.procmailrc は以前のまま。ClamAV と bsfilter でふるいにかけた後、Maildir へ。
@ bsfilter は deb のものに
以前入れた時は deb が古かったので /usr/local に自前でインストールした。 まずはこれを古い HDD から戻して動作確認後 deb のものに切り替え。
.mew.el の中も
(load "/usr/share/doc/bsfilter/examples/mua/mew4/mew.el")
に変更。
@ Samba
/etc/samba/smb.conf を書き戻す。smbpasswd でパスワード再設定。
@ X
とりあえずインストール時の設定で xorg.conf を作る。
Load "freetype"
をコメントアウトして、
Load "xtt"
に変更。
@ KDE
sid は現在 3.5.3 と 3.5.4 混在状態になっているため、依存関係の問題で簡単にはインストールできずてこずった。 kdebase-data と kdelibs-data の 3.5.3 を http://snapshot.debian.net/ からとってきて hold して 3.5.3 系 KDE として各種パッケージをインストール。
@ フレッシュリーダー
- libapache2-mod-suphp php5-cli をインストール
- /var/www/freshreader、/etc/apache2/sites-available/freshreader を戻す
- a2ensite freshreader
- /etc/init.d/apache2 reload
- /etc/hosts に freshreader を追加
@ cpufreqd
@ Skype
skype-beta-1.3.0.30-1_i386.deb をインストール。
@ cron
一般ユーザ naney の crontab ファイルを再登録。
@ Perl モジュール
足りないと気がついた時点で順次インストール。
@ autofs + smbfs (2006年8月3日)
/etc/auto.master、/etc/auto.misc を書き戻して /etc/init.d/autofs restart。
@ mt-daapd (2006年8月22日)
deb パッケージを公式サイトからダウンロードし、/etc/mt-daapd.conf を書き戻して /etc/init.d/mt-daapd restart
- 納品前日なのに /var が壊れた! HDDからのブートで Debian ... (2005-09-27)
- Debian Linux kernel 2.6.23 をビルドする。 (2007-12-23)
- [ Debian ] ThinkPad X31 にインストール (2003-12-03)
- CD-R ドライブが使えない (2006-07-27)
- Linux kernel を 2.6.8 に (2004-09-17)
2006年8月4日 (金)
■ Algorithm::RabinKarp でソースコード中の重複を発見

blog.bulknews.net で紹介されていた、Algorithm::RabinKarp Perl モジュールを試してみた。
ハッシュを使って文字列検索を行う Rabin-Karp アルコリズムを実装しているモジュールで、モジュールをインストールすると rabin.pl というスクリプトが一緒にインストールされる。
これを使うと例えば
rabin.pl '*.pm' lib > rabin.txt
で lib ディレクトリ内の *.pm ファイル全てのなかで重複する部分を発見してくれる(内部的には File::Find::Rule を使ってファイルを処理している)。 リファクタリング対象になりそうなところを探すのに便利そうだ。
実際使ってみると重複個所がいろいろ発見できて面白い。 ただ、
- 文字単位で、行の途中から/行の途中までを抽出するため、ソースコードの重複表示としてはちょっとみにくい。
- 出現回数が多い部分が先に表示される。
などちょっと出力が見にくい面がある(結果の上から見ているとなんだか気持ち悪くなる)。
とりあえず rabin.pl をいじって、最長文字列を先に表示するようにソートの条件を変えたりして遊んでみた。 モジュールの使い方を覚えてスクリプトを自前で書くと、自分好みの重複発見ツールが書けそうだ。
- Linux で使えるデスクトップ検索ツール Beagle でローカルファイ... (2006-08-08)
- CGI プログラム、Out of memory! に泣く (2001-01-04)
- WiKicker 0.29 リリース - ビルドまわりの改良など (2006-02-13)
- 今日のさえずり - 背後に立たれていても気がつかないという恐れ (2008-09-09)
- Perl モジュール XML::DOM が Debian GNU/Linu... (1999-08-18)
2006年12月4日 (月)
■ SpeedyCGI 以下で WiKicker がうまく動かない?

WiKicker ベースのシステムが稼働しているホストが FreeBSD 5.2.1-RELEASE から FreeBSD 6.1-RELEASE に更新されるのにともない、再インストール作業を行った。
動作確認をしたところ CGI プログラムは動くものの Perl モジュール中の DATA セクションが読めていないようなエラー表示がされた。
もしやと思い SpeedyCGI を外したら正常動作。
SpeedyCGI 下で動くことを考えて、DATA セクションを1度しか読まないようにコーディングしてあるはずなのだが、はて。
他の作業もあり細かいチェックができなかったのでもしかしたら違うところでの問題かもしれないが、ちょっと厄介。
- [ WiKicker ] SpeedyCGI 対応するも…… (2003-11-09)
- Windows 上での Apache 2.0.53 では PATH_INF... (2005-04-10)
- [ Perl ] Log::Log4perlのはまりどころ (2004-03-02)
- CGI プログラム、Out of memory! に泣く (2001-01-04)
- [ WiKicker ] SpeedyCGI (2003-10-17)
2006年12月7日 (木)
■ 久しぶりに C 言語プログラムのコードレビュー

開発が順調ではないプロジェクトについて、Perl モジュールと C 言語によるプログラムのソースコードをレビューした。
非公式なコードレビューだが、ぽこぽこ問題点が見つかる。 C 言語なんて久しぶりだけれど、ぱっと見てポインタの計算が間違えていることに気がついたりして、自分もまだ捨てたもんじゃないなと。
(自分も含めて)コーディングする人は「ま、いっか」「後で」で書いてしまいがち。 で、往々にして「後で」はやってこない。
やはり他人に見てもらうことが重要。
- 第2回 社内 Perl 勉強会 (2006-04-28)
- TortoiseCVS 1.8.0-RC4 (2004-08-26)
- 今日のさえずり - 上げ潮特大号 (2008-09-18)
- 第1回 社内 Perl 勉強会 (2006-04-21)
- Algorithm::RabinKarp でソースコード中の重複を発見 (2006-08-04)
2006年12月12日 (火)
■ PAR::Repository でビルド済み Perl モジュールをネットワーク配信

@ 実行可能ファイル作成としての PAR
PAR といえば Perl スクリプトを実行可能ファイル(Windows なら EXE 形式ファイル)に変換するモジュールとして有名である。
ちなみに実行可能ファイルを作成する部分はは PAR 0.97 より PAR-Packer パッケージに分けられ、PAR 自体はインストールしやすい pure Perl なパッケージになっている。
@ PAR モジュールアーカイブからのローダとしての PAR
PAR が提供するもう一つの(こちらが本来はメイン?)機能は、プログラムの実行時に必要な Perl モジュールを PAR ファイルと呼ばれる Perl モジュールアーカイブファイルからロードする機能である。 XS モジュールなどもコンパイルすることができるどこかの環境で1度ビルドして PAR ファイルにしておけば、同じアーキテクチャのホスト上でそのまま利用することができる。
@ PAR リポジトリ
ロードしたい PAR ファイルはファイルパスだけではなく URL でも指定することができ、必要な時にオンデマンドでフェッチさせることができる。 これを使えば Perl プログラムの集中管理可能だ。
PAR 0.951 からは PAR リポジトリというコンセプトが追加され、パッケージ毎に作った PAR ファイルをサーバ上(あるいはローカル)のリポジトリに蓄積してオンデマンドでロードできるようになった。
個別に PAR ファイルを指定する従来の方式に比べてかなり便利そうである。 ということで試用してみた。
まずは
- PAR
- PAR::Repository
- PAR::Repository::Client
- PAR::Repository::Query
- PAR::Dist
- PAR::Packker
あたりをインストールし準備 OK。
@ 1. PAR リポジトリを作成する
最初に PAR-Repository に含まれている parrepo で。
parrepo create -r /tmp/PAR
PAR リポジトリファイルの中にはデータベースファイルが作成されるが、これは DBM::Deep というアーキテクチャ非依存のものを使っているので、Linux でも Windows でもどちらからでもアクセス可能である (つまり Linux 上でリポジトリをメンテできるということだ)。
@ 2. Perl パッケージを PAR ファイル化する
次に必要な PAR ファイルを作成する。 作成したいパッケージを展開してビルドし、blib ができている状態で PAR::Dist を使ってパッケージ化する。
perl Makefile.PL make make test perl -MPAR::Dist -e blib_to_par
例えば ActivePerl*1 上で WWW-Mechanize-1.20 を PAR ファイル化すると
WWW-Mechanize-1.20-MSWin32-x86-multi-thread-5.8.8.par
というファイルが作成される。
普段から ActivePerl で必要なライブラリは基本的に自前で PPM パッケージ化して、動作確認した上で PPM リポジトリに蓄積するようにしているので、合わせて次の手順でパッケージを作ることになる。
perl Makefile.PL nmake nmake test perl -MPAR::Dist -e blib_to_par make_ppm
@ 3. PAR リポジトリに PAR ファイルを登録する
PAR ファイルができたら parrepo でリポジトリに登録する。
parrepo inject -r /tmp/PAR -f xxx.par
@ 4. PAR リポジトリ上のライブラリを使用してみる
例えば先ほどの WWW::Mechanize がリポジトリに登録されている状態で
#!/usr/bin/perl
use PAR { repository => 'file:///tmp/PAR/' };
use WWW::Mechanize;
my $mech = WWW::Mechanize->new;
$mech->get('http://www.example.com');
print $mech->content;
というスクリプトを書いて実行すると、PAR リポジトリから WWW::Mechanize がロードされて正しく実行される。
ここでリポジトリを Web サーバへアップロードして、repository のところに URL を指定するようにすることもできる。 例えばリポジトリを http://www.example.com/PAR/ に配置したとすると
#!/usr/bin/perl
use PAR { repository => 'http://www.example.com/PAR/' };
use WWW::Mechanize;
my $mech = WWW::Mechanize->new;
$mech->get('http://www.example.com');
print $mech->content;
と書き換えることで、インストールしていない WWW::Mechanize を使用できるようになる。
@ Perl プログラムを実行形式化する
先ほどの Perl スクリプトを get_top_page.pl という名前で保存して pp で実行可能ファイル化する。
pp -o get_top_page.exe -M PAR::Repository::Client get_top_page.pl
とすれば get_top_page.exe という実行可能ファイルが作成される。 WWW::Mechanize はオンデマンドで http://www.example.com/PAR/ からフェッチされるので、アップデートが必要な場合は新しい PAR ファイルを作成してリポジトリを更新するだけでよい。 EXE ファイルを作成しなおして利用者に配付しなすといった作業も不要だ。
@ スクリプトもリポジトリにおく
さらには実行するスクリプトをも PAR リポジトリに置いておくことが可能だ。
例えば WWW-Mechanize に含まれている mech-dump をオンデマンドにフェッチして実行する実行形式ファイルは以下のコマンドで作成できる。
pp -o mech-dump.exe -M PAR::Repository::Client \
-e "use PAR { repository => 'http://www.example.com/PAR/', \
run => 'mech-dump' }"
@ まとめ
ActivePerl では PPM があるとはいえ、普通のユーザにちょっとしたプログラムを使ってもらうのに「ActivePerl をインストールして、PPM パッケージをインストールして、……」というのは手間すぎる。
pp で プログラムに必要なものを全てバンドルした実行形式化ファイルにするという方法ももちろんあるのだが、頻繁にアップデートするようなスクリプトの場合には、起動のための部分だけ pp で作成しておいてあとは PAR リポジトリで集中管理するというのもちょっと魅力的である。
- [ Perl ] PDL::PP で C extension を書く (2004-02-19)
- 自前 PPM リポジトリの管理 (2006-07-03)
- ActivePerl で Ming (2005-02-23)
- ActivePerl 5.8.8.820 の PPM では ppd/tar... (2007-02-05)
- Wineを入れてみる (2005-03-31)
2006年12月15日 (金)
■ Perl スクリプトを PAR ファイルにして PAR リポジトリに登録する

PAR リポジトリから Perl モジュールをネットワーク配信するためには、以下の手順で PAR ファイルを作成する。
perl Makefile.PL make make test perl -MPAR::Dist -e blib_to_par
blib ディレクトリ以下のファイルもとに PAR ファイルが作成されるので、でき上がった PAR ファイルを リポジトリに登録すれば良い(PAR::Repository でビルド済み Perl モジュールをネットワーク配信)。
ではちょっとした Perl スクリプトを PAR リポジトリからロードして使えるようにするにはどうすればよいか。もちろん h2xs などで一式そろえ make して blib ツリーを作るようにすればいいが、たった 1 つのスクリプトファイルだけの時などは大袈裟だ。
この場合は pp でいける。
echo 'print "hello world!"' > myscript.pl pp -o myscript.par -p myscript.pl parrepo inject -r /tmp/PAR myscript.par -v 1.00 \ -a MSWin32-x86-multi-thread -p 5.8.8 \ --any-arch --any-version
スクリプトのメタデータがないので、parrepo に登録する際に明示的にオプションで指定してあげる必要がある。
- -v
- プログラムのバージョン番号
- -a
- アーキテクチャ
- -p
- Perl のバージョン
- --any-arch
- アーキテクチャ非依存で動くならば指定しておく
- --any-version
- 任意の Perl のバージョンで動くならば指定しておく。
PAR ファイル(にした Perl スクリプト)が --any-arch で --any-version であっても、-a と -p は必須だ (PAR::Repository の中にアーキテクチャ/バージョンつきで登録された上でシンボリックリンクの形で any 扱いにされるため)。
これで PAR リポジトリからスクリプトを実行できるようになる。 スクリプトの更新もリポジトリ側で行うだけで良くなる。
perl -e "use PAR { repository => 'http://www.example.com/PAR/',
run => 'myscript.pl'}"
お好みで実行形式ファイルにしておけば Perl をインストールすることなく実行できるようになるので便利。
pp -o myscript.exe -M PAR::Repository::Client \
-e "use PAR { repository => 'http://www.example.com/PAR/',
run => 'myscript.pl'}"
ちなみに PAR リポジトリを使わずに、直接 PAR ファイルを指定して実行できることもできる。
perl -e "use PAR { file => 'http://www.example.com/myscript.par', \
run => 'myscript.pl' }
ちょっとした用途ではこちらでも良いけれど、アーキテクチャ別の管理やらモジュールの管理やらを考えると PAR リポジトリを作ってしまった方が楽。
- PAR::Repository でビルド済み Perl モジュールをネット... (2006-12-12)
- Module::Build でソースパッケージング (2005-08-24)
- 「依存関係検査のしにくいモジュール」に依存するスクリプトをPARで実行形式化する (2005-03-08)
- 野良パッケージと依存 Perl モジュールのインストールセット をCPAN... (2006-02-11)
- PostgreSQL を使いはじめる (1999-12-17)
2007年1月8日 (月)
■ iCalendar 形式経由でスケジュールを社内 Blog に表示

仕事用に Skype 名を作成し、ついでに社内 Blog に Skype ボタンを貼りつけてログイン状態を表示できるようにしてみた。
そういえば電話もそうなんだけれど、本社に連絡を取るとき「もしかして会議中?」などと勘繰ってかけるかどうか迷ってしまうことがある。 かけたい人の予定がわかればいいのになと。
ならば逆もしかりだろうということで、自分の仕事のスケジュールを晒してみようと思いついた。 グループウェアとかそういうのは大袈裟なので、まずは社内 Blog のサイドバーに表示するようにしたい。
ということでこの3連休に実装してみた。
@ 構成
@ 入力
完全なスケジュールはほぼ日手帳に手書きで管理しているので、ミーティング・外出など晒しカテゴリのイベントだけを、電子化する必要がある。 手で HTML 毎回ごりごり書き直すのも嫌なので、スケジュール管理ソフトを使いたい。 この部分は KDE の KOrganizer を使うことにした。
@ サーバへアップロード
で、KOrganizer のスケジュールを iCalendar 形式でエクスポート。 このファイルを社内 Blog を配信しているサーバに rsync で転送。
この処理はちょっと手間なので自動化したいところ。
@ 社内 Blog 内表示用 JavaScript Include ファイル生成 CGI プログラム
この iCalendar 形式ファイルを読み込んで、今日以降の10件(程度)を HTML フラグメントに変換し JavaScript プログラム (document.write() 列) として出力する Perl CGI プログラムを作成。
iCalendar の形式の読み込みについては Data::ICal や iCal::Paraser などの Perl モジュールを利用できる。 今回はシンプルに使えそうな iCal::Parser をチョイス。 基本的には
use iCal::Parser; my $parser = iCal::Parser->new; my $calendar = $parser->parse($ics_file_name);
で読み込んだデータがハッシュリファレンスとして $calendar に設定される。 イベントは $calendar->{2007}->{01}->{01}->{$uid} のように「年、月、日、イベントUID」のハッシュ階層として格納されているので、これを読み出せばよい。
@ 社内 Blog サイドバーに表示
で、この CGI プログラムが生成する JavaScript プログラムをサイドバーで JavaScript Include。
まずは表示までできるようになった。
これで
をまとめて公開できる社内 Blog にアップグレード。
おいおいスケジュールの表示デザインとかは改良していきたい。 hCalendar 形式にして CSS でデザインするのがいいのかな。
- Plagger のインストールが大変なので XML::RSS で RSS ... (2006-06-10)
- Hyper Estraier で社内 Web コンテンツ検索 (2006-06-01)
- WiKicker に JSON でのページ出力機能を追加 (2007-04-03)
- [ DiKicker ] くっつき BBSをくっつけてみた。 (2004-05-04)
- [ WiKicker ] 憧れのサイドバー (2004-01-23)
2007年4月3日 (火)
■ WiKicker に JSON でのページ出力機能を追加

最近は DiKicker ばかりに手を入れていたが、久しぶりに WiKicker の改良も行っている。 しばらく前から実装を始めていた JSON 形式での出力機能が今日完成。
今までは WikiPage について
という2つの出力形式を持っていたので、JSON が加わることで3つめとなる。
@ サーバ側で WikiPage の構文解析まではやる
クライアントサイドの JavaScript でページの内容に合わせて様々な処理をできるように、サーバ側で構文解析まではしてあげるというのが主な目的。
JavaScript でまたパーサを書いてメンテしていくのも大変なので、その部分はサーバでやってしまおうかと。 構文解析した結果の解析木を JSON 形式で返して、JavaScript 側であとはお好きにという形。
@ CPAN にある JSON モジュールを使用
サーバ側の Perl プログラムには、構文解析をして解析木を作れるようになっている。 この解析木から Visitor パターンで JSON 形式を生成していく。
依存モジュールを増やすことを避けるべく、最初は自前で JSON 形式に変換していこうと思ったのだがやっぱり面倒だった。 ということで CPAN にあるモジュールをチョイス。
JSON 関連では JSON、JSON::Syck、JSON::PC などがあるが今回はインストールのしやすさを考えて pure Perl モジュールとして実装されている JSON を採用することにした。
Visitor クラスで解析木を無名ハッシュ/無名配列のツリーに変換して、JSON モジュールに流しこめば OK。
use JSON; my $json = JSON->new(pretty => 1); my $js = $json->objToJson($tree);
WiKicker のフレームワークにはフォーマット別に出力を切り換える機構があるので、これに JSON を追加して application/json で送るようにして完成。
ちなみに残念ながら JSON 1.07 は Perl 5.005_03 では make test が fail するので、NaneyOrgWiki では使えない。
- Rubric でプライベート SBS を立てるも 0.140 では日本語に不具合 (2006-07-22)
- [ WiKicker ] hell mode - HTMLタグ付けブロックの導入 (2005-09-13)
- WiKicker の Makefile.PL を Module::Inst... (2006-02-10)
- 野良パッケージと依存 Perl モジュールのインストールセット をCPAN... (2006-02-11)
- WiKicker 0.29 リリース - ビルドまわりの改良など (2006-02-13)
2007年4月7日 (土)
■ 携帯電話(iモード)から Twitter を更新する

Twitter をいろいろ遊んでみて「やはり携帯電話から更新できないと」と思えてきた。
携帯電話からメールを送る事で Twitter にアップデートをかけてくれるゲートウェイを設置できれば一番いいのだけれど、そのようなメールアドレスを作る場所が今はない(さすがに会社のサーバはまずい)。
ということでiモードから更新をかけられるように短い CGI プログラムを書くことにした。 CPAN には Net::Twitter という Perl モジュールがあるのだが、JSON::Any (と JSON::XS / JSON / JSON::DWIW / JSON::Syck のどれか)が必要で、ちょっと大げさなので今回は使用は見送り。 普通に CGI.pm と LWP::UserAgent で書いた。
#!/usr/bin/perl -w
use 5.005_03;
use strict;
use CGI qw(-no_xhtml);
use Jcode;
use LWP::UserAgent;
my $query = CGI->new;
my $user_name = $query->param('u');
my $password = $query->param('p');
my $status = $query->param('s');
$user_name = '' unless defined $user_name;
$password = '' unless defined $password;
$status = '' unless defined $status;
my $message = '';
if ($user_name ne '' && $password ne '' && $status ne '') {
my $ua = LWP::UserAgent->new;
Jcode::convert(\$status, 'utf8', 'sjis');
$ua->credentials('twitter.com:80', 'Twitter API', $user_name, $password);
my $request = $ua->post('http://twitter.com/statuses/update.json',
{status => $status . ' '});
if ($request->is_success) {
$message = '<p>OK</p>';
}
}
print $query->header(-type => 'text/html', -charset => '');
print '<html><head><title>Twitter update</title></title><body>';
print '<form method="post" action="twitter">';
print 'ユーザ名:', $query->textfield('u'), '<br>';
print 'パスワード:', $query->password_field('p'), '<br>';
print 'ステータス:', $query->textfield('s'), '<br>';
print '<input type="submit">';
print '</form>';
print $message;
print '</body></html>';
とりあえずこれで、iモードから送信できることを確認。 パスワードの入力が面倒だけれども、サーバ側に書いておくのも嫌なので毎回送ることにした。FOMA 端末側には定型文として保存しておく以外にいい手はないのかな。
最初うまく送れなくてなんだろうと思ったが、あきやん氏の「Twitterで日本語を入力する方法 (akiyan.com)」の記事にある
- 全て全角文字で入力して、最後に半角スペースをいれる
- 半角全角を混在させるときは、半角文字と全角文字の間にスペースをいれる
といった日本語を入力する際の注意点がらみだったようである。 とりあえず CGI プログラムの方で最後に必ずいわゆる半角空白を追加するようにしておいた。
文字数チェックとか Twitter API の返り値チェックとか、改善すべきところはいろいろあるけれど、自分用にはまずこれでいいかな。
気が向いた時に外出先から更新かけます。
- 携帯電話からの Twitter 投稿に tmitter を使ってみることにした (2007-07-26)
- MAILPIA による Twitter リプライチェック (2008-11-18)
- ケータイ用にプライベート Wiki を設置 (2008-01-07)
- Twitter を使い始めて1年 (2008-04-06)
- 半分は Twitter のためにパケ・ホーダイを契約 (2007-08-01)
2007年12月29日 (土)
■ Twitter ベイジアンフィルタプロキシ

Twitter で following が増えてくるにつれて、タイムラインに目を通すのが大変になってきた(という程きちんと見ている訳ではないが)。 さっとタイムラインをなめて面白そうな情報をピックアップしたい時は、「おはよう」とか「風呂入った」とか「トイレ」とかは除外して読みたい(そういう書き込み自体は嫌いじゃないのだが、人生はあまりにも短い)。
Twit や P3:PeraPeraPrv では NG ワード指定ができて、それらを含むステータスは表示しないようにできるのだが、Twitter の書き込みは揺らぎが激しすぎて指定しきれないという弱点がる。
ということでベイジアンフィルタでフィルタリングしてみることにした。
自前で Twitter クライアントを作る気はないので、proxy の形でさっと実装してみた。
#!/usr/bin/perl
use strict;
use warnings;
use HTTP::Proxy;
use HTTP::Proxy::BodyFilter::complete;
my $proxy = HTTP::Proxy->new(port => 8088);
$proxy->push_filter(response => HTTP::Proxy::BodyFilter::complete->new,
mime => 'application/xml');
$proxy->push_filter(response => Bsfilter->new,
mime => 'application/xml');
$proxy->start;
{
package Bsfilter;
use File::Temp qw/tempfile/;
use XML::XPath;
use base qw(HTTP::Proxy::BodyFilter);
sub filter {
my ($self, $dataref, $message, $protocol, $buffer) = @_;
return unless defined($$dataref) && $$dataref ne '';
eval {
my $xml = XML::XPath->new(xml => $$dataref);
my @nodes = $xml->findnodes('/statuses/status/text/text()');
return unless @nodes;
for my $node (@nodes) {
my $text = $node->getNodeValue;
if (is_NG($text)) {
$node->setNodeValue("[NG] $text");
}
}
$$dataref = qq(<?xml version="1.0" encoding="UTF-8"?>\n);
$$dataref .= $xml->get_context->toString;
utf8::encode($$dataref);
};
if ($@) {
warn $@;
}
}
sub will_modify { 1 }
sub is_NG {
my ($text) = @_;
my ($fh, $filename) = tempfile();
utf8::encode($text);
print $fh $text;
close($fh);
my $result
= system(
"bsfilter --homedir ~/.twitter-bsfilter --ignore-header --auto-update $filename"
);
unlink($filename);
return !$result;
}
}
@ HTTP proxy の作成
Perl で HTTP proxy を作ろうとして真っ先に思い浮かんだのは POE だけれど、ちょっとヘビーなので今回は HTTP::Proxy をチョイス。 もともとフィルタリング HTTP proxy を作ることを念頭に置いた Perl モジュールなので今回の目的にぴったり。
1つはまった点といえば、filter の呼び出しがレスポンス全てを取得してからではなく一部分ずつの呼び出しになるところ。その仕様に気がつくのにちょっと時間がかかってしまった。 例えば XML 形式のレスポンスをフィルタしようとしても、普通に HTTP::Proxy を使うと XML の一部ずつがフィルタに渡されるため、XML のパースがうまくいかない。
これについては HTTP::Proxy::BodyFilter::complete を使うことで、まとめてフィルタに渡せるようになった。
@ レスポンスの処理
Twitter のタイムライン取得については P3:PeraPeraPrv が XML 形式で取得しているので、そのタイプのレスポンスをフィルタするようにした。
XML::XPath でステータス部分を抜き出して NG 判定し、NG であれば先頭に [NG] を追加する。 これで Twitter クライアント側で [NG] を NG ワード指定すれば、表示されないようにすることができる。
@ bsfilter による NG 判定
NG 判定は普段メールの spam フィルタとして使っている bsfilter を使った。 単純に system 関数で呼び出して結果を取得するだけ。
今回は対象がメールではないので --ignore-header を指定。また自動的に学習するように --auto-update を指定。 それと普段メールのフィルタリングに使っているのとは bsfilter のデータベースを別にしたいので、--homedir も指定しておく。
@ NG と非 NG の学習。
NG ワードを twitter-NG.txt に、非 NG ワードを twitter-clean.txt に書いて以下のコマンドを実行。
bsfilter --add-clean --ignore-header --homedir ~/.twitter-bsfilter twitter-clean.txt bsfilter --add-spam --ignore-header --homedir ~/.twitter-bsfilter twitter-NG.txt bsfilter --update --homedir ~/.twitter-bsfilter
自分の環境 (Debian GNU/Linux sid)では、UTF-8 で書いておいて問題なかった。
@ フィルタリングしてみる
あとは先の proxy を起動し、P3:PeraPeraPrv でプロキシとして localhost:8088 を指定すれば OK。
タイムラインを取得するたびに bsfilter が動いて NG なステータスには [NG] が挿入される。
@ フィルタリングの精度
これについては、まだまだチューンの必要ありかな。
- 事前の学習データが少ない。
- --auto-update していることもあり、最初に NG 判定が多いとそちら側に強化されすぎる。
- 毎回 bsfilter を呼んでいるため、同じステータスが何度も学習される。
まだ使える精度まで上がってないけれど、教師データを増やせばそれなりにいけるかもしれない。
proxy の枠組ができたので、(@~は抜いてから bsfilter に渡すとか、前後の文脈も含めるとか)いろいろ試して遊べそうではある。 別に bsfilter にこだわらず、正規表現による判定などをしてもよいし。
この辺り P3 は Java で書かれているので、プラグインを書いて拡張できるよう将来になると面白いなと思ってみたり。
- ColdSync (2004-05-05)
- MAILPIA による Twitter リプライチェック (2008-11-18)
- POE で HTTP プロキシサーバ (2005-10-15)
- 今日のさえずり - サーバ止めた。この静寂がたまらない。 (2008-11-16)
- PAR (2004-07-19)
スポンサード リンク
■よく検索されるキーワード
perl(62) torrent(54) linux(48) 提案書(47) windows(43) 書き方(41) 使い方(29) アジェンダ(26) x31(25) 充電式カイロ(25) cvs(22) インストール(20) サンプル(20) thinkpad(19) アジェンダとは(19) f-01a(18) wiki(17) c#(16) 感想(16) カイロ(16) usb(16) java(16) 秋葉原(15) debian(15) ヨドバシカメラ(15) subversion(15) 壁紙(15) 作り方(15) 静電気(14) apache(14) グッズ(14) デロンギ(13) フリー(13) sh-01a(13) ganttproject(13) 修理(13) ssh(12) svn(12) ヨドバシ(12) truecrypt(12) ダイソー(11) 手帳(11) activeperl(11) ubuntu(11) ほぼ日手帳(11) firefox(10) mew(10) mp980(10) ドラマ(10) 日本語(10) n-01a(10) google(10) tc-1(10) 評判(10) ツール(10) djunit(9) cgi(9) 動画(9) mp3(9) オイルヒーター(9) docomo(9) rcs(9) 除去(9) centos(9) メモリ(9) エネループ(9) 設定(9) p-01a(9) tortoisesvn(9) 無印(8) ケース(8) 口コミ(8) ミノルタ(8) メール(8) インストーラ(8) 会議(8) xampp(8) 加湿器(8) af(7) 値段(7)■注目キーワード
購入 買った 発売日 フリー 無料 価格 値段 作り方 選び方 使い方 方法 設定 サンプル ダウンロード 限定 在庫 予約 穴場 比較 検証 レビュー 感想 評価 評判 使用感 使ってみた 口コミ 噂 最新 MP3 動画 意味 お薦め お勧め おすすめ 便利 Blog ブログ mixi 修理 デザインProcess Time: 15.154621s / load averages: 0.26, 0.49, 0.56
nDiki by WATANABE Yoshimasa (profile)
Powered by DiKicker
Base theme by Nana (for tDiary)



スポンサード リンク