Perl Hackers Hub

第32回 新人さんのためのPerl入門(2)

この記事を読むのに必要な時間:およそ 5.5 分

前回の(1)こちらから。

Perlのコーディング規約

いざ学んだPerlをアウトプットしようとしたときには,Perlの自由な記述に戸惑うことがあるでしょう。ここではコーディングスタイルの一例として「Perl style guide」を,そしてコーディングをサポートするモジュールとしてPerl::CriticとPerl::Tidyを簡単に紹介します。

perlstyleでコーディングスタイルを参考にする

Perlのコードをどのように書くとよいのかの一例として,Perldoc内にPerl style guideという形で紹介されています。ターミナルからperldoc perlstyleで参照でき,インデントやスペースの置き方,ドキュメントの書き方の指南が提供されています。

perlstyle内でも書かれているように,次の2つは必ずコードの冒頭に書いてください。

use strict;
use warnings;

文法チェックと警告が有効になり,変数の宣言忘れやタイプミスなどについて警告を出してくれます。これらの警告を受け付けたくないときは,そのときだけ例外的にno strict,no warningsを使います。

Perl::CriticでPerlベストプラクティスに沿っているかを確認する

『Perlベストプラクティス』注1という書籍ではPerlのベストプラクティスを複数紹介しています。Perl::Criticは,Perlのコードがそのベストプラクティスに沿っているかをチェックしてくれます。インストールすると,perlctiricファイル名でチェックができます。ホームディレクトリ以下に作成される.perlcriticを編集することで,細かくルールを定義できます。

注1)
Damian Conway著/株式会社クイープ訳『Perlベストプラクティス』オライリー・ジャパン,2006年

Perl::Tidyでコードを整形する

Perl::Tidyは,ソースコードをルールに沿って整形してくれます。インストールすると,perltidy ファイル名で実行できます。たとえばperltidy -i=4 -nsfs ファイル名とすると,インデントは4スペースで,セミコロンの前のスペースが除去されて出力されます。Perl::Criticと同様に.perltidyrcにルールを定義しておくと便利です。

PerlでWebアクセスをする

Perlではモジュールを使いこなせば,巨大なWebシステムからコマンドラインツールまで簡単に実装できます。その中でもHTTP通信は,モジュールでとても簡単に実装できます。特にプログラミング初心者にとっては,実際にWebサイトやWeb APIから情報を取得することで,できることの幅が広げられるでしょう。PerlでHTTP通信をするためのモジュールでお勧めなのは,本節で紹介するLWP::UserAgentとFurlです。

LWP::UserAgentでHTTP通信をする

LWPはPerlでWebアクセスするための各種モジュールの集まりです。LWP::UserAgentはその中の一つで,ユーザエージェントを実装するクラスです。

リスト1はLWP::UserAgentを利用してWebページをダウンロードします。

リスト1 lwp.pl

1:  use LWP::UserAgent;
2: 
3:  my $ua = LWP::UserAgent->new(
4:     agent => "PerlHackersHub_32/1.0",
5:     timeout => 10,
6: );
7: my $url = "http://gihyo.jp/dev/serial/01/perl-hackers-hub";
8: my $res = $ua->get($url);
9: print $res->content;

モジュールは1行目のようにuseで指定して,3~6行目でLWP::UserAgentオブジェクトのインスタンスを作成し$uaに代入しています。4~5行目ではユーザエージェントとタイムアウトを指定しています。GETを使うために8行目ではアロー演算子を用いてgetメソッドを呼び出し,取得先を指定します。HTTP::Responceが返ってくるので変数$resに格納し,htmlを表示させたいので$res->contentのようにcontentメソッドを使い,printで表示させます。

実行すると図1のようにHTMLを取得できます。同様にしてステータスコードやヘッダも取得できるので,次のように出力を追加してみます。

print $res->code."\n";
print $res->message.'\n'; # 間違えた!
print $res->header('Content-Type')."\n";

図1 lwp.plの実行結果

$ perl lwp.pl
<!DOCTYPE html>
...
<head>
<meta http-equiv="Content-Type"
content="text/html; charset=UTF-8" />
<title>Perl Hackers Hub:連載 gihyo.jp … 技術評論社
(省略)

Perlでは文字列の連結に.を使うので,改行を表す\nをダブルクオーテーションで囲んだものと連結すると,出力時に1行ずつ改行されて表示されます。

\nをシングルクォーテーションで囲ってしまうと改行されずに\nをそのまま表示してしまうので,シングルクォーテーションとダブルクオーテーションの使い分けに注意してください。

