« 2004年05月 | メイン | 2005年03月 »

2004年08月05日

二重起動の防止

あるプログラムが走っているときに、同時に同じプログラムを起動させたくないときがある。Windows 環境であれば mutex オブジェクトを使うことができ、Perl にも Win32::Mutex モジュールが存在する。
use Win32::Mutex;
die "二重起動" if(Win32::Mutex->open('hogehoge'));
$mutex=Win32::Mutex->new(1, 'hogehoge');
while(1){
    print ++$n,"\n";
    sleep(5);
};
2行目で他に hogehoge という名前の Mutex オブジェクトが作られていないかどうかチェックし、もし他で hogehoge という名の Mutex オブジェクトが作られていれば、先へ進まずに終了する。3行目では hogehoge という Mutex オブジェクトを作成している。
したがって、このスクリプトを2つ起動しようとしても、2つ目は2行目のチェックで引っかかって終了してくれるはずである。

ただし、タイミングによっては完璧ではないようだ。

投稿者 augustus : 22:19 | コメント (0) | トラックバック

2004年08月03日

CSV の行を分解

CSVをコンマで分けるのは一見簡単そうであるが、実は奥が深い。Perl では Text::CSV_XS モジュールを使うのが便利だ。

たとえば、split 関数を使って「,」で分ければ、次のような単純な例はうまくいく。
$line='A,BB,CCC,,D';
@values=split(/,/,$line);
しかし、これでは「,」や「"」を含む値を適切に扱うことはできない。値の中に「,」や「"」を含むときは値を「"」で囲み、含まれる「"」は「""」と記述するのだが、単純に「,」で切っては当然うまくいかない。

Perlメモ(http://www.din.or.jp/~ohzaki/perl.htm#CSV2Values)に詳しくやり方が書いてあった。難しくて解読困難だ。(^^;
$tmp=$line='"""北海道,札幌市""",ABC,"XX,XX","abc"';
$tmp=~s/(?:\x0D\x0A|[\x0D\x0A])?$/,/;
@values=map {/^"(.*)"$/?scalar($_=$1,s/""/"/g,$_):$_}
        ($tmp =~ /("[^"]*(?:""[^"]*)*"|[^,]*),/g);

Text::CSV_XS を使って以下のようにすることもできる。日本語を扱わないなら {binary=>1} は不要である。
use Text::CSV_XS;
$csv=Text::CSV_XS->new({binary=>1}); #create a object
$line='"北海道,札幌市",ABC,"XX,XX","""abc"""';
$status=$csv->parse($line);          #parse a string
@values=$csv->fields();              #get the fields
print join("\n",@values);
Text::CSV_XS は Active Perl なら標準で含まれているからこれが便利だろう。

投稿者 augustus : 22:36 | コメント (0) | トラックバック

perl でリンクを抽出する

perl でリンクを抽出するには HTML::LinkExtor モジュールを使うのが便利だ。
$p = HTML::LinkExtor->new([$callback[, $base]]);
まずは LinkExtor オブジェクトを作るわけだが、 callback 関数を指定しておくと、 リンクを見つけるたびに callback 関数が呼び出される。 callback 関数を指定していないときは $p->links で 含まれるリンクを明示的に読み出すことができる。
$base を指定しておくと、相対パスで指定されたリンクを 自動的に $base を基準にしたものとみなして絶対パスに直してくれる。

文字列からリンクを抽出したいときは $p->parse($strings) とするが、 ファイルからリンクを抽出するときは $p->parse_file($filename) とする。

では、http://www.augustus.to/ に含まれるリンクを抽出してみよう。
use LWP;
use HTML::LinkExtor;

$url="http://www.augustus.to/";
$browser = LWP::UserAgent->new;
$response = $browser->get($url);

$p = HTML::LinkExtor->new(\&callback,$url);
$p->parse($response->{_content});

sub callback {
    my($tag, %links) = @_;
    print "$tag @{[%links]}\n";
}

callback 関数を使わないならこんな感じ。
use LWP;
use HTML::LinkExtor;

$url="http://www.augustus.to/";
$browser = LWP::UserAgent->new;
$response = $browser->get($url);

$p = HTML::LinkExtor->new(unlink(),$url);
$p->parse($response->{_content});
for $x ($p->links){
    print join(" ", @{$x}),"\n";
}

投稿者 augustus : 08:54 | コメント (0) | トラックバック

2004年08月02日

perl で cookie を取得

perl で web ページにアクセスするとき、クッキーを取得したいときもあるだろう。そういうときは HTTP::Cookies モジュールを使えばよい。
以下の例のようにするとページのソースが表示されるとともに、クッキーが指定されたファイルに保存される。
use LWP;
use HTTP::Cookies;

$url="http://www.amazon.co.jp/"; #アクセスする URL
$file="cookies_amazon.txt";      #クッキーを保存するファイル

$browser = LWP::UserAgent->new;
$browser->cookie_jar({file =>$file, autosave=>1 });
$response = $browser->get($url);
print $response->{_content};

投稿者 augustus : 21:24 | コメント (0)

2004年08月01日

ユーザ認証を要するページにperlでアクセス

BASIC認証またはDIGEST認証を要求する web ページに perl でアクセスしたいときには LWP::UserAgent モジュールの credentials メソッドが使える。
実験用に用意した http://www.augustus.to/test/authtest/ にアクセスしてみよう。領域名は Auth_Test、ユーザ名は authtestuser、パスワードは password である。スクリプトは以下のようになる。
use LWP;
use HTTP::Request::Common;

$domain="www.augustus.to";
$port=80;
$realm="Auth_Test";   #領域名
$user="authtestuser"; #ユーザ名
$passwd="password";   #パスワード
$url="http://www.augustus.to/test/authtest/";

$browser = LWP::UserAgent->new;
$browser->credentials(
    "$domain:$port",$realm,$user,$passwd);
$response = $browser->get($url);
print $response->{_content};

投稿者 augustus : 21:07 | コメント (2) | トラックバック