0

相対パスを絶対パスに変更する

LWP等で取得してきたコンテンツをごにょごにょしようとしてもリンク先が相対パスだったら画像等がリンク切れで非常に扱いにくい。
後にその画像だけを取得したい時等。

これがすべて下記のように変換されていると何かと便利
<img src="../../header.gif" />

<img src="http://japan.cnet.com/news/header.gif" />

URIモジュールを使うのその変換を数行のコードでやってくれます。

#!/usr/bin/perl -w
 
use strict;
use warnings;
use utf8;
use LWP;
 
 
my $link = 'http://japan.cnet.com/news/business/story/0,3800104746,20416479-0,00.htm';
 
my $ua = LWP::UserAgent->new;
my $res = $ua->get($link);
 
my $content = $res->content;
 
$content =~ s/href=("|')(\S*)("|')/&change_path($1, $2, $3, $link, 'href=')/gei;
$content =~ s/src=("|')(\S*)("|')/&change_path($1, $2, $3, $link, 'src=')/gei;
 
print $content;
 
sub change_path {
my ($pre, $path, $sur, $link, $element) = @_;
my $uri = URI->new_abs($path, $link);
 
return $element . $pre . $uri . $sur;
}

これで取得したコンテンツのリンクはすべて絶対パスに変わります。
正規表現駆使してやらずともできるのはうれしい。

0

HTML::Featureのユーザーエージェントが設定できない件

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

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

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

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

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

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

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

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

0

Perl 5.8.xのUTF8フラグ

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

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

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

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

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

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

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

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

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

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

0

perlでMeCabを使う

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

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

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

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

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

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

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

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

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