また,print文ごとに\nを付けずに特殊変数$\\nを代入する方法もあります。

$\ = "\n";
print $res->code;

print文の文末には特殊変数$\も出力されているので,\nの代入によってprint文の文末に\nが自動で出力されます。$\の仕様はperldoc -v '$\'から,特殊変数の一覧はperldoc perlvarから参照できます。

より軽量なHTTPクライアントFurl

FurlはLWPに次いで有名なHTTP通信モジュールで,処理の速さが長所です。

Furlを使う場合もリスト2のようにLWP::UserAgentと似た感覚でHTTP通信ができます。LWPに慣れたらFurlを使うとよいでしょう。

リスト2 furl.pl

use Furl;

my $furl = Furl->new(
    agent => 'PerlHackersHub_32/1.0',
    timeout => 10,
);
my $url = 'http://gihyo.jp/dev/serial/01/perl-hackers-hub';
my $res = $furl->get($url);
print $res->content;

Benchmarkで簡易ベンチマーク

BenchmarkモジュールでCPU時間をもとにパフォーマンス比較が行えるので,LWP::UserAgentとFurlで比較してみましょう。

リスト3は,ローカルのHTTPサーバへLWP::UserAgentとFurlで1,000回ずつGETリクエストしたときの比較を,cmpthese関数で行っています。cmptheseでは図2のように結果を比較表にして,遅い順に出力します。Rateは1秒間の実行回数で表され,右に比較対象との比率を表しています。このようにベンチマーク上ではFurlのパフォーマンスが良いことがわかります。

リスト3 benchmark.pl

use Benchmark qw(cmpthese);
use LWP::UserAgent;
use Furl;

必ずローカル,または管理下のサーバを対象にすること
my $url = 'http://localhost:8000/index.html';

my $lwp = LWP::UserAgent->new(timeout => 10);
my $furl = Furl->new(timeout=>10);

cmpthese(
    1000, {
    lwp => sub { $lwp->get($url) },
    furl => sub { $furl->get($url) },
});

図2 benchmark.plの実行結果

$ perl bench_lwp_furl.pl
       Rate lwp furl
lwp 901/s -- -60%
furl 2273/s 152% --

なお,外部のサーバへこうした短時間の連続アクセスを送るのは迷惑行為となるので,自分の管理下にあるサーバを対象に実行してください。これはほかのWebアクセスするプログラムも同様です。

URL操作とパーセントエンコーディング

HTTP通信をする先のURLを1つの文字列変数で宣言して扱ってもよいのですが,マルチバイト文字や特殊文字のエスケープで問題が発生することがあるので,クエリ操作やURLエンコードの方法を知っておくと便利です。

URIモジュールを使うと,http://ja.wikipedia.org/w/api.php?action=query&prop=revisions&titles=AT%26T&rvprop=content&format=xmlのようなクエリ付きURLを手軽に作成できます。query_formでクエリを組み立てていくと,クエリパラメータが多く複雑なものでもわかりやすいコードになります。

リスト4はURIモジュールを使って,Wikipedia APIへの検索クエリを組み立てています。パラメータの値が自動でURLエンコードされるので,titlesの値であるAT&T&部分がパーセントエンコーディングされて&titles=AT%26Tのようになります。こうしないと&Tというパラメータが発生し,うまく取得できない場合が生じます。また,ホスト部分やパスだけを取得したり,変更したりもできます。

リスト4 uri.pl

use URI;

#Wikipedia API でAT&T について取得するクエリ
my $uri = URI->new('http://ja.wikipedia.org/w/api.php');
$uri->query_form(
    action => 'query',
    prop => 'revisions',
    titles => 'AT&T',
    rvprop => 'content',
    format => 'xml',
);

print $uri->host; # ja.wikipedia.org
print $uri->path; # /w/api.php
print $uri->as_string;
# http://ja.wikipedia.org/w/api.php?action=query&prop..

なお,速度を重視してURLエンコードだけ必要なプログラムを作りたい場合は,高機能なぶん重いURIモジュールを使うよりも,URLエンコードに特化したモジュールであるURI::Escape::XSやURL::Encode::XSを使うほうが良いこともあるので参考にしてください。

著者プロフィール

hiroki.o

1989年,静岡県生まれ。2014年に大学院修了後,新卒で某企業に入社しプログラマになり本格的にPerlを学びながら業務でWebアプリケーションの開発などに携わっている。

コメント

コメントの記入