<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <title>perl-mongers.org</title>
    <link rel="alternate" type="text/html" href="http://perl-mongers.org/" />
    <link rel="self" type="application/atom+xml" href="http://perl-mongers.org/atom.xml" />
    <id>tag:perl-mongers.org,2008-05-19://1</id>
    <updated>2008-10-10T12:07:30Z</updated>
    <subtitle>Yet Another Perl Mongers</subtitle>
    <generator uri="http://www.sixapart.com/movabletype/">Movable Type 4.21-en</generator>

<entry>
    <title>HTMLから本文を抜き出せるモジュールHTML::ExtractContent </title>
    <link rel="alternate" type="text/html" href="http://perl-mongers.org/2008/10/extract-content-from-html.html" />
    <id>tag:perl-mongers.org,2008://1.83</id>

    <published>2008-10-10T11:44:31Z</published>
    <updated>2008-10-10T12:07:30Z</updated>

    <summary><![CDATA[こういうの無いかなぁと思ってました。 例えば任意のサイトのサマリを作りたい時、HTMLをテキスト化して一定文字数で削る訳ですが、どこからどこまでが本文かはそのサイト製作者の意図する所であってなかなか難しい処理かと思います。 今回ご紹介するHTML::ExtractContentはHTMLの内容を判断しコンテンツの本文らしき部分を抜き出せる凄いモジュールです。 ソースを見ましたがテキストに含めるかどうかの閾値が設定されており、かつ句読点まで判断しています。ソースはutf-8で書かれており、おそらく作者は日本人(もしくは日本通)かと思われます。 試しに先日の記事URLから本文を抜き出してみたいと思います。 use strict; use warnings; use HTML::ExtractContent; use LWP::UserAgent; my $agent = LWP::UserAgent-&gt;new; my $res = $agent-&gt;get(&#39;http://perl-mongers.org/2008/09/template-refine.html&#39;); my $extractor = HTML::ExtractContent-&gt;new; $extractor-&gt;extract($res-&gt;decoded_content); print $extractor-&gt;as_text; コードもこれだけ。そして実行結果。 Template::Refineというモジュールを見つけました。リンク先にある通り、ruleを使うことで簡単にテンプレートの値を置き換える事が出来ます。このモジュールの良い所は、テンプレートファイルにテンプレートエンジン専用の識別子を記述しなくて良い所。どうやって指定するかというと、XPathを使います。リンク先から引用すると my $username = &#39;Test User&#39;; my $rule = simple_replace {...]]></summary>
    <author>
        <name>mattn</name>
        <uri>http://mattn.kaoriya.net/</uri>
    </author>
    
    <category term="htmlextractcontent" label="HTML::ExtractContent" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://perl-mongers.org/">
        <![CDATA[<p>こういうの無いかなぁと思ってました。</p>
<br />
<p>例えば任意のサイトのサマリを作りたい時、HTMLをテキスト化して一定文字数で削る訳ですが、どこからどこまでが本文かはそのサイト製作者の意図する所であってなかなか難しい処理かと思います。</p>
<p>今回ご紹介する<a href="http://search.cpan.org/dist/HTML-ExtractContent/">HTML::ExtractContent</a>はHTMLの内容を判断しコンテンツの本文らしき部分を抜き出せる凄いモジュールです。</p>
<p>ソースを見ましたがテキストに含めるかどうかの閾値が設定されており、かつ句読点まで判断しています。ソースはutf-8で書かれており、おそらく作者は日本人(もしくは日本通)かと思われます。</p>
<p>試しに<a href="http://perl-mongers.org/2008/09/template-refine.html">先日の記事URL</a>から本文を抜き出してみたいと思います。</p>
<pre class="prettyprint">
use strict;
use warnings;
use HTML::ExtractContent;
use LWP::UserAgent;

my $agent = LWP::UserAgent-&gt;new;
my $res = $agent-&gt;get(&#39;http://perl-mongers.org/2008/09/template-refine.html&#39;);

my $extractor = HTML::ExtractContent-&gt;new;
$extractor-&gt;extract($res-&gt;decoded_content);
print $extractor-&gt;as_text;</pre>
<p>コードもこれだけ。そして実行結果。</p>
<pre>
Template::Refineというモジュールを見つけました。リンク先にある通り、ruleを使うことで簡単にテンプレートの値を置き換える事が出来ます。このモジュールの良い所は、テンプレートファイルにテンプレートエンジン専用の識別子を記述しなくて良い所。どうやって指定するかというと、XPathを使います。リンク先から引用すると
my $username = &#39;Test User&#39;;
my $rule = simple_replace {
my $node = shift;
return replace_text $node, $username;
} &#39;//*[@class=&quot;username&quot;]&#39;;
といった感じにルールを決め
$frag = $frag-&gt;process($rule);
say $frag-&gt;render;
と実行する事でテンプレートへの反映が行われます。まるでWeb::Scraperの様ですね。
今日はサンプルとして、美輪明宏のチンコの有無を返すAPIから得た結果をテンプレートに反映してみたいと思います。
まずテンプレート
&lt;p&gt;美輪明宏にチンコは...&lt;span class=&quot;miwa&quot;&gt;...&lt;/span&gt;。&lt;/p&gt;
確かにテンプレート専用の識別子は使用していません。そしてperlのコード
use strict;
use warnings;
use Encode;
use Perl6::Say;
use LWP::Simple;
use JSON;
use Template::Refine::Fragment;
use Template::Refine::Utils qw(replace_text simple_replace);
my $miwa = from_json(get &quot;http://dzfl.jp/mojo/&quot;);
my $rule = simple_replace {
my $node = shift;
return replace_text $node, encode_utf8($miwa-&gt;{miwa} ? &#39;ある&#39; : &#39;ない&#39;);
} &#39;//*[@class=&quot;miwa&quot;]&#39;;
my $frag = Template::Refine::Fragment-&gt;new_from_file(&#39;template.html&#39;);
print $frag-&gt;process($rule)-&gt;render;
HTMLのmiwaというクラス属性を持ったノードに対して&quot;ある&quot;/&quot;ない&quot;というテキストで置換しています。
簡単ですね。テンプレートエンジン専用の識別子を使用しないので、HTMLの属性値さえ決めておけば、テンプレートの殆どをデザイナさんに任せてしまう事も出来る様になります。
すばらしいですね。</pre>
<p>ちゃんと本文が取れています。ヘッダ部やページ右にあるナビゲータの文字は含まれていません。</p>
<p>すばらしいですね。他のアプリケーションにも簡単に取り込めそうですし期待が膨らみます。</p>
<br />
<p>どなたかこれを使ったウェブサービスを作ってみませんか。</p>

]]>
        
    </content>
</entry>

<entry>
    <title>実用！ Perlでクロネコヤマト荷物照会</title>
    <link rel="alternate" type="text/html" href="http://perl-mongers.org/2008/09/perl-kuronekoyamato.html" />
    <id>tag:perl-mongers.org,2008://1.82</id>

    <published>2008-09-21T09:44:06Z</published>
    <updated>2008-09-23T17:49:05Z</updated>

    <summary>仕事をしていると、荷物を宅配便で送る業務っていうのがあるんですけれども、宅配便業者さんに引き渡した後、ちゃんと届いたか確認したいってことありますよね。 というわけで、今回はPerlでクロネコヤマトの荷物照会のページをスクレイピングして、荷物の状況表示を回収するPerlスクリプトです。 応用すると、未配達の荷物を追跡して問い合わせるロボットなんかが作れるかもしれません。 今回は、モジュールにしてみましたので、ディレクトリをしっかり掘って使ってみてください。 Filename: WebService/KuronekoYamato.pm package WebService::KuronekoYamato; use warnings; use strict; use Carp; use version; our $VERSION = qv(&#39;0.0.1&#39;); # Other recommended modules (uncomment to use): # use IO::Prompt; # use Perl6::Export; # use Perl6::Slurp; # use Perl6::Say; use...</summary>
    <author>
        <name>CL</name>
        <uri>http://blog.dtpwiki.jp/dtp/</uri>
    </author>
    
    <category term="webscraper" label="Web::Scraper" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="wwwmechanize" label="WWW::Mechanize" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://perl-mongers.org/">
        <![CDATA[<p>仕事をしていると、荷物を宅配便で送る業務っていうのがあるんですけれども、宅配便業者さんに引き渡した後、ちゃんと届いたか確認したいってことありますよね。</p>
<p>というわけで、今回はPerlでクロネコヤマトの荷物照会のページをスクレイピングして、荷物の状況表示を回収するPerlスクリプトです。</p>
<p>応用すると、未配達の荷物を追跡して問い合わせるロボットなんかが作れるかもしれません。</p>
<p>今回は、モジュールにしてみましたので、ディレクトリをしっかり掘って使ってみてください。</p>
<p>Filename: WebService/KuronekoYamato.pm</p>
<pre class="prettyprint">
package WebService::KuronekoYamato;
 
use warnings;
use strict;
use Carp;
 
use version; our $VERSION = qv(&#39;0.0.1&#39;);
 
# Other recommended modules (uncomment to use):
#  use IO::Prompt;
#  use Perl6::Export;
#  use Perl6::Slurp;
#  use Perl6::Say;
use Encode;
use WWW::Mechanize;
use Web::Scraper;
use YAML::Syck;
 
 
# Module implementation here
 
# コンストラクタ
sub new {
  my ( $class ) = shift;
  my $mech = WWW::Mechanize-&gt;new();
  $mech-&gt;agent_alias( &#39;Windows IE 6&#39; );
  $mech-&gt;get(&#39;http://toi.kuronekoyamato.co.jp/cgi-bin/tneko?init&#39;);
  my $self = { mech =&gt; $mech, };
  bless $self;
}
 
# ヤマト運輸に問い合わせ
sub check {
  my $self    = shift;
  my $numbers = shift; # 荷物問い合わせ番号のリストのリファレンス
  # フォームの問い合わせは10件ごとなので10件ごとのリストのリストにする
  my $list; # 10件ごとに分割されたリストのリストが入る
  my $j = -1; #添え字調整
  foreach ( my $i = 0; $i &lt; $#$numbers + 1; $i++ ) {
    $j++ unless $i % 10;
    push @{$list-&gt;[$j]}, $numbers-&gt;[$i];
  }
  # _requestを呼んで実際にWebアクセスする
  my $result = [];
  foreach my $item( @$list ) {
    my $res = _request($self, $item);
    push @$result, @$res; # 返答は最大10件なので、$resultにためていく
  }
  return $result; # 集まったリストを返す
}
 
# 実際にリストからアクセスする
sub _request {
  my $self = shift;
  my $list = shift;
  $self-&gt;{mech}-&gt;form_number(1);
  for ( my $i = 0; $i &lt; $#$list + 1; $i++) {
    my $field = sprintf &quot;number%02d&quot;, $i+1;
    $self-&gt;{mech}-&gt;set_fields( $field =&gt; $list-&gt;[$i]);
  }
  $self-&gt;{mech}-&gt;submit;
  
  # Web::Scraper による解析
  my $s = scraper {
    process &#39;//tr/td[1]/input/../../td[2][contains(. , &quot;-&quot;)]/..&#39;,
    &#39;tneko[]&#39; =&gt; scraper {
      process &#39;//td[2]&#39;,
      number =&gt; &#39;TEXT&#39;,
      process &#39;//td[3]&#39;,
      date =&gt; &#39;TEXT&#39;,
      process &#39;//td[4]&#39;,
      status =&gt; &#39;TEXT&#39;,
    },
  };
  my $res = $s-&gt;scrape( # Shift_JISをUTF-8に変換
              encode(&#39;utf8&#39;, decode(&#39;cp932&#39;, $self-&gt;{mech}-&gt;content() ) )
            );
  # 得られた結果をリストで返す
  return $res-&gt;{tneko};
}
 
sub dump {
  my $self = shift;
  print Dump($self);
  return;
}
 
1; # Magic true value required at end of module
__END__</pre>

使うときは、

<pre class="prettyprint">
#!/usr/bin/perl
 
use lib qw(lib/);
package main;
use strict;
use warnings;
use YAML::Syck;
use WebService::KuronekoYamato;
use utf8;
 
 
my $n = WebService::KuronekoYamato-&gt;new();
my $res = $n-&gt;check([
  240000000000,
  240000000011,
]);
 
print Dump($res);
exit;</pre>

<p>こんな感じで使うといいんじゃないでしょうか。身の回りにあるクロネコヤマトの発送伝票で試してみてください。</p>
<p>ねえよ。</p>
<p>今回のは、CoreReposにも置いてあります。正直言ってPerlのモジュールやらオブジェクト指向がよくわかっていないっぽいので、修正してもらえればなあとも思ってたり。</p>
<p><a href="http://svn.coderepos.org/share/lang/perl/WebService-KuronekoYamato/">http://svn.coderepos.org/share/lang/perl/WebService-KuronekoYamato/</a></p>
<p>～～～</p>
<p>このようなスクリプトがあったところで、大事なのは、荷物が動いていなかったときの交渉と手配だったりすることは言うまでもありません。</p>
<p>今回のエントリは、<br />
<a href="http://blog.dtpwiki.jp/dtp/2007/08/user_scriptoper_7948.html">M.C.P.C.: クロネコヤマトの荷物お問い合わせシステムでテキストボックスへフォーカスを合わせるUser Script（Opera用）</a><br />
<a href="http://blog.dtpwiki.jp/dtp/2006/09/plagger_6158.html">M.C.P.C.: Plaggerでクロネコヤマトの荷物お問い合わせが出来ればいいよね</a><br />
あたりが元ネタです。</p>]]>
        
    </content>
</entry>

<entry>
    <title>perlはモジュール(cpan)がすてき！</title>
    <link rel="alternate" type="text/html" href="http://perl-mongers.org/2008/09/perlcpan.html" />
    <id>tag:perl-mongers.org,2008://1.81</id>

    <published>2008-09-12T14:37:33Z</published>
    <updated>2008-09-12T15:08:12Z</updated>

    <summary><![CDATA[大阪から、こんばんはこんばんは！ perlはモジュールが素敵なんだよ。たぶん、あなたの隣の席の、白い歯が似合うハンサムボーイより素敵だよ！ NIrvanaのRape Meの歌詞が見たい！とか急に思うよね。　思っちゃうよね。そういうときは、もちろんcpan 検索だね。 モジュール探す http://search.cpan.org/search?query=lyrics 色々みつかったね！そのうちの一つをピックアップしたよ！ モジュールインストール インストール！ sudo cpan install Lyrics::Fetcher::LyricWiki ソース 歌詞をプリントアウトするよ #!/usr/bin/perl use strict; use warnings; use Lyrics::Fetcher::LyricWiki; print Lyrics::Fetcher::LyricWiki-&gt;fetch(&#39;nirvana&#39; , &#39;rape me&#39;); 良い子のみんな、表示できたよね！　結果貼付けると、著作権的に怒られるかもしれないから、 自粛したよ。よくわかってないけどね！ 最後に 普通にgoogleで検索するより何か、ワクワクするでしょ。　こういった面白モジュールがたくさんみつかるのはperlが一番じゃないかな！　 ワクワクモジュールみつけたら、perl-mongers.orgに記事書くと良いと思うよ！ :wq!...]]></summary>
    <author>
        <name>tomyhero [livedoor.com]</name>
        <uri>http://profile.livedoor.com/tomyhero/</uri>
    </author>
    
    <category term="cpan" label="cpan" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="lyricsfetcherlyricwiki" label="Lyrics::Fetcher::LyricWiki" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://perl-mongers.org/">
        <![CDATA[<p>大阪から、こんばんはこんばんは！</p>
<br />
<p>perlはモジュールが素敵なんだよ。たぶん、あなたの隣の席の、白い歯が似合うハンサムボーイより素敵だよ！</p>
<br />
<p>NIrvanaのRape Meの歌詞が見たい！とか急に思うよね。　思っちゃうよね。そういうときは、もちろんcpan 検索だね。</p>

<h4> モジュール探す</h4>

<p><a href="http://search.cpan.org/search?query=lyrics">http://search.cpan.org/search?query=lyrics</a></p>
<br />
<p>色々みつかったね！そのうちの一つをピックアップしたよ！</p>

<h4> モジュールインストール</h4>

<p>インストール！</p>
<pre>
sudo cpan install Lyrics::Fetcher::LyricWiki</pre>

<h4> ソース</h4>

<p>歌詞をプリントアウトするよ</p>

<pre>
#!/usr/bin/perl

use strict;
use warnings;
use Lyrics::Fetcher::LyricWiki;
print Lyrics::Fetcher::LyricWiki-&gt;fetch(&#39;nirvana&#39; , &#39;rape me&#39;);</pre>

<p>良い子のみんな、表示できたよね！　結果貼付けると、著作権的に怒られるかもしれないから、</p>
<p>自粛したよ。よくわかってないけどね！</p>

<h4> 最後に</h4>

<p>普通にgoogleで検索するより何か、ワクワクするでしょ。　こういった面白モジュールがたくさんみつかるのはperlが一番じゃないかな！　</p>
<br />
<p>ワクワクモジュールみつけたら、perl-mongers.orgに記事書くと良いと思うよ！</p>
<br />
<p>:wq!</p>




]]>
        
    </content>
</entry>

<entry>
    <title>Web::ScraperライクなテンプレートエンジンTemplate::Refine</title>
    <link rel="alternate" type="text/html" href="http://perl-mongers.org/2008/09/template-refine.html" />
    <id>tag:perl-mongers.org,2008://1.80</id>

    <published>2008-09-11T13:06:19Z</published>
    <updated>2008-09-11T13:39:28Z</updated>

    <summary><![CDATA[Template::Refineというモジュールを見つけました。リンク先にある通り、ruleを使うことで簡単にテンプレートの値を置き換える事が出来ます。このモジュールの良い所は、テンプレートファイルにテンプレートエンジン専用の識別子を記述しなくて良い所。どうやって指定するかというと、XPathを使います。リンク先から引用すると my $username = &#39;Test User&#39;; my $rule = simple_replace { my $node = shift; return replace_text $node, $username; } &#39;//*[@class=&quot;username&quot;]&#39;; といった感じにルールを決め $frag = $frag-&gt;process($rule); say $frag-&gt;render; と実行する事でテンプレートへの反映が行われます。まるでWeb::Scraperの様ですね。 今日はサンプルとして、美輪明宏のチンコの有無を返すAPIから得た結果をテンプレートに反映してみたいと思います。 まずテンプレート &lt;p&gt;美輪明宏にチンコは...&lt;span class=&quot;miwa&quot;&gt;...&lt;/span&gt;。&lt;/p&gt; 確かにテンプレート専用の識別子は使用していません。そしてperlのコード use strict; use warnings; use Encode; use...]]></summary>
    <author>
        <name>mattn</name>
        <uri>http://mattn.kaoriya.net/</uri>
    </author>
    
    <category term="templaterefine" label="Template::Refine" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://perl-mongers.org/">
        <![CDATA[<p><a href="http://blog.jrock.us/articles/Template%3A%3ARefine.pod">Template::Refine</a>というモジュールを見つけました。リンク先にある通り、ruleを使うことで簡単にテンプレートの値を置き換える事が出来ます。このモジュールの良い所は、テンプレートファイルにテンプレートエンジン専用の識別子を記述しなくて良い所。どうやって指定するかというと、XPathを使います。リンク先から引用すると</p>
<pre class="prettyprint">
my $username = &#39;Test User&#39;;
my $rule = simple_replace {
    my $node = shift;
    return replace_text $node, $username;
} &#39;//*[@class=&quot;username&quot;]&#39;;</pre>
<p>といった感じにルールを決め</p>
<pre class="prettyprint">
$frag = $frag-&gt;process($rule);
say $frag-&gt;render;</pre>
<p>と実行する事でテンプレートへの反映が行われます。まるでWeb::Scraperの様ですね。</p>
<p>今日はサンプルとして、<a href="http://dzfl.jp/blog/2007/07/29/miwa-mojo-api/">美輪明宏のチンコの有無を返すAPI</a>から得た結果をテンプレートに反映してみたいと思います。</p>
<p>まずテンプレート</p>
<pre class="prettyprint">
&lt;p&gt;美輪明宏にチンコは...&lt;span class=&quot;miwa&quot;&gt;...&lt;/span&gt;。&lt;/p&gt;</pre>
<p>確かにテンプレート専用の識別子は使用していません。そしてperlのコード</p>
<pre class="prettyprint">
use strict;
use warnings;
use Encode;
use Perl6::Say;
use LWP::Simple;
use JSON;
use Template::Refine::Fragment;
use Template::Refine::Utils qw(replace_text simple_replace);

my $miwa = from_json(get &quot;http://dzfl.jp/mojo/&quot;);
my $rule = simple_replace {
    my $node = shift;
	return replace_text $node, encode_utf8($miwa-&gt;{miwa} ? &#39;ある&#39; : &#39;ない&#39;);
} &#39;//*[@class=&quot;miwa&quot;]&#39;;

my $frag = Template::Refine::Fragment-&gt;new_from_file(&#39;template.html&#39;);
print $frag-&gt;process($rule)-&gt;render;</pre>
<p>HTMLのmiwaというクラス属性を持ったノードに対して&quot;ある&quot;/&quot;ない&quot;というテキストで置換しています。</p>
<p>簡単ですね。テンプレートエンジン専用の識別子を使用しないので、HTMLの属性値さえ決めておけば、テンプレートの殆どをデザイナさんに任せてしまう事も出来る様になります。</p>
<p>すばらしいですね。</p>

]]>
        
    </content>
</entry>

<entry>
    <title>Getopt::Chainでgitライクなsubcommandを処理する</title>
    <link rel="alternate" type="text/html" href="http://perl-mongers.org/2008/08/getoptchaingitsubcommand.html" />
    <id>tag:perl-mongers.org,2008://1.79</id>

    <published>2008-08-24T02:49:56Z</published>
    <updated>2008-08-24T13:04:15Z</updated>

    <summary><![CDATA[Yokohama.pmでxcezxさんがMonday Moduleのtech talkをされていたので、早速書いてみました。 http://d.hatena.ne.jp/xcezx/ 今回紹介するのは、gitのようなsubcommandのoptionを処理してくれるモジュールです。 gitだと、例えば以下のようにcommitサブコマンドにオプションを渡します。このオプションなどをパースしてくれて、簡単に取得できるようにしてくれます。 git.pl init --quiete git.pl commit -a -m &#39;Hello&#39; commands以下にsubcommandの記述を書くと、そのsubcommandのcontextで引数の値などを取得する事ができます。例えば、commitサブコマンドのmオプションの値とかが簡単にとれるようになります。 #!/usr/bin/env perl use strict; use warnings; use Getopt::Chain; use Perl6::Say; main(); sub main { setup_commands(); } sub setup_commands { Getopt::Chain-&gt;process( options =&gt; [qw/ version /],...]]></summary>
    <author>
        <name>http://www.hatena.ne.jp/dann/</name>
        <uri>http://www.hatena.ne.jp/dann/</uri>
    </author>
    
    <category term="commandline" label="commandline" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="getoptchain" label="Getopt::Chain" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="mondaymodule" label="monday-module" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://perl-mongers.org/">
        <![CDATA[<p>Yokohama.pmでxcezxさんがMonday Moduleのtech talkをされていたので、早速書いてみました。</p>
<p><a href="http://d.hatena.ne.jp/xcezx/">http://d.hatena.ne.jp/xcezx/</a></p>
<br />
<p>今回紹介するのは、gitのようなsubcommandのoptionを処理してくれるモジュールです。</p>
<p>gitだと、例えば以下のようにcommitサブコマンドにオプションを渡します。このオプションなどをパースしてくれて、簡単に取得できるようにしてくれます。</p>

<blockquote>
<p>  git.pl init --quiete</p>
<p>  git.pl commit -a -m &#39;Hello&#39;</p>
</blockquote>

<p>commands以下にsubcommandの記述を書くと、そのsubcommandのcontextで引数の値などを取得する事ができます。例えば、commitサブコマンドのmオプションの値とかが簡単にとれるようになります。</p>

<pre class="prettyprint">
#!/usr/bin/env perl
use strict;
use warnings;
use Getopt::Chain;
use Perl6::Say;

main();

sub main {
    setup_commands();
}

sub setup_commands {
    Getopt::Chain-&gt;process(
        options =&gt; [qw/ version /],
        run =&gt; sub {
            my $context   = shift;
            my @arguments = @_;
            say $context-&gt;local_option(&#39;version&#39;);
        },

        commands =&gt; {
            init =&gt; {
                options =&gt; [qw/ quiet|q template=s shared=s/],
                run     =&gt; ¥&amp;init,
            },
            commit =&gt; {
                options =&gt; [qw/ auto|a message|m=s /],
                run     =&gt; ¥&amp;commit,
            },
        }
    );
}

# sub commands
sub init {
    my $context   = shift;
    my @arguments = @_;

    if($context-&gt;local_option(&#39;quiet&#39;)) {
        say &#39;Only print error and warning messages.&#39;;
    }
    say $context-&gt;local_option(&#39;template&#39;);
}

sub commit {
    my $context   = shift;
    my @arguments = @_;
    say $context-&gt;local_option(&#39;message&#39;);
}

__END__</pre>

]]>
        
    </content>
</entry>

<entry>
    <title>CatalystとConfig</title>
    <link rel="alternate" type="text/html" href="http://perl-mongers.org/2008/08/catalystconfig.html" />
    <id>tag:perl-mongers.org,2008://1.78</id>

    <published>2008-08-14T14:11:00Z</published>
    <updated>2008-08-14T14:29:47Z</updated>

    <summary><![CDATA[こんにちはこんにちは！ tomyheroです！　トミヘロじゃなくて、とぅーまいひーろ　って読むんだよ！ 今自分の中で流行ってる、CatalystとConfig周りの実装をこっそり晒そうと思うよ。　 aim catalystアプリだけじゃなくて、外からでも使えるように実装したほうがいいとおもうんだよ！ MyApp::Config Config::Multiをシングルトンで、どこでもつかえるようにするよ。　 MyApp::Utils　というので、設定ファイルのパスをとってますね！これについては、後で書くよ！ package MyApp::Config; use strict; use warnings; use Config::Multi; use MyApp::Utils; use base &#39;Class::Singleton&#39;; our $FILES ; sub _new_instance { my $cm = Config::Multi-&gt;new( { dir =&gt; MyApp::Utils::path_to(&#39;conf&#39;)-&gt;stringify , app_name =&gt; &#39;myapp&#39; ,...]]></summary>
    <author>
        <name>tomyhero [livedoor.com]</name>
        <uri>http://profile.livedoor.com/tomyhero/</uri>
    </author>
    
    <category term="catalyst" label="Catalyst" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="configmulti" label="Config::Multi" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://perl-mongers.org/">
        <![CDATA[<p>こんにちはこんにちは！ tomyheroです！　トミヘロじゃなくて、とぅーまいひーろ　って読むんだよ！</p>
<br />
<p>今自分の中で流行ってる、CatalystとConfig周りの実装をこっそり晒そうと思うよ。　</p>

<h4> aim</h4>

<p>catalystアプリだけじゃなくて、外からでも使えるように実装したほうがいいとおもうんだよ！</p>

<h4> MyApp::Config</h4>

<p><a href="http://search.cpan.org/dist/Config-Multi/">Config::Multi</a>をシングルトンで、どこでもつかえるようにするよ。　 MyApp::Utils　というので、設定ファイルのパスをとってますね！これについては、後で書くよ！</p>

<pre class="prettyprint">
package MyApp::Config;

use strict;
use warnings;
use Config::Multi;
use MyApp::Utils;
use base &#39;Class::Singleton&#39;;

our $FILES ;
sub _new_instance {
    my $cm = Config::Multi-&gt;new(
        {
        dir =&gt; MyApp::Utils::path_to(&#39;conf&#39;)-&gt;stringify ,
        app_name    =&gt; &#39;myapp&#39; ,
        extension   =&gt; &#39;yml&#39;
    });
    my $config = $cm-&gt;load();
    $FILES = $cm-&gt;files;
    return $config;
}
sub files {
    return $FILES;
}

1;</pre>

<h4> MyApp::Utils</h4>

<p>アプリケーションのUtilsモジュールだよ。Catalyst::Utilsだと、カタリスト依存しちゃうから、自分で作っちゃった方が良いと思うよ。 path_toとかのコードは、Catalystを参考にパクると良いと思うよ。</p>

<pre class="prettyprint">
package MyApp::Utils;

use warnings;
use strict;
use Path::Class::Dir;
use Path::Class::File;
use FindBin;

sub home {
    return $ENV{MYAPP_HOME} ||  Path::Class::Dir-&gt;new(  $FindBin::Bin, &#39;./../&#39; );
}

sub path_to {
    my ( @path ) = @_;
    my $path = Path::Class::Dir-&gt;new( &amp;home , @path );
    warn $path;
    if ( -d $path ) { return $path }
    else { return Path::Class::File-&gt;new( &amp;home, @path ) }
}

1;</pre>

<h4> MyApp::Plugin::Config</h4>

<p>オレオレコンフィグプラグインを作るよ！</p>
<p>ぶっちゃけ、MyApp::Config　を $c-&gt;config にぶっ込んでるだけだよ。</p>
<pre class="prettyprint">
package MyApp::Plugin::Config;

use strict;
use warnings;
use MyApp::Config;
use NEXT;

our $VERSION =&#39;0.02&#39;;

sub setup {
    my $c = shift;
    my $config = MyApp::Config-&gt;instance();

    if( $c-&gt;debug ) {
        my $files = MyApp::Config-&gt;files();
        for my $file ( @{$files} ) {
            $c-&gt;log-&gt;debug( &#39;Load Config &#39; . $file );
        }
    }

    $c-&gt;config( $config ) ;
    $c-&gt;NEXT::setup( @_ );
}

1;</pre>

<h4>  MyApp::Web</h4>

<p>カタリストアプリだよ。プラグイン読み込むよ。</p>

<pre class="prettyprint">
package MyApp::Web;

use strict;
use warnings;
use Catalyst::Runtime &#39;5.70&#39;;
use Catalyst qw/+MyApp::Plugin::Config/;
our $VERSION = &#39;0.01&#39;;
__PACKAGE__-&gt;setup;

1;</pre>

<h4>  conf/myapp_web.yml</h4>

<p>設定ファイルだよ。</p>

<pre class="prettyprint">
---
name: Config Sample</pre>

<h4> MyApp::Web::Controller::Root</h4>

<p>コンフィグデータが、ちゃんととれてるか表示するよ！</p>

<pre class="prettyprint">
package MyApp::Web::Controller::Root;

use strict;
use warnings;
use base &#39;Catalyst::Controller&#39;;

__PACKAGE__-&gt;config-&gt;{namespace} = &#39;&#39;;

sub default : Private {
    my ( $self, $c ) = @_;
    $c-&gt;response-&gt;body(  $c-&gt;config-&gt;{name} );
}

sub end : ActionClass(&#39;RenderView&#39;) {}

1;</pre>

<p>たぶんみえてるんじゃないかな！</p>

<h4> おわり</h4>

<p>以上だよ。　</p>
<p>ちなみに、 MyApp::Config はどこからでも呼べるから、ガンガン呼ぶと良いと思うよ。多い日も安心だね！</p>
<br />
<p>:wq!</p>

]]>
        
    </content>
</entry>

<entry>
    <title>HTTP::Asyncで速度アップ</title>
    <link rel="alternate" type="text/html" href="http://perl-mongers.org/2008/08/speed-up-with-http-async.html" />
    <id>tag:perl-mongers.org,2008://1.77</id>

    <published>2008-08-12T12:35:05Z</published>
    <updated>2008-08-12T12:53:17Z</updated>

    <summary><![CDATA[こんにちは！ tomyhero です！ 一つのリクエスト内で、複数のAPIを叩いたり、フィードを読み込んだりすると重くなって行きますよね！　たとえば、複数のアフィリエイト広告APIを叩くときとか！ そういうときは、HTTP::Async を使うと良いと思います！ リクエストの結果を待たないで、次のリクエストを投げてくれます！で、後で回収をおこなうことができます。 サンプルコード #!/usr/bin/perl use HTTP::Async; use HTTP::Request; use LWP::UserAgent; use Data::Dumper; use Perl6::Say; use Time::HiRes qw/gettimeofday tv_interval/ ; # 適当なurl.本来なら別ドメインのサイトが良いと思う。攻撃ぽくなるので。 our @urls = ( &#39;http://clip.livedoor.com/rss/recent&#39;, &#39;http://clip.livedoor.com/rss/hot&#39;, &#39;http://clip.livedoor.com/rss/popular&#39;, ); &amp;normal(); &amp;async(); sub async { my...]]></summary>
    <author>
        <name>tomyhero [livedoor.com]</name>
        <uri>http://profile.livedoor.com/tomyhero/</uri>
    </author>
    
    <category term="cpan" label="cpan" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="httpasync" label="HTTP::Async" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="httprequest" label="HTTP::Request" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="lwpuseragent" label="LWP::UserAgent" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="timehires" label="Time::HiRes" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://perl-mongers.org/">
        <![CDATA[<p>こんにちは！ tomyhero です！</p>
<br />
<p>一つのリクエスト内で、複数のAPIを叩いたり、フィードを読み込んだりすると重くなって行きますよね！　たとえば、複数のアフィリエイト広告APIを叩くときとか！</p>
<br />
<p>そういうときは、<a href="http://search.cpan.org/dist/HTTP-Async/">HTTP::Async</a> を使うと良いと思います！ </p>
<p>リクエストの結果を待たないで、次のリクエストを投げてくれます！で、後で回収をおこなうことができます。</p>

<h4> サンプルコード</h4>

<pre class="prettyprint">
#!/usr/bin/perl 

use HTTP::Async;
use HTTP::Request;
use LWP::UserAgent;
use Data::Dumper;
use Perl6::Say;
use Time::HiRes qw/gettimeofday tv_interval/ ;

# 適当なurl.本来なら別ドメインのサイトが良いと思う。攻撃ぽくなるので。
our @urls = (
    &#39;http://clip.livedoor.com/rss/recent&#39;,
    &#39;http://clip.livedoor.com/rss/hot&#39;,
    &#39;http://clip.livedoor.com/rss/popular&#39;,
);


&amp;normal();
&amp;async();

sub async {
     my $t0 = [gettimeofday];
    my $async = HTTP::Async-&gt;new;

    for my $url (@urls) {
        $async-&gt;add( HTTP::Request-&gt;new( GET =&gt; $url ) );
    }

    my @results = ();
    while ( my ( $response, $id ) = $async-&gt;wait_for_next_response ) {
        push @results, +{ id =&gt; $id, content =&gt; $response-&gt;content };
    }

    @results = sort { $a-&gt;{&quot;id&quot;} cmp $b-&gt;{&quot;id&quot;} } @results;

    my $elapsed = tv_interval ( $t0, [gettimeofday]);
    say &#39;async :&#39;  . $elapsed;
    #warn Dumper \@results;
}

sub normal {
     my $t0 = [gettimeofday];
    my @results = ();
    for my $url (@urls) {
        my $ua = LWP::UserAgent-&gt;new;
        my $response = $ua-&gt;get(&#39;http://search.cpan.org/&#39;);
        push @results , $response-&gt;content;
    }

    my $elapsed = tv_interval ( $t0, [gettimeofday]);
    say &#39;normal:&#39; . $elapsed;
#    warn Dumper \@results;
}</pre>


<h4> 結果</h4>
<p>ネットワークをかいしてるので、正確ではないですが、目安にはなります。</p>

<pre>
normal:1.315056
async :0.368374</pre>

<p>add_with_opts()　モジュールを使うと、proxyや、timeoutの設定ができたりしますよ。</p>

<h4> 最後に</h4>

<p>早いサイトって良いですよね！　</p>
<br />
<p>試してませんが、<a href="http://search.cpan.org/dist/ParallelUserAgent/">ParallelUserAgent</a>もいいのかも！　場合によってはforkでもいいのかも！</p>
<br />
<p>:wq!</p>



]]>
        
    </content>
</entry>

<entry>
    <title>PHP使いによるCatalyst初心者記事</title>
    <link rel="alternate" type="text/html" href="http://perl-mongers.org/2008/08/catalystcontrolleratompub.html" />
    <id>tag:perl-mongers.org,2008://1.75</id>

    <published>2008-08-08T19:49:12Z</published>
    <updated>2008-08-11T12:59:18Z</updated>

    <summary>mumumu です。普段 PHPを使ってWebアプリケーションを書いたり、C, C++ を書いたりしています。 今回 Atompub サーバを書くことになり、一番まともな実装(Catalyst::Controller::Atompub) がある Perl を使うことにしました。 Catalyst::Controller::Atompub を使うからには当然 Catalyst を使うことになるわけですが、2年振りにPerlを書いたことと、フレームワークの流儀も全く解っていなかったことから結構ハマりました。以下では、それを脈絡なく書いていこうと思います。普段PHP使いだからって石を投げないでくだしあ( ;´Д⊂ヽ Catalystを学ぶにあたって 「perl Catalyst」でぐぐったところ、まとまった記事がすぐに出てこなかったことから、私は Catalyst::Manual::Tutorial を順に読んでいろいろ試していきましたが、後で調べたら はじめてのCatalyst というマニュアルの翻訳を見つけました。MVCフレームワークに触れたことがある人には、凄くいい資料ではないでしょうか。Catalystクックブック も素晴らしいです。 以下では、こうして学びながら特に引っ掛かった点をピックアップして書いていきます。 Catalystのインストール 環境は Debian GNU/Linux etch を使いました。これには、既にパッケージとして libcatalyst-perl (5.7.006)等が用意されていますが、lazy-people.org の tomyheroさん から (tomyhero) install Task::Catalyst (tomyhero)...</summary>
    <author>
        <name>mumumu.myopenid.com</name>
        <uri>http://mumumu.myopenid.com/</uri>
    </author>
    
    <category term="catalyst" label="Catalyst" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://perl-mongers.org/">
        <![CDATA[<p><a href="http://mumumuorg.blogspot.com">mumumu</a> です。普段 PHPを使ってWebアプリケーションを書いたり、C, C++ を書いたりしています。</p>
<p>今回 <a href="http://tools.ietf.org/rfc/rfc5023.txt">Atompub</a> サーバを書くことになり、一番まともな実装(<a href="http://search.cpan.org/~takeru/Catalyst-Controller-Atompub-v0.5.1/lib/Catalyst/Controller/Atompub.pm">Catalyst::Controller::Atompub</a>) がある Perl を使うことにしました。</p>
<br />
<p>Catalyst::Controller::Atompub を使うからには当然 Catalyst を使うことになるわけですが、2年振りにPerlを書いたことと、フレームワークの流儀も全く解っていなかったことから結構ハマりました。以下では、それを脈絡なく書いていこうと思います。普段PHP使いだからって石を投げないでくだしあ( ;´Д⊂ヽ</p>

<h3>Catalystを学ぶにあたって</h3>

<p>「perl Catalyst」でぐぐったところ、まとまった記事がすぐに出てこなかったことから、私は <a href="http://search.cpan.org/~zarquon/Catalyst-Manual-5.7013/lib/Catalyst/Manual/Tutorial.pod">Catalyst::Manual::Tutorial</a> を順に読んでいろいろ試していきましたが、後で調べたら <a href="http://www.tcool.org/catalyst/Intro.html">はじめてのCatalyst</a> というマニュアルの翻訳を見つけました。MVCフレームワークに触れたことがある人には、凄くいい資料ではないでしょうか。<a href="http://www.tcool.org/catalyst/Cookbook.html">Catalystクックブック</a> も素晴らしいです。</p>
<br />
<p>以下では、こうして学びながら特に引っ掛かった点をピックアップして書いていきます。</p>

<h3>Catalystのインストール</h3>

<p>環境は Debian GNU/Linux etch を使いました。これには、既にパッケージとして libcatalyst-perl (5.7.006)等が用意されていますが、<a href="http://lazy-people.org/">lazy-people.org</a> の <a href="http://d.hatena.ne.jp/tomyhero">tomyheroさん</a> から</p>

<pre>
(tomyhero) install Task::Catalyst
(tomyhero) install HTML::Parser
(tomyhero) install Template
(tomyhero) install Encode
(tomyhero) この辺ふるいのはいってると、文字コード周りでgdgdになる。
(tomyhero) FYI</pre>

<p>という有難い情報があったので、CPAN から直接インストール(執筆時点での最新版は 5.7014) することにしました。256MBしか割り当てていないバーチャルマシン上での作業なので予想はしてたんですが、上の Task::Catalyst, HTML::Parser, Template, Encode を最新にするのに1時間掛かりました。依存関係でいろいろ聞かれたりしますが、「y」で通して（たぶん）大丈夫です。個人的には XML::LibXML が XML::LibXML::Common を先にインストールしてくれなくてエラーになったりしましたが、もう一度 XML::LibXML::Common -&gt; XML::LibXML の順でインストールし直すと大丈夫でした。</p>
<br />
<p>最後に、肝心の Catalyst::Controller::Atompub のインストールです。これに30分。</p>
<p>これは滞りなくいきました。CPANから多数のモジュールをインストールするとなると、非常に時間が掛かるものですが、「y」を押しながら気長に他のことをしましょう。</p>

<pre>
# perl -MCPAN -e shell
cpan&gt; install Catalyst::Runtime Catalyst::Plugin::ConfigLoader Catalyst::Plugin::Static::Simple Catalyst::Model::DBIC::Schema DBIx::Class::Schema::Loader DBD::SQLite Catalyst::View::TT Catalyst::Controller::Atompub Catalyst::Action::RenderView</pre>

<p>インストールが終わったら、プロジェクトを作りましょう。今回は説明のため、Sample というプロジェクトにします。</p>

<pre>
$ catalyst.pl Sample
(....ディレクトリ構造とか最低限の雛形とかいろんなものが生成される)
$ cd Sample/</pre>

<p>プロジェクトを作ったあとは、一応動作確認しておきます。Catalyst には、開発用のWebサーバが用意されています。以下のようにして起動します。</p>
<pre>
$ script/sample_server.pl
.....  Sampleプロジェクトの情報がずらずらと表示
[info] sample1 powered by Catalyst 5.7014
You can connect to your server at http://example.com:3000</pre>

<p>無事起動したら、<a href="http://example.com:3000">http://example.com:3000</a> にブラウザからアクセスしてみましょう。</p>
<p>以下のような画面にアクセスできるはずです。この開発用サーバ起動の操作は何度も使うことになります。</p>
<br />
<p><a href="http://perl-mongers.org/sample_hello.png"><img alt="http://perl-mongers.org/sample_hello.png" src="http://perl-mongers.org/sample_hello.png" /></a></p>

<h3>URLルーティング</h3>

<p>Webアプリケーションフレームワークを実際に使うにあたって、私がまず関心を持つのはURLルーティング、すなわち「特定のURLに対応した処理をどこに書くか」ということです。Catalystにはこの点で多彩なやり方が用意されており、多少混乱しました。</p>
<br />
<p>Catalyst では コントローラー にURLに対応した処理をサブルーチン(関数)として記述します。まずは適当にコントローラーを生成します。script/sample_create.pl が様々な雛形を自動で生成してくれるようになっていますので、それを利用します。</p>

<pre>
$ script/sample_create.pl controller hello
 exists &quot;/home/mumumu/Sample/script/../lib/Sample/Controller&quot;
 exists &quot;/home/mumumu/Sample/script/../t&quot;
 created &quot;/home/mumumu/Sample/script/../lib/Sample/Controller/hello.pm&quot;
 created &quot;/home/mumumu/Sample/script/../t/controller_hello.t&quot;</pre>

<p>hello コントローラーが追加されました。lib/Sample/Controller/hello.pm を開き、podの部分を除いた(間違っても use strict, use warnings は除かないように！)部分は以下のようになっています。ここでは、sub index ... の部分に注目します。</p>
<br />
<p>(lib/Sample/Controller/hello.pm)</p>
<pre class="prettyprint">
package Sample::Controller::hello;

use strict;
use warnings;
use parent &#39;Catalyst::Controller&#39;;

sub index :Path :Args(0) {
    my ( $self, $c ) = @_;

    #
    #    http://example.com/hello/ や http://example.com/hello へのリクエスト
    #    に対して、「Matched Sample::Controller::hello in hello.」を表示する。
    #
    $c-&gt;response-&gt;body(&#39;Matched Sample::Controller::hello in hello.&#39;);
}

1;</pre>

<p>indexって何か意味あるの？ それ以前に :Path とか :Args とか Perlの文法的にアリなの？ と調べること2時間。:Path や :Args は <a href="http://search.cpan.org/~nwclark/perl-5.8.7/lib/attributes.pm">アトリビュート</a> と呼ばれる、属性を変更するハンドラを呼び出すためのおまじないみたいですが、ここは黒魔術だと思ってあまりキニシナイことにしました。とりあえず、「:ほげほげ」をサブルーチン名の後に書くことで、ルーティングのやり方を指定できるようです。このほげほげを Catalyst の世界ではアクションと呼ぶようです。</p>
<br />
<p>上の 「index :Path :Args(0)」のアクション指定は、 Catalyst にビルトインされた特別なアクションで、<a href="http://example.com/hello/">http://example.com/hello/</a> や、<a href="http://example.com/hello">http://example.com/hello</a> のように、パッケージ名から、Controllerまでの部分を除いたもの(ここではhello) のあとに引数を何も与えなかった場合に呼び出されるアクションらしいです。</p>
<br />
<p>また、サブルーチンの引数について説明をしておくと、第1引数 $self は、Sample::Controller::hello オブジェクト(オブジェクト指向でいうところの this) です。 第2引数に $c が指定されていますが、これは「コンテキストオブジェクト」というもので、ここからリクエストやレスポンスのオブジェクトはもちろん、データベース操作に使えるModelなど、Webアプリケーションにおける処理に必要な様々なオブジェクトを取り出すことができます。アクション指定をしたサブルーチンの引数には必ずこの $c がついている（はず）ですので、様々な操作が行えるはずです。</p>
<br />
<p>私が主に使ったアクションを「ちょっとだけ」以下に並べておきます。正直たくさんあって参りました。</p>
<br />
<p>ここでアクション指定をすべて説明はできないので、詳細は<a href="http://cpansearch.perl.org/~zarquon/Catalyst-Manual-5.7013/lib/Catalyst/Manual/Intro.pod#Action_types">マニュアルにあるアクションの一覧</a> を見るとよいと思います。私自身も未だによくわかってないアクションがかなりありますネ(´ー｀; )</p>

<pre class="prettyprint">
package Sample::Controller::hello;
#
#  Path アクション
#  
#  Path の引数の先頭にスラッシュを入れないと、パッケージ名から Controller まで
#  を除いた部分(ここではhello) からの相対URLにマッチする。
#  以下の場合は http://example.com/hello/foo/bar や、
#  http://example.com/hello/foo/bar/baz などのリクエストに対して hoge が呼ば
#  れる。
#  
#  これに対して:Path(&#39;/foo/bar&#39;) として先頭にスラッシュを入れると、絶対指定となり、
#  http://example.com/foo/bar や、http://example.com/foo/bar/baz などが呼ばれたと
# きに hoge が呼ばれる
#
sub hoge :Path(&#39;foo/bar&#39;) {
    # ....
}</pre>

<pre class="prettyprint">
#
#  Regex アクション
#  
#  パッケージ名に関係なく、マッチするURLを正規表現で指定する
#  以下の場合は、http://example.com/foo/hoge としたときは サブルーチンhoge
#  が呼ばれるが、http://example.com/hoge では呼ばれない
#
sub hoge :Regex(&#39;^(\w+?)/hoge&#39;) {
    # ....
}</pre>

<pre class="prettyprint">
package Sample::Controller::hello;
#
#  Local アクション
#  
#  URLが、必ずパッケージ名から、Controllerまでの部分を除いたもの
#  (ここではhello) で始まり、あとにサブルーチン名が続いたものにマッチすること
#  を指定する。
#
#  以下の場合は、http://example.com/hello/hoge/foo や 
#  http://example.com/hello/hoge としたときに、サブルーチンhoge
#  が呼ばれるが、http://example.com/hoge では呼ばれない
#
sub hoge :Local {
    # ....
}</pre>

<pre class="prettyprint">
#
#  default アクション
#
#  どのアクションにもURLがマッチしない場合に呼ばれる。404ページやエラーページ
#  の作成に便利
#
sub default :Private {
    # ....
}</pre>

<h3> データベース操作</h3>

<p>さて、アクション指定をしたサブルーチン内では、マッチしたURLに対して様々な操作ができることがわかりました。URLルーティングに続いて、私が次に関心を持つのは、Webアプリケーションに欠かせないデータベースの操作です。Catalyst ではどうしたらいいのでしょうか？</p>
<br />
<p>以下、順を追って説明したいと思います。なお、私は今回 sqlite3 を使いました。</p>
<p>まずはデータベースの構造（スキーマ）です。本当は Atompub 用のスキーマを書きたいのですが、そこは割愛して、説明のための簡単なスキーマを作ります。</p>

<pre>
$ cd Sample
$ sqlite3 sample.db
SQLite version 3.5.9
Enter &quot;.help&quot; for instructions
sqlite&gt; CREATE TABLE sample (
     ...&gt;   id            INTEGER PRIMARY KEY,
     ...&gt;   sample_text        TEXT
     ...&gt;);
sqlite&gt;</pre>

<p>次にデータベースにアクセスするための Model クラスを作ります。Perl では、ORM(Object Relational Mapping) という、DBアクセスを楽にプログラムから行うためのモジュールとして、DBICというものがあります。ここではそれを利用するように指定してクラスを生成します。コントローラーを作ったときと同じく、script/sample_create.pl を使います。</p>
<p>  </p>
<p>script/sample_create.pl への引数として、いろいろごちゃごちゃと指定していますが、順番に以下の表の通りです。</p>
<p>  </p>
<table>
<tr>


</tr>
<tr>
<td>model</td>
<td>作成対象（model or  view or controller)</td>
</tr>
<tr>
<td>DB</td>
<td>作成するクラス名（ちゃんと書くとSample::Model::DB）</td>
</tr>
<tr>
<td>DBIC::Schema</td>
<td>スーパークラス名（Catalyst::Model::DBIC::Schema）</td>
</tr>
<tr>
<td>Sample::Schema</td>
<td>スキーマ情報のクラス名</td>
</tr>
<tr>
<td>dbi:SQLite:dbname=sample.db</td>
<td>接続情報</td>
</tr>
</table>
<p>  </p>
<pre>
 $ script/sample_create.pl model DB DBIC::Schema Sample::Schema create=static dbi:SQLite:sample.db 
 exists &quot;/home/mumumu/Sample/script/../lib/Sample/Model&quot;
 exists &quot;/home/mumumu/Sample/script/../t&quot;
Dumping manual schema for Sample::Schema to directory /home/mumumu/Sample/script/../lib ...
Schema dump completed.
created &quot;/home/mumumu/Sample/script/../lib/Sample/Model/DB.pm&quot;
created &quot;/home/mumumu/Sample/script/../t/model_DB.t&quot;</pre>
<p>    </p>
<p>いろいろと生成されたようです。具体的には、lib/Sample/Schema/Sample.pm に、テーブルの定義がdumpされてクラスが自動生成されているのがわかると思います。また、lib/Sample/Schema.pm には、スキーマをロードするクラス、そしてlib/Sample/Model/DB.pm には、DBの接続設定が書かれているようです。皆さんの目で確認してみて下さい。</p>
<br />
<p>これらを使って、Perlプログラムからレコードを挿入してみます。URLルーティングのところで説明した、hello コントローラーを以下のように書き換えてみます。</p>
<br />
<p>(lib/Sample/Controller/hello.pm)</p>
<pre class="prettyprint">
package Sample::Controller::hello;

use strict;
use warnings;
use parent &#39;Catalyst::Controller&#39;;

sub index :Path :Args(0) {
    my ( $self, $c ) = @_;

    #    自動生成した sample スキーマクラスを使って sample_text カラムに
    #    挿入する 
    $c-&gt;model(&#39;DB::sample&#39;)-&gt;update_or_create({
        sample_text =&gt; &#39;im catalyst newbie. testing hello!&#39;,
    });

    #
    #    http://example.com/hello/ や http://example.com/hello へのリクエスト
    #    に対して、「Matched Sample::Controller::hello in hello.」を表示する。
    #
    $c-&gt;response-&gt;body(&#39;Matched Sample::Controller::hello in hello.&#39;);
}

1;</pre>

<p>自動生成したクラスは、「$c-&gt;model(&#39;スキーマ名&#39;)-&gt;DBアクセスのメソッド」 のようにして使います。上記の例では DB::sample がスキーマ名で、 DBアクセスのメソッドとして update_or_create を使っています。とりあえずこの使い方は「おまじない」のようなもの、としておきましょう。</p>
<br />
<p>しかし、「DBアクセスのメソッド」は他にもたくさんあるはずです。SELECT や DELETE, UPDATE とか、、それらの詳細については、<a href="http://search.cpan.org/~ash/DBIx-Class-0.08010/lib/DBIx/Class/Manual.pod">DBIX::Class::Manual</a> 等を参考にしてみてください。</p>
<br />
<p>書き換えたあと、プロジェクトを作り、動作確認したときの要領で開発用サーバを起動し、<a href="http://example.com:3000/hello">http://example.com:3000/hello</a> にアクセスしてみましょう。相も変わらず「Matched Sample::Controller::hello in hello.」と表示されるだけですが、データベースの中身は変わっています。ちょっと確かめてみましょう。</p>

<pre>
$ sqlite3 sample.db
SQLite version 3.5.9
Enter &quot;.help&quot; for instructions
sqlite&gt; select * from sample;
1|im catalyst newbie. testing hello!  &lt;- 挿入されたレコード！
sqlite&gt;</pre>

<p>1番のidで、im catalyst newbie. testing hello!　と挿入されているのがわかると思います。これは lib/Sample/Controller/hello.pm の indexアクションに書いたものです。</p>

<h4> sqliteに関する注意点</h4>

<p>sqlite は単一ファイルにデータベースの情報を格納します。よって、Webサーバ経由でPerlからアクセスする場合は、sqliteコマンドで作ったファイル(ここではsample.db) がWebサーバの権限で読み書きできなければいけません。「Unable to Open Database!」のようなエラーが出る場合は、この点を真っ先に疑うようにしましょう。</p>
<br />
<p>また、こうした問題は往々にして sample_server.pl を使った開発サーバにおいてよりも、Apache + mod_perl のような、デプロイ後の環境で往々にして起こりがちです。パーミッションとdbファイルのパスはきちんと確認しておくようにしましょう。</p>
<br />
<p>Catalyst と sqlite は面倒な関係にあるようです。lazy-people.org の tomyhero氏は以下のようにIRCで叫んでいました。</p>

<pre>
 (tomyhero) sqliteで十分ではなくて、sqliteのほうが
 (tomyhero) めんどうなんだお！
 (tomyhero) myssqlとかつかったほうがいいお</pre>

<h3> その他びっくりしたこと、小さな疑問等（ひとりごと的に）</h3>

<ul>
<li> DBIC と DBIx::Class って同じものかどうか未だに区別がつかない</li>
<li> 入力の validate はどこに書けばいいの？と思ったら、validateのフローはばっさりカットされているようだ。型にハマったLazyな方法ないかしら</li>
<li> 設定ファイルは 2方式あるらしく、Catalyst::Manual::Tutorial では、Apacheの設定ファイルライクな方式が使われていた。どっちがいいんだろうねーと思いつつ、結局慣れ親しんだyamlに走った</li>
<li> デプロイしてみて、動かすのにこれだけ苦労したのは久しぶりかも。SSLを絡めたらとたんにfastCGIで動かなくなったりとかあったけど、最終的には Apache + mod_perl2 に落ち着いた</li>
</ul>

<h3> とりあえずのおわり</h3>

<p>あれ、View はどうしたの？ とか、Atompubの記述が全く出てこないぢゃないかとか、いろいろツッコミどころはあるとは思いますが、長くなってきたので今回はこの辺で。。ということで(´ー｀; )  View 以外にも Basic 認証についても結構ひっかかったりしたので、それについても機会があったら書きたいと思います。</p>
<br />
<p>最後に、<a href="http://lazy-people.org">lazy-people.org</a> の皆さんには多くの助言を頂きました。この場を借りて御礼申し上げます。</p>

]]>
        
    </content>
</entry>

<entry>
    <title>WWW::Mechanize::Plugin::Web::Scraperでスクレイピングをもっと簡単に</title>
    <link rel="alternate" type="text/html" href="http://perl-mongers.org/2008/07/mechanize-scraper.html" />
    <id>tag:perl-mongers.org,2008://1.72</id>

    <published>2008-07-30T13:19:30Z</published>
    <updated>2008-07-31T06:13:01Z</updated>

    <summary><![CDATA[スクレイピングして何すんだと言われましても、スクレイピングがしたくてしょうがないmattnです。 今日、WWW::Mechanize::Plugin::Web::Scraperというcpanモジュールを(otsuneさんのブクマ経由で)見つけました。モジュール名の通り、WWW::MechanizeからWeb::Scraperするプラグインです。 先日書いた「何時でも何処でも携帯で「はてなスター」チェック」では、両方使ってagentを切り替えたりしてましたが、これを使うともっとスマートに書けるようになります。今日は小ネタでソースだけ。 use strict; use warnings; use WWW::Mechanize::Pluggable; use YAML::Syck; my $username = &#39;xxxxx&#39;; my $password = &#39;xxxxx&#39;; my $mech = WWW::Mechanize::Pluggable-&gt;new(); $mech-&gt;get(&#39;http://www.hatena.ne.jp/login?location=http://s.hatena.ne.jp/&#39;); $mech-&gt;submit_form( form_number =&gt; 1, fields =&gt; { name =&gt; $username, password =&gt; $password, } ); $mech-&gt;get(&quot;http://s.hatena.ne.jp/$username/report&quot;);...]]></summary>
    <author>
        <name>mattn</name>
        <uri>http://mattn.kaoriya.net/</uri>
    </author>
    
    
    <content type="html" xml:lang="en" xml:base="http://perl-mongers.org/">
        <![CDATA[<p>スクレイピングして何すんだと言われましても、スクレイピングがしたくてしょうがないmattnです。</p>
<br />
<p>今日、<a href="http://search.cpan.org/~blom/WWW-Mechanize-Plugin-Web-Scraper-0.01/">WWW::Mechanize::Plugin::Web::Scraper</a>というcpanモジュールを(otsuneさんのブクマ経由で)見つけました。モジュール名の通り、WWW::MechanizeからWeb::Scraperするプラグインです。</p>
<p>先日書いた「<a href="http://perl-mongers.org/2008/07/post_4.html">何時でも何処でも携帯で「はてなスター」チェック</a>」では、両方使ってagentを切り替えたりしてましたが、これを使うともっとスマートに書けるようになります。今日は小ネタでソースだけ。</p>

<pre class="prettyprint">
use strict;
use warnings;
use WWW::Mechanize::Pluggable;
use YAML::Syck;

my $username = &#39;xxxxx&#39;;
my $password = &#39;xxxxx&#39;;

my $mech = WWW::Mechanize::Pluggable-&gt;new();
$mech-&gt;get(&#39;http://www.hatena.ne.jp/login?location=http://s.hatena.ne.jp/&#39;);
$mech-&gt;submit_form(
    form_number =&gt; 1,
    fields =&gt; {
        name     =&gt; $username,
        password =&gt; $password,
    }
);
$mech-&gt;get(&quot;http://s.hatena.ne.jp/$username/report&quot;);
my $stars = $mech-&gt;scrape(&#39;span.entry-title a&#39;, &#39;stars[]&#39;,
    { title =&gt; &#39;TEXT&#39;, link =&gt; &#39;@href&#39; }
);
warn Dump $stars;</pre>
<p>いい感じにキレイですね。</p>

]]>
        
    </content>
</entry>

<entry>
    <title>CGI.pmのファイルアップローダ</title>
    <link rel="alternate" type="text/html" href="http://perl-mongers.org/2008/07/cgipm-uploader.html" />
    <id>tag:perl-mongers.org,2008://1.71</id>

    <published>2008-07-27T09:41:11Z</published>
    <updated>2008-07-28T13:27:08Z</updated>

    <summary>今日は、Perlで作るファイルアップローダの基本ルーチンを書いてみようと思います。 最初に某業界のインターネットによるファイル送信の歴史を、僕の主観で書いてみます。関係ないようで、実は関係あるんです。 データ通信入稿の歴史 専用線やISDN Managerなど、インフラにコストをかけないと遠隔地への通信入稿ができない前インターネット時代が終わり、インターネット時代になると、首都圏にある全国ユーザを対象にした印刷サービス業や地方の通販印刷業がまず行ったのはFTPサーバまたはAnonymousFTPサーバを立てデータ通信入稿に利用することだったが、これらはユーザにFTPクライアントを設定してもらう説明のコストが非常に高いという欠点があり、次なる手段として、どこかの業者がWebブラウザによるファイル送信を設置したところ他の業者も同様の仕組みを設置して今に至る。 Webのフォームからのアップロードによって、データ通信入稿がものすごく容易になったのです。 本題行きますね。 Perlでファイル送信 さて、Perlでファイル送信するスクリプトですが、CGI.pmというモジュールは今時標準モジュールなので、これを使うと簡単にできます。 テンポラリファイルが書き込まれるディレクトリの設定 CGI.pmのテンポラリファイルが書き込まれる場所が変更できないと思われている人も多いですけれども、実は変更可能。 僕のコードはこんな感じ。 # ------------------------------------------------- # _set_tempdirectory ( $tempdir ) # ------------------------------------------------- # CGI.pm の内部設定の、TMPDIRECTORY を引数に変更する。 # CGI.pm 初期化する前に設定する必要がある # ていうか、ここら辺アンドキュメンテッドなんじゃねー # ていうきもしなくもない。後で調べる。 sub _set_tempdirectory{ my $tempdir = shift; if ($TempFile::TMPDIRECTORY)...</summary>
    <author>
        <name>CL</name>
        <uri>http://blog.dtpwiki.jp/dtp/</uri>
    </author>
    
    <category term="qtmpfilename" label="$q-&gt;tmpFileName" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="cgipm" label="CGI.pm" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="filebasename" label="File::BaseName" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="filecopy" label="File::Copy" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="move" label="move" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="tmpdirectory" label="TMPDIRECTORY" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="upload" label="upload" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="uploader" label="uploader" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="アップローダ" label="アップローダ" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="アップロード" label="アップロード" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://perl-mongers.org/">
        <![CDATA[<p>今日は、Perlで作るファイルアップローダの基本ルーチンを書いてみようと思います。</p>

<p>最初に某業界のインターネットによるファイル送信の歴史を、僕の主観で書いてみます。関係ないようで、実は関係あるんです。</p>

<h3>データ通信入稿の歴史</h3>

<blockquote><p>専用線やISDN Managerなど、インフラにコストをかけないと遠隔地への通信入稿ができない前インターネット時代が終わり、インターネット時代になると、首都圏にある全国ユーザを対象にした印刷サービス業や地方の通販印刷業がまず行ったのはFTPサーバまたはAnonymousFTPサーバを立てデータ通信入稿に利用することだったが、これらはユーザにFTPクライアントを設定してもらう説明のコストが非常に高いという欠点があり、次なる手段として、どこかの業者がWebブラウザによるファイル送信を設置したところ他の業者も同様の仕組みを設置して今に至る。</blockquote></p>

<p>Webのフォームからのアップロードによって、データ通信入稿がものすごく容易になったのです。</p>

<p>本題行きますね。</p>

<h3>Perlでファイル送信</h3>

<p>さて、Perlでファイル送信するスクリプトですが、CGI.pmというモジュールは今時標準モジュールなので、これを使うと簡単にできます。</p>

<h4>テンポラリファイルが書き込まれるディレクトリの設定</h4>

<p>CGI.pmのテンポラリファイルが書き込まれる場所が変更できないと思われている人も多いですけれども、実は変更可能。</p>

<p>僕のコードはこんな感じ。</p>

<pre class="prettyprint">
# -------------------------------------------------
# _set_tempdirectory ( $tempdir ) 
# -------------------------------------------------
# CGI.pm の内部設定の、TMPDIRECTORY を引数に変更する。
# CGI.pm 初期化する前に設定する必要がある
# ていうか、ここら辺アンドキュメンテッドなんじゃねー
# ていうきもしなくもない。後で調べる。 
 
sub _set_tempdirectory{
   
  my $tempdir = shift;
 
  if ($TempFile::TMPDIRECTORY) {
    $TempFile::TMPDIRECTORY = $tempdir; 
  } 
  elsif($CGITempFile::TMPDIRECTORY) {
    $CGITempFile::TMPDIRECTORY = $tempdir;
  }
 
  return;
}</pre>

このルーチンを、<strong>use CGI; した後、かつ、my $q = CGI-&gt;new; する前に実行</strong>します。

<p>これ何に役立つかっていうと、アップロードCGI呼び出しの引数によってアップロード先のURLを区別したいときに使います。つまり、アップロード中のステータス、たとえばファイル転送済みの容量表示をしたいときに。</p>

<p>ここで、CGI.pm をよく使っている人は、「my $q = CGI-&gt;new; する前なのに、どうやってアップロードCGI呼び出しの引数をとれるの？」って思うかもしれません。そう、おなじみの$q-&gt;param(&#39;foo&#39;)でとれないんです。</p>

<p>しかし、引数とるのに、CGI.pmを使う必要はありません。$ENV{&#39;QUERY_STRING&#39;}をパースしちゃいましょう！ Perl4時代に逆戻りですね！</p>

<h4>テンポラリディレクトリにアップロードされたファイルの保存</h4>

<p>この手のルーチン作例は、いっぱいWebにあがっているのですが、テンポラリディレクトリにあるファイルを、実際のファイルに保存するルーチンがみんなまちまちで、どれを使っていいか悩みます。</p>

<p><a href="http://perldoc.jp/docs/modules/CGI.pm-2.89/CGI.pod">http://perldoc.jp/docs/modules/CGI.pm-2.89/CGI.pod</a>だと</p>

<blockquote><pre>
   # バイナリ・ファイルをどこか安全なところへコピーします
    open (OUTFILE,&quot;&gt;&gt;/usr/local/web/users/feedback&quot;);
    while ($bytesread=read($filename,$buffer,1024)) {
       print OUTFILE $buffer;
    }</pre>

</blockquote>

<p>となっています。これスピード遅くね？</p>

<p>実際、最近の入稿データは余裕で1GBとかありますので、普通のやり方をしてたのでは、アップロード送信終了後の待ち時間がとても長くなりがちです。</p>

<p>とりあえず、僕は、File::Copyモジュールのmoveを使ってみました。これだったら、テンポラリディレクトリと、保存ディレクトリが同じファイルシステム上にあるのならば、一瞬で保存が終わってくれます。</p>

<p>ここで、CGI.pm をよく使っている人は、「moveって、たしか引数としてtarget pathとdestination pathの2つが必要で、ファイルハンドルだと駄目だったよね？」って思うかもしれません。そう、$q-&gt;upload(&#39;foo&#39;)をそのまま使えません。</p>

<p>でも、ちゃんと考えてあって、$q-&gt;tmpFileName( $q-&gt;upload(&#39;foo&#39;) )なんてすると、テンポラリファイルのパスが得られちゃうんです。これは便利。</p>

<p>実際には以下のようになります。</p>

<pre class="prettyprint">
use CGI;
use File::Copy;
use File::Basename;

my $upload_dir  = &#39;upload&#39;;      # 保存先のディレクトリ
 
my $q  = CGI-&gt;new();             # CGIオブジェクト
my $fh = $q-&gt;upload(&#39;filename&#39;); # ファイルハンドル兼ファイル名
my $temp_path = $q-&gt;tmpFileName($fh); # アップロードされた
                                      #ファイルのフルパス
fileparse_set_fstype(&#39;MSDOS&#39;);   # WinIE用パス文字設定
my $filename    = basename($fh); # アップロードされたファイルの
                                 # ファイル名
my $upload_path
  = &quot;$upload_dir/$filename&quot;;     # 保存先フルパス
 
move ($temp_path, $upload_path)  # File::Copy の moveメソッドで
  or die $!;                     # 移動
close($fh);                      # おまじない</pre>

続きを読む以降では、僕が持っている実際のアップロードルーチンのソースが書いてあります。]]>
        <![CDATA[<h3>サンプルソース</h3>

<p>これ実際に使ってます。テンポラリディレクトリの位置を変える必要がないので、前出のテンポラリディレクトリ指定ルーチンは組み込んでません。</p>

<p>Fillename:upload.cgi</p>

<pre class="prettyprint">
#!/usr/bin/perl
use strict;
use warnings;
use CGI;
use CGI::Carp qw(fatalsToBrowser);
use File::Copy;
use File::Basename;
 
my $upload_dir  = &#39;upload&#39;;      # 保存先のディレクトリ
 
my $q  = CGI-&gt;new();             # CGIオブジェクト
my $fh = $q-&gt;upload(&#39;filename&#39;); # ファイルハンドル兼ファイル名
my $temp_path = $q-&gt;tmpFileName($fh); # アップロードされた
                                      #ファイルのフルパス
fileparse_set_fstype(&#39;MSDOS&#39;);   # WinIE用パス文字設定
my $filename    = basename($fh); # アップロードされたファイルの
                                 # ファイル名
my $upload_path
  = &quot;$upload_dir/$filename&quot;;     # 保存先フルパス
 
move ($temp_path, $upload_path)  # File::Copy の moveメソッドで
  or die $!;                     # 移動
close($fh);                      # おまじない
 
print $q-&gt;header( -type=&gt;&#39;text/html&#39;, -charset=&gt;&#39;UTF-8&#39;, );
print &lt;&lt;&quot;END_OF_HTML&quot;;
&lt;body&gt;&lt;p&gt;done.&lt;/p&gt;&lt;/body&gt;
END_OF_HTML
 
exit;
 
__END__</pre>

Filename: upload.html

<pre class="prettyprint">
&lt;html&gt;
  &lt;body&gt;
    &lt;form action=&quot;upload.cgi&quot; method=&quot;post&quot;
      enctype=&quot;multipart/form-data&quot;&gt;
      &lt;p&gt;
        &lt;label for=&quot;filename&quot;&gt;file&lt;/label&gt;
        &lt;br&gt;
        &lt;input type=&quot;file&quot; name=&quot;filename&quot; id=&quot;filename&quot;&gt;
      &lt;/p&gt;
      &lt;p&gt;
        &lt;input type=&quot;submit&quot; name=&quot;submit&quot; value=&quot;submit&quot;&gt;
      &lt;/p&gt;
    &lt;/form&gt;
  &lt;/body&gt;
&lt;/html&gt;</pre>

<h3>さいごに</h3>

<p>自分のblogに書いていてもコードの善し悪しを評価してもらえず、せっかくperl-mongers.orgていうのがあるので、ここに書いてみようと思いました。</p>

<p>おそらく、ファイルシステムに使うファイル名に、外来のデータ由来の文字をそのまま使うな、ていう指摘はあるとは思いますが、<a href="http://blog.dtpwiki.jp/dtp/2005/06/post_f824.html">その点は全くアグリーです</a>。</p>

<p>このエントリのオリジナルは、</p>

<p><a href="http://blog.dtpwiki.jp/dtp/2007/10/cgipm_e5c6.html">M.C.P.C.: CGI.pmのアップロード後のファイル処理を高速に行う</a> [blog.dtpwiki.jp] です。</p>]]>
    </content>
</entry>

<entry>
    <title>何時でも何処でも携帯で「はてなスター」チェック</title>
    <link rel="alternate" type="text/html" href="http://perl-mongers.org/2008/07/post_4.html" />
    <id>tag:perl-mongers.org,2008://1.70</id>

    <published>2008-07-08T06:09:48Z</published>
    <updated>2008-07-18T07:02:04Z</updated>

    <summary><![CDATA[追記 コメント欄でotsuneさんにご指摘頂きました。scraperのprocess部、LWPの初期化をループ内で行わないようにしました。 やっぱり書いた記事にはてなスターが付くと嬉しいものですよね。出先でちょっとした間にはてなスターが付いているのを見て、ニタニタしたい人もいるかと思います。 でもはてなスターにはモバイルページがありません。しかもスターレポートページを閲覧するにはログインが必要になります。さて今日はモバイル端末から閲覧出来るエゴツール「モバイルはてなスターページ」を作って見たいと思います。 まずスターレポートページを見る為に、WWW::Mechanizeを使ってログインします。ログインページは http://www.hatena.ne.jp/login?location=http://s.hatena.ne.jp/ となります。セキュリティを考慮されたいならばhttpsにされるのが良いかと思います。以下WWW::Mechanizeでログインする処理になります。 my $username = &#39;xxxxxxxx&#39;; my $password = &#39;xxxxxxxx&#39;; my $mech = WWW::Mechanize-&gt;new(timeout =&gt; 10, agent=&gt;&#39;StarScraper&#39;); $mech-&gt;get(&#39;http://www.hatena.ne.jp/login?location=http://s.hatena.ne.jp/&#39;); $mech-&gt;add_header(&#39;Accept-Encoding&#39;, &#39;identity&#39;); my $res = $mech-&gt;submit_form( form_number =&gt; 1, fields =&gt; { name =&gt; $username, password =&gt;...]]></summary>
    <author>
        <name>mattn</name>
        <uri>http://mattn.kaoriya.net/</uri>
    </author>
    
    <category term="webscraper" label="Web::Scraper" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="wwwmechanize" label="WWW::Mechanize" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://perl-mongers.org/">
        <![CDATA[<h4>追記</h4>
<p>コメント欄でotsuneさんにご指摘頂きました。scraperのprocess部、LWPの初期化をループ内で行わないようにしました。</p>
<br />
<p>やっぱり書いた記事に<a href="http://s.hatena.ne.jp/">はてなスター</a>が付くと嬉しいものですよね。出先でちょっとした間に<a href="http://s.hatena.ne.jp/">はてなスター</a>が付いているのを見て、ニタニタしたい人もいるかと思います。</p>
<p>でも<a href="http://s.hatena.ne.jp/">はてなスター</a>にはモバイルページがありません。しかもスターレポートページを閲覧するにはログインが必要になります。さて今日はモバイル端末から閲覧出来るエゴツール「モバイルはてなスターページ」を作って見たいと思います。</p>
<p>まずスターレポートページを見る為に、WWW::Mechanizeを使ってログインします。ログインページは</p>
<pre>
http://www.hatena.ne.jp/login?location=http://s.hatena.ne.jp/</pre>
<p>となります。セキュリティを考慮されたいならばhttpsにされるのが良いかと思います。以下WWW::Mechanizeでログインする処理になります。</p>
<pre class="prettyprint">
my $username = &#39;xxxxxxxx&#39;;
my $password = &#39;xxxxxxxx&#39;;

my $mech = WWW::Mechanize-&gt;new(timeout =&gt; 10, agent=&gt;&#39;StarScraper&#39;);
$mech-&gt;get(&#39;http://www.hatena.ne.jp/login?location=http://s.hatena.ne.jp/&#39;);
$mech-&gt;add_header(&#39;Accept-Encoding&#39;, &#39;identity&#39;);
my $res = $mech-&gt;submit_form(
    form_number =&gt; 1,
    fields =&gt; {
        name     =&gt; $username,
        password =&gt; $password,
    }
);</pre>
<p>ログイン後の処理はWeb::Scraperでのスクレイピングになります。レシピは以下の通り</p>
<pre class="prettyprint">
my $star_list = scraper {
    process &#39;span.entry-title&#39;,
        &#39;stars[]&#39; =&gt; scraper {
            process &#39;a&#39;, title =&gt; &#39;TEXT&#39;, link =&gt; &#39;@href&#39;;
        };
    result &#39;stars&#39;;
};</pre>
<p>そして上記mechをWeb::Scraperのuaに設定し、スクレイピングを実行します。</p>
<pre class="prettyprint">
$star_list-&gt;user_agent( $mech );

my $u = &quot;http://s.hatena.ne.jp/$username/report&quot;;
my $stars = $star_list-&gt;scrape( URI-&gt;new($u) );</pre>
<p>さて、これだけではスターが付けられたURLの一覧しか取得出来ません。そこで、はてなスターAPIを使ってスターのエントリを取得します。はてなスターAPIのエントリ取得URLは以下の通り。</p>
<pre>
http://s.hatena.ne.jp/entries.json?uri=[URL]</pre>
<p>このAPIに上記でスクレイピングしたURLを渡します。</p>
<pre class="prettyprint">
my $ua = LWP::UserAgent-&gt;new;
for my $star (@$stars) {
    my $uri = &#39;http://s.hatena.ne.jp/entries.json?uri=&#39; . URI::Escape::uri_escape($star-&gt;{link});
    my $req = HTTP::Request-&gt;new(GET =&gt; $uri);
    my $res = $ua-&gt;request($req);
    $res-&gt;is_success or return 0;
    my $json = from_json( $res-&gt;content );
    my @sts = @{$json-&gt;{entries}-&gt;[0]-&gt;{stars}};
}</pre>
<p>ここで気をつける必要があるのですが、stsの要素はHASHの場合とスカラの場合があり、HASHにはスター情報が、スカラには&quot;☆35☆&quot;といった省略する数値が入っています。これに気をつけて以下の様に処理します。</p>
<pre class="prettyprint">
    for my $st (@sts) {
        if (ref $st eq &#39;HASH&#39;) {
            print &#39;&lt;img src=&quot;http://s.hatena.ne.jp/images/star.gif&quot; title=&quot;&#39; . $st-&gt;{name} . &#39;&quot; /&gt;&#39;
        } else {
            printf &#39;&lt;font color=&quot;#f4b128&quot;&gt;%d&lt;/font&gt;&#39;, $st;
        }
    }</pre>
<p>全体のコードは以下の様になります。</p>
<pre class="prettyprint">
#!/usr/bin/perl

use warnings;
use strict;
use URI;
use Web::Scraper;
use HTML::Entities;
use WWW::Mechanize;
use JSON;

my $username = &#39;xxxxxxxx&#39;;
my $password = &#39;xxxxxxxx&#39;;

my $mech = WWW::Mechanize-&gt;new(timeout =&gt; 10, agent=&gt;&#39;StarScraper&#39;);
$mech-&gt;get(&#39;http://www.hatena.ne.jp/login?location=http://s.hatena.ne.jp/&#39;);
$mech-&gt;add_header(&#39;Accept-Encoding&#39;, &#39;identity&#39;);
my $res = $mech-&gt;submit_form(
    form_number =&gt; 1,
    fields =&gt; {
        name     =&gt; $username,
        password =&gt; $password,
    }
);

my $star_list = scraper {
    process &#39;span.entry-title&#39;,
        &#39;stars[]&#39; =&gt; scraper {
            process &#39;a&#39;, title =&gt; &#39;TEXT&#39;, link =&gt; &#39;@href&#39;;
        };
    result &#39;stars&#39;;
};
$star_list-&gt;user_agent( $mech );

print &quot;Content-Type: text/html; charset=utf-8\n\n&quot;;
my $u = &quot;http://s.hatena.ne.jp/$username/report&quot;;
my $stars = $star_list-&gt;scrape( URI-&gt;new($u) );
my $ua = LWP::UserAgent-&gt;new;
for my $star (@$stars) {
    printf &quot;&lt;a href=\&quot;%s\&quot;&gt;%s&lt;/a&gt;&lt;br /&gt;&amp;#x202C;\n&quot;, $star-&gt;{link}, encode_entities($star-&gt;{title});
    my $uri = &#39;http://s.hatena.ne.jp/entries.json?uri=&#39; . URI::Escape::uri_escape($star-&gt;{link});
    my $req = HTTP::Request-&gt;new(GET =&gt; $uri);
    my $res = $ua-&gt;request($req);
    $res-&gt;is_success or return 0;
    my $json = from_json( $res-&gt;content );
    my @sts = @{$json-&gt;{entries}-&gt;[0]-&gt;{stars}};
    for my $st (@sts) {
        if (ref $st eq &#39;HASH&#39;) {
            print &#39;&lt;img src=&quot;http://s.hatena.ne.jp/images/star.gif&quot; title=&quot;&#39; . $st-&gt;{name} . &#39;&quot; /&gt;&#39;
        } else {
            printf &#39;&lt;font color=&quot;#f4b128&quot;&gt;%d&lt;/font&gt;&#39;, $st;
        }
    }
    print &quot;&lt;br /&gt;\n&quot;;
}</pre>
<p>携帯片手にニタニタしてみてはどうでしょうか。</p>

]]>
        
    </content>
</entry>

<entry>
    <title>strict プラグマについて</title>
    <link rel="alternate" type="text/html" href="http://perl-mongers.org/2008/07/strict.html" />
    <id>tag:perl-mongers.org,2008://1.69</id>

    <published>2008-07-07T15:17:38Z</published>
    <updated>2008-07-07T16:11:54Z</updated>

    <summary><![CDATA[友達が以前、日記で「use strict; って何でデフォルトでオンになってないの？」と言うことを書いていたのを見て、そういえばどうしてなんだろうと思ったのを思い出したので、書いてみる。（use すると strict プラグマが効くようになるモジュールとかはありますね。moose とか。そういう需要はあると言うことですよね） perl を始めた方は、知り合いに勧められて始めた場合、「とにかく use strict; を宣言しておくといいよ」と言われて付けていたり、フリーで配布されてる掲示板スクリプトを改造していて、「use strict; した方が良いっぽい」と思ってやってみたらエラーの嵐でさんざんな目にあったりしてい(る|た)人も多いかと思います。後者は昔の僕ですが。 まぁ、use strict をするとなぜいいのかは tomyhero さんがすでに書いているので、そちらを参照してください。 「use strict; って何でデフォルトでオンになってないの？」 言われてみれば確かに。何でなんでしょうか？ よく Perl を使っていて、Perl の黒魔術的なところも知っている人なら、strict を無効化しないと出来ない処理があることは理解されてますよね。でも、そういうときは &quot;no strict;&quot; として局所的に strict プラグマを無効化出来ることも知っているはず。 デフォルトがオンで必要なところで no strict するのであれば、理にかなってるような気もしますよね。 ただ、ここまではスクリプトやモジュールを書くときの話で、ワンライナーのユーザがデフォルトで use strict...]]></summary>
    <author>
        <name>vkgtaro</name>
        
    </author>
    
    <category term="strict" label="strict" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="質問" label="質問" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="雑感" label="雑感" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://perl-mongers.org/">
        <![CDATA[<p>友達が以前、日記で「use strict; って何でデフォルトでオンになってないの？」と言うことを書いていたのを見て、そういえばどうしてなんだろうと思ったのを思い出したので、書いてみる。（use すると strict プラグマが効くようになるモジュールとかはありますね。moose とか。そういう需要はあると言うことですよね）</p>
<p>perl を始めた方は、知り合いに勧められて始めた場合、「とにかく use strict; を宣言しておくといいよ」と言われて付けていたり、フリーで配布されてる掲示板スクリプトを改造していて、「use strict; した方が良いっぽい」と思ってやってみたらエラーの嵐でさんざんな目にあったりしてい(る|た)人も多いかと思います。後者は昔の僕ですが。</p>
<p>まぁ、use strict をするとなぜいいのかは tomyhero さんが<a href="http://perl-mongers.org/2008/05/use_strict.html">すでに書いているので、そちらを参照してください。</a></p>
<p>「use strict; って何でデフォルトでオンになってないの？」</p>
<p>
言われてみれば確かに。何でなんでしょうか？<br />
よく Perl を使っていて、Perl の黒魔術的なところも知っている人なら、strict を無効化しないと出来ない処理があることは理解されてますよね。でも、そういうときは &quot;no strict;&quot; として局所的に strict プラグマを無効化出来ることも知っているはず。
</p>
<p>デフォルトがオンで必要なところで no strict するのであれば、理にかなってるような気もしますよね。</p>
<p>
ただ、ここまではスクリプトやモジュールを書くときの話で、ワンライナーのユーザがデフォルトで use strict オンだと面倒なのかなーとか想像してます。<br />
いちいち my 書くの面倒だよねとか、そんな感じなのかなーとか考えてみたんだけど、どうなんでしょうか？あくまで僕の考えです。
</p>
<p>誰か答えを知っていたら教えてください！</p>

<h3> 追記</h3>

<p>tomyhero さんの記事に<a href="http://perl-mongers.org/2008/05/use_strict.html">理由が書いてあったのを突っ込まれました &gt;_&lt;</a>（&quot;もう一つの使い方&quot;ってところ）</p>
<p>感謝というのはいいですよね。なんか色んな人の意見聞いてみたい！</p>

]]>
        
    </content>
</entry>

<entry>
    <title>実用！ 画像でブックマーク数を返すSBMからブックマーク数を数値で取得</title>
    <link rel="alternate" type="text/html" href="http://perl-mongers.org/2008/07/_sbm.html" />
    <id>tag:perl-mongers.org,2008://1.68</id>

    <published>2008-07-05T03:59:05Z</published>
    <updated>2008-07-07T04:29:45Z</updated>

    <summary><![CDATA[こんにちは！ この前会社のCentOS4のサーバをyumったらPerl5.8.5のパッケージが更新されてしまい、CPANから入れたEncodeモジュールがパッケージのでデグレードしてしまい、メール送信で使っていたencode(&#39;MIME-Header-ISO_2022_JP&#39;, $foo )が動かなくなって涙目になりました。 さて、前回実用！ Perlで少しでもSBMのブックマーク数を多く見せる - perl-mongers.orgでは、いろいろなソーシャルブックマークサービス（以下SBM）に用意されたWeb APIにアクセスし、ブックマーク数の合計をとるということをやりました。 今回は、SBMから得られる特定URLのブックマーク数が、イメージで得られるタイプの場合、どうやって数値として使えるか、というのをやってみます。本来想定された用途以外の使い方にチャレンジする、という意味では、Hackと言えると思います。 ～～～ たとえば、FC2ブックマーク、画像としてブックマーク数を表示できるようになっています。 http://bookmark.fc2.com/image/users/http://perl-mongers.org/ で、 が得られます。 コンピュータが画像から文字を解読するのは大変 SBMから得られる画像に数字が書いてある場合、その画像から数字を認識させるのはかなり困難です。あらかじめ得られる画像データの特徴リストを持っておき、それと照合する、なんてことをすれば簡単になりますが、SBMサービス側の気まぐれで、「画像内の数字をかっこよくしよう」、なんてやられてしまった日には涙目です。 というわけで、画像を解析して数字を得るって言うのはあんまり現実的ではないです。 隠れたところにブックマーク数として採用できるデータが！ さて、画像を解析するのがボツになったので、じゃあどうやって、ブックマーク数の情報を取得するのか、という話なんですけれども、先ほどの http://bookmark.fc2.com/image/users/http://perl-mongers.org/ にブラウザでアクセスすると、 ブラウザのアドレス欄が、&quot;http://bookmark.fc2.com/icons/00002.png&quot;とかになっていることに注目。つまり、画像表示のために、画像アイコンのURLにリダイレクトされているのです。 このURLの中に、なにやらブックマーク数として採用できそうな文字列が入っているので、これを利用します。 リダイレクト先のURLだけを取得 PerlでHTTPの通信をするときによく使われる、LWP::UserAgentを使います。リクエスト用URLをGETすると、ヘッダに、転送先のURLが入って帰ってくるので、それを正規表現で数字部分だけ取り出し、数値として取り扱います。 下の例では、画像として取得できるサービス一般で使えるようにしてみました。 各ソーシャルブックマークサービス（SBM）のブックマーク数画像表示APIを調べた ::: creazy photograph [creazy.net] にて、各SBMにて、画像として取得するときのリクエスト用URLと、リダイレクト先のURLが書いてありますので、そのようにやってみます。なお、@niftyクリップと、POOKMARKはこっちで調査して付け加えました。 （2008-07-06 13:06訂正：スクリプトの名前をsmb_img_count.plからsbm_img_count.plに変更。livedoor用画像ファイル取得アドレスがYahoo!用のものになっていたのを訂正。また、動作がわかりやすいように、リダイレクト先のURLを表示するようにし、実行例も変更しました。http://b.hatena.ne.jp/kits/20080706#bookmark-9198443より指摘いただきました。） Filename: sbm_img_count.pl use strict; use...]]></summary>
    <author>
        <name>CL</name>
        <uri>http://blog.dtpwiki.jp/dtp/</uri>
    </author>
    
    <category term="lwpuseragent" label="LWP::UserAgent" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="simple_request" label="simple_request" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="xmlrpclite" label="XMLRPC::Lite" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="xmlrpctransporthttp" label="XMLRPC::Transport::HTTP" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="リダイレクト" label="リダイレクト" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://perl-mongers.org/">
        <![CDATA[<p>こんにちは！ この前会社のCentOS4のサーバをyumったらPerl5.8.5のパッケージが更新されてしまい、CPANから入れたEncodeモジュールがパッケージのでデグレードしてしまい、メール送信で使っていたencode(&#39;MIME-Header-ISO_2022_JP&#39;, $foo )が動かなくなって涙目になりました。</p>

<p>さて、前回<a href="http://perl-mongers.org/2008/06/perl-sbm.html">実用！ Perlで少しでもSBMのブックマーク数を多く見せる - perl-mongers.org</a>では、いろいろなソーシャルブックマークサービス（以下SBM）に用意されたWeb APIにアクセスし、ブックマーク数の合計をとるということをやりました。</p>

<p>今回は、SBMから得られる特定URLのブックマーク数が、イメージで得られるタイプの場合、どうやって数値として使えるか、というのをやってみます。本来想定された用途以外の使い方にチャレンジする、という意味では、Hackと言えると思います。</p>

<p>～～～</p>

<p>たとえば、FC2ブックマーク、画像としてブックマーク数を表示できるようになっています。</p>

<p><a href="http://bookmark.fc2.com/image/users/http://perl-mongers.org/">http://bookmark.fc2.com/image/users/http://perl-mongers.org/</a></p>

<p>で、</p>

<p><img src="http://bookmark.fc2.com/image/users/http://perl-mongers.org/" /></p>

<p>が得られます。</p>

<h4>コンピュータが画像から文字を解読するのは大変</h4>

<p>SBMから得られる画像に数字が書いてある場合、その画像から数字を認識させるのはかなり困難です。あらかじめ得られる画像データの特徴リストを持っておき、それと照合する、なんてことをすれば簡単になりますが、SBMサービス側の気まぐれで、「画像内の数字をかっこよくしよう」、なんてやられてしまった日には涙目です。</p>

<p>というわけで、画像を解析して数字を得るって言うのはあんまり現実的ではないです。</p>

<h4>隠れたところにブックマーク数として採用できるデータが！</h4>

<p>さて、画像を解析するのがボツになったので、じゃあどうやって、ブックマーク数の情報を取得するのか、という話なんですけれども、先ほどの</p>

<p><a href="http://bookmark.fc2.com/image/users/http://perl-mongers.org/">http://bookmark.fc2.com/image/users/http://perl-mongers.org/</a></p>

<p>にブラウザでアクセスすると、</p>

<p>ブラウザのアドレス欄が、&quot;http://bookmark.fc2.com/icons/00002.png&quot;とかになっていることに注目。つまり、画像表示のために、画像アイコンのURLにリダイレクトされているのです。</p>

<p>このURLの中に、なにやらブックマーク数として採用できそうな文字列が入っているので、これを利用します。</p>

<h4>リダイレクト先のURLだけを取得</h4>

<p>PerlでHTTPの通信をするときによく使われる、LWP::UserAgentを使います。リクエスト用URLをGETすると、ヘッダに、転送先のURLが入って帰ってくるので、それを正規表現で数字部分だけ取り出し、数値として取り扱います。</p>

<p>下の例では、画像として取得できるサービス一般で使えるようにしてみました。</p>

<p><a href="http://creazy.net/2008/01/sbm_counter_image_api.html">各ソーシャルブックマークサービス（SBM）のブックマーク数画像表示APIを調べた ::: creazy photograph</a> [creazy.net]</p>

<p>にて、各SBMにて、画像として取得するときのリクエスト用URLと、リダイレクト先のURLが書いてありますので、そのようにやってみます。なお、@niftyクリップと、POOKMARKはこっちで調査して付け加えました。</p>

<p>（2008-07-06 13:06訂正：スクリプトの名前をsmb_img_count.plからsbm_img_count.plに変更。livedoor用画像ファイル取得アドレスがYahoo!用のものになっていたのを訂正。また、動作がわかりやすいように、リダイレクト先のURLを表示するようにし、実行例も変更しました。<a href="http://b.hatena.ne.jp/kits/20080706#bookmark-9198443">http://b.hatena.ne.jp/kits/20080706#bookmark-9198443</a>より指摘いただきました。）</p>

<p>Filename: sbm_img_count.pl</p>

<pre class="prettyprint">
use strict;
use warnings;
use LWP::UserAgent;
 
our $sbms = { 
       hatena =&gt;
       {
         proxy   =&gt; &#39;http://b.hatena.ne.jp/entry/image/&#39;,
         regexp  =&gt; &#39;/(\d+)\.png&#39;,
       },
       livedoor =&gt;
       {
         proxy   =&gt; &#39;http://image.clip.livedoor.com/counter/&#39;,
         regexp  =&gt; &#39;/(\d+)$&#39;,
       },
       yahoo =&gt;
       {
         proxy   =&gt; &#39;http://num.bookmarks.yahoo.co.jp/image/large/&#39;,
         regexp  =&gt; &#39;/(\d+)$&#39;,
       },
       buzzurl =&gt;
       {
         proxy   =&gt; &#39;http://api.buzzurl.jp/api/counter/v1/image?url=&#39;,
         regexp  =&gt; &#39;/(\d+)\.gif&#39;,
       },
       fc2 =&gt;
       {
         proxy   =&gt; &#39;http://bookmark.fc2.com/image/users/&#39;,
         regexp  =&gt; &#39;/(\d+)\.png&#39;,
       },
       nifty =&gt;
       {
         proxy   =&gt; &#39;http://api.clip.nifty.com/api/v1/image/counter/&#39;,
         regexp  =&gt; &#39;/(\d+)\.png&#39;,
       },
       pookmark =&gt;
       {
         proxy   =&gt; &#39;http://pookmark.jp/count/&#39;,
         regexp  =&gt; &#39;/(\d+)$&#39;,
       },
};
 
my $url = &#39;http://perl-mongers.org/&#39;;
print 0
    + get_sbm( &#39;hatena&#39;  , $url )
    + get_sbm( &#39;livedoor&#39;, $url )
    + get_sbm( &#39;yahoo&#39;   , $url )
    + get_sbm( &#39;buzzurl&#39; , $url )
    + get_sbm( &#39;fc2&#39;     , $url )
    + get_sbm( &#39;nifty&#39;   , $url )
    + get_sbm( &#39;pookmark&#39;, $url );
print &quot;\n&quot;;
 
exit;
 
 
sub get_sbm {
  my $service = shift;
  my $url     = shift;
  return get_sbm_imageicon( $service, $url )
}
 
# ブックマーク件数イメージ提供サービスから件数取得
sub get_sbm_imageicon {
  my $servce = shift;
  my $url    = shift;
  our $sbms;
  my $ua = LWP::UserAgent-&gt;new();
  $ua-&gt;agent(&#39;Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)&#39;);
  my $method = &#39;GET&#39;;
  #my $method = &#39;HEAD&#39;;
  my $req = HTTP::Request-&gt;new( $method,
                                $sbms-&gt;{$servce}-&gt;{proxy}.$url );
  my $res = $ua-&gt;simple_request($req);
  my $location = $res-&gt;header(&#39;location&#39;);
  print &quot;$location\n&quot;;
  my $count = 0;
  if ( $location =~ m|$sbms-&gt;{$servce}-&gt;{regexp}| ) {
    $count = 0 + $1;
  }
  return $count;
}</pre>

実行例：

<pre>
$ sbm_img_count.pl
http://b.hatena.ne.jp/images/users/normal/00134.png
http://image.clip.livedoor.com/img/users/small/00019.png
http://thumbnail.yimg.jp/number/large/7
http://cdn.buzzurl.jp/static/image/num/1.gif
http://bookmark.fc2.com/icons/00002.png
http://clip.nifty.com/images/counter/00000.png
http://pookmark.jp/images/count/3
147
$</pre>

便利に使うには、コマンドラインからの入力が@ARGVに入るので、コマンドラインからURLを入れて問い合わせるように改造する、CGI.pmモジュールを使って、URLのクエリーから問い合わせるように改造する、等々できるんじゃないかなと思います。

<p><br />
[続きを読む]以降では、画像でしかブックマーク数の情報を提供していないSBMで、SBM運営会社の代わりに、XML-RPCインターフェースのAPIを用意するというあさっての方向に突っ走ってみます。</p>]]>
        <![CDATA[<p>～～～</p>

<p>FC2ブックマークでは、ブックマーク数が画像でしかとれないような感じですので、代わりにXML-RPCによるAPIを用意してみます。これまでの画像取得URLのリダイレクト先を見るので充分じゃないか、という気もしますが、まあこれはこれで応用できるような気もします故。</p>

<p>Filename: xmlrpc.cgi</p>

<pre class="prettyprint">
#!/usr/bin/perl
use strict;
use warnings;
use XMLRPC::Transport::HTTP;
 
XMLRPC::Transport::HTTP::CGI
  -&gt; dispatch_to(&#39;link&#39;)
  -&gt; handle;
exit;
 
package link;
use strict;
use warnings;
use CGI;
use LWP::UserAgent;
use utf8;
binmode STDOUT =&gt; &#39;:utf8&#39;;
 
 
sub getCount {
  shift if UNIVERSAL::isa($_[0] =&gt; __PACKAGE__);
  my $self;
  @$self = @_;

  our $sbms = { 
         fc2 =&gt;
         {
           proxy   =&gt; &#39;http://bookmark.fc2.com/image/users/&#39;,
           regexp  =&gt; &#39;/(\d+)\.png&#39;,
         },
  };
  my $res = {};
  foreach my $item ( @$self ) {
    $res-&gt;{$item} = get_sbm_imageicon(&#39;fc2&#39;, $item);
  }
  return $res;
};
 
 
# ブックマーク件数イメージ提供サービスから件数取得
sub get_sbm_imageicon {
  my $servce = shift;
  my $url    = shift;
  our $sbms;
  my $ua = LWP::UserAgent-&gt;new();
  $ua-&gt;agent(&#39;Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)&#39;);
  my $req = HTTP::Request-&gt;new( &#39;GET&#39;,
                                $sbms-&gt;{$servce}-&gt;{proxy}.$url );
  my $res = $ua-&gt;simple_request($req);
  my $location = $res-&gt;header(&#39;location&#39;);
  my $count = 0;
  if ( $location =~ m|$sbms-&gt;{$servce}-&gt;{regexp}| ) {
    $count = 0 + $1;
  }
  return $count;
}


1;</pre>

これを呼び出すクライアントは、こうです。

<p>Filename: client.pl</p>

<pre class="prettyprint">
#!/usr/bin/perl
use strict;
use warnings;
use XMLRPC::Lite;
 
our $EndPoint = &#39;http://example.com/path/to/xmlrpc.cgi&#39;;
 
my @urls = (
    &#39;http://perl-mongers.org/&#39;,
    &#39;http://instfont.info/&#39;,
    &#39;http://pdf.printjapan.com/&#39;,
);
 
my $map = XMLRPC::Lite
     -&gt; proxy($EndPoint)
     -&gt; call (&#39;link.getCount&#39;, @urls)
     -&gt; result;
 
printf(&quot;%d\t%s\n&quot;, $map-&gt;{$_}, $_) for @urls;</pre>

実行例：

<p>$ perl client.pl <br />
2       <a href="http://perl-mongers.org/">http://perl-mongers.org/</a><br />
0       <a href="http://instfont.info/">http://instfont.info/</a><br />
6       <a href="http://pdf.printjapan.com/">http://pdf.printjapan.com/</a><br />
$</p>

<p>～～～</p>

<p>今回のエントリは、</p>

<p><a href="http://blog.dtpwiki.jp/dtp/2007/06/xmlrpclitehello_9df7.html">M.C.P.C.: XMLRPC::LiteでHello, World!</a> [blog.dtpwiki.jp]<br />
<a href="http://blog.dtpwiki.jp/dtp/2008/04/edge_nowapixmlr_6fa3.html">M.C.P.C.: EDGE Now!のリンク件数を返す野良API（XML-RPC）プログラム</a> [blog.dtpwiki.jp]</p>

<p>の再構成品です......</p>

<p><br />
（2008-07-06 13:17追記）</p>

<p><a href="http://b.hatena.ne.jp/kits/20080706#bookmark-9198443">http://b.hatena.ne.jp/kits/20080706#bookmark-9198443</a></p>

<blockquote><p>[perl][http][sbm]smb_img_count.plで、livedoorのproxyがyahooのと同じになってます。/ Locationの取得ならHEADでもよさそうだけど、サービス側がGETしか対応してないところが幾つかあり。</p></blockquote>

<p>とありましたので、proxyの記述については訂正しました。また、HEADでやった例を以下に示します。</p>

<pre class="prettyprint">
$ perl sbm_img_count_head.pl 
http://b.hatena.ne.jp/images/users/normal/00134.png
http://image.clip.livedoor.com/img/users/small/00019.png
http://thumbnail.yimg.jp/number/large/7
http://cdn.buzzurl.jp/static/image/top/s.gif
http://bookmark.fc2.com/icons/00002.png
http://clip.nifty.com/images/counter/00000.png
http://pookmark.jp/images/count/3
146
$</pre>

どうやら、BuzzurlがHEADによるリクエストに対応してくれないようです。]]>
    </content>
</entry>

<entry>
    <title>デフォルト値のperlらしい指定法</title>
    <link rel="alternate" type="text/html" href="http://perl-mongers.org/2008/07/perl_1.html" />
    <id>tag:perl-mongers.org,2008://1.67</id>

    <published>2008-07-02T14:17:14Z</published>
    <updated>2008-07-02T17:33:20Z</updated>

    <summary> http://blog.livedoor.jp/dankogai/archives/51074877.html のダイジェスト。 Scalarによるデフォルト値 sub num{ my $num = shift || -1; # .... } 0や&#39;&#39;を入力値として用いたい場合は sub num{ my $num = shift; $num = -1 if not defined $num; # .... } Perl 5.10.0 以降なら sub num{ my $num =...</summary>
    <author>
        <name>dankogai [livedoor.com]</name>
        <uri>http://profile.livedoor.com/dankogai/</uri>
    </author>
    
    <category term="idiom" label="idiom" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://perl-mongers.org/">
        <![CDATA[<ul>
<li> <a href="http://blog.livedoor.jp/dankogai/archives/51074877.html">http://blog.livedoor.jp/dankogai/archives/51074877.html</a></li>
</ul>

<p>のダイジェスト。</p>

<h3> Scalarによるデフォルト値</h3>

<pre class="prettyprint">
sub num{
    my $num = shift || -1; 
    # ....
}</pre>

<p>0や&#39;&#39;を入力値として用いたい場合は</p>

<pre class="prettyprint">
sub num{
    my $num = shift;
    $num = -1 if not defined $num;
    # ....
}</pre>

<p>Perl 5.10.0 以降なら</p>

<pre class="prettyprint">
sub num{
    my $num = shift // -1;
    # ....
}</pre>

<h3> Hashによるデフォルト値</h3>

<p>以下で一発!</p>

<pre class="prettyprint">
sub conf{
    my %arg = (
        lang =&gt; &#39;perl&#39;,
        rank =&gt; 1,
        @_ # ここが決め手!           
    );
    # ...
}</pre>
<p>オブジェクトをnewしたいなら、以下がお手軽。</p>
<pre class="prettyprint">
package A::Module
sub new{
    my $pkg = shift;
    bless {
        lang =&gt; &#39;perl&#39;,
        rank =&gt; 1,
        @_
    }, ref $pkg || $pkg;
}</pre>

<p>Dan the Perl Monger</p>

]]>
        
    </content>
</entry>

<entry>
    <title>実用！ PerlでコマンドラインからTwitter投稿</title>
    <link rel="alternate" type="text/html" href="http://perl-mongers.org/2008/06/_perltwitter.html" />
    <id>tag:perl-mongers.org,2008://1.66</id>

    <published>2008-06-28T00:09:41Z</published>
    <updated>2008-06-28T00:34:46Z</updated>

    <summary><![CDATA[最近WindowsからLinuxへログインして作業していることが多いんですけれども、なんかつぶやきたくなったときにこんなの。Twitterにポスト。Net::Twitterモジュールを使います。 今回の流れは、 とりあえず投稿できるスクリプトを作ってみる コマンドラインから投稿できるものにグレードアップ となっています。 とりあえず投稿できるスクリプトを作ってみる まず、固定文字列だったらこんな感じで。「もへもへ」という文字列を投げます。username、passwordは自分のを使おう。 Filename:twit_test.pl　(UTF-8で) #!/usr/bin/perl use strict; use warnings; use Net::Twitter; my $twit = Net::Twitter-&gt;new( username =&gt; &#39;username&#39;, #ユーザー名 password =&gt; &#39;password&#39;, #パスワード ); $twit-&gt;update(&#39;もへもへ&#39;); 実行すると、Twitterに投稿されるはずです。文字化けしてたら、おそらく文字エンコーディングがUTF-8以外です。UTF-8で保存し直すか、Encodeモジュールで適切に変換してあげましょう。 コマンドラインから投稿できるものにグレードアップ 上のスクリプトを生かして、コマンドラインからの文字列を投稿するスクリプトに改造します。今回はタイプ量減らしたいので、コンソールがUTF-8の場合に限定。他の環境の場合、Encodeモジュールやらなにやら使用のこと。 Filename: twitter #!/usr/bin/perl use strict; use warnings; use...]]></summary>
    <author>
        <name>CL</name>
        <uri>http://blog.dtpwiki.jp/dtp/</uri>
    </author>
    
    <category term="nettwitter" label="Net::Twitter" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://perl-mongers.org/">
        <![CDATA[<p>最近WindowsからLinuxへログインして作業していることが多いんですけれども、なんかつぶやきたくなったときにこんなの。Twitterにポスト。Net::Twitterモジュールを使います。</p>
<p>今回の流れは、</p>
<ul><li>とりあえず投稿できるスクリプトを作ってみる</li>
<li>コマンドラインから投稿できるものにグレードアップ</li></ul>
<p>となっています。</p>
<h4>とりあえず投稿できるスクリプトを作ってみる</h4>
<p>まず、固定文字列だったらこんな感じで。「もへもへ」という文字列を投げます。username、passwordは自分のを使おう。</p>
<p>Filename:twit_test.pl　(UTF-8で)</p>
<pre class="prettyprint">
#!/usr/bin/perl
use strict;
use warnings;
use Net::Twitter;
my $twit = Net::Twitter-&gt;new(
  username =&gt; &#39;username&#39;,  #ユーザー名
  password =&gt; &#39;password&#39;,  #パスワード
);
$twit-&gt;update(&#39;もへもへ&#39;);</pre>

<p>実行すると、Twitterに投稿されるはずです。文字化けしてたら、おそらく文字エンコーディングがUTF-8以外です。UTF-8で保存し直すか、Encodeモジュールで適切に変換してあげましょう。</p>
<h4>コマンドラインから投稿できるものにグレードアップ</h4>
<p>上のスクリプトを生かして、コマンドラインからの文字列を投稿するスクリプトに改造します。今回はタイプ量減らしたいので、コンソールがUTF-8の場合に限定。他の環境の場合、Encodeモジュールやらなにやら使用のこと。</p>
<p>Filename: twitter</p>
<pre class="prettyprint">
#!/usr/bin/perl
use strict;
use warnings;
use Net::Twitter;
my $twit = Net::Twitter-&gt;new(
  username =&gt; &#39;username&#39;,  #ユーザー名
  password =&gt; &#39;password&#39;,  #パスワード
);
$twit-&gt;update($_) for @ARGV;</pre>

<p>上記twitterというファイルに実行権限を与えておいて、個人用実行ファイルを置くディレクトリ（$HOME/bin とかにpath通しておくと便利）に入れるとかしておくと、</p>
<pre>
$ twitter エロス</pre>

<p>とか</p>
<pre>
$ twitter &#39;エロス カワユス&#39;</pre>

<p>とかで投稿できます。</p>
<p><span class="mt-enclosure mt-enclosure-image" style="display: inline;"><img alt="net-twitter-post.jpg" class="mt-image-none" src="http://perl-mongers.org/net-twitter-post.jpg" style="" /></span></p>
<p>今回のスクリプトを改造して、定期的にビーコン打ち出すとか、作業が終わったらnotify出すとか応用できます。ちょっと考えたら、うちの業界のサーバには、製版が終わったらメールを送信する機能が付き始めていますが、こういうのもついていてもいいかとも思いました。</p>
<p>※調子こいて投稿しまくっていると連投制限に引っかかるみたいなので注意しましょう。</p>]]>
        
    </content>
</entry>

</feed>
