Perl入門ゼミ

テキスト処理、Linuxサーバー管理、Web開発ならPerl
  1. Perl
  2. 日付・時刻

Google Calendar Data API で祝日を取得する

祝日というのは人間が決めたものなので非常に扱いにくいものです。春分、秋分という前年の2月に決まる祝日や、振替休日などもあります。

今回のサンプルではGoogleがGoogle Calendar Data APIで提供してくれている日本の祝日のデータを取得することにします。

あくまでGoogleが調べた日本の休日のデータなので絶対的な信頼性はありません。Googleが間違っていれば間違った祝日のデータを取得しますので、日付の間違いが損害を及ぼすようなアプリケーションにそのまま使用してはいけません。かならず他の手段で正しいことを確かめるようにします。

use strict;
use warnings;

# Web上から情報を取得するのでHTTPクライアントを使用する。
use LWP::UserAgent;

#フィードがXMLで与えられるのでXML::Simpleで解析。
use XML::Simple;

# Google Calendar Data API のURL( 日本の祝日を取得するためのURL )
my $feed_base
  = 'http://www.google.com/calendar/feeds/japanese@holiday.calendar.google.com/public/full';

# この日を含む開始日
my $start_date = '2007-01-01';

# この日を含まない終了日
my $end_date = '2008-01-01';

# フィードの最大取得件数
my $max_results = 100;

my $query = "start-min=${start_date}&start-max=${end_date}&max-results=${max_results}";

my $feed_url = $feed_base . '?' . $query;

# WebからXMLを取得
my $http_client = LWP::UserAgent->new;
my $response = $http_client->get($feed_url);

my $holidays_xml;
if ($response->is_success) {
  $holidays_xml = $response->content;
}
else {
  die "フィードの取得に失敗しました。";
}

# XMLを解析
my $xml_parser = XML::Simple->new;
# XML::SAXがない人のためパーサを変更
$XML::Simple::PREFERRED_PARSER = 'XML::Parser'; 
my $holidays_data = $xml_parser->XMLin($holidays_xml);

my $holidays = [];
for my $key (keys %{$holidays_data->{'entry'}}) {
  my $holiday_day = $holidays_data->{entry}{$key}{'gd:when'}{startTime};
  my $holiday_name = $holidays_data->{entry}{$key}{title}{content};
  push @$holidays, {day => $holiday_day, name => $holiday_name};
}

# 文字コードがPerlの内部表現( UTF8 )になっているのでお好みに応じてエンコード
use Encode;
my $encode_to;
if ($^O eq 'MSWin32') {
  $encode_to = 'shift-jis';
}
else {
  $encode_to = 'utf8';
}

# データすべてをエンコード
for my $holiday (@$holidays) {
  for my $key (keys %$holiday) {
    $holiday->{$key} = encode($encode_to, $holiday->{$key});
  }
}

use Data::Dumper;
print Data::Dumper->Dump([$holidays], ['*holidays']);

祝日の問題

祝日は国によってことなります。また祝日が決まっても振り替え休日で休日が変化することもあります。春分や秋分などのように政府が前年の2月に正式な祝日の日を決定するものもあります。

Google Calender Data API

Google Calender Data API を使用すると、国民の休日を取得することができます。振替休日も考慮されています。信頼性はGoogleの信頼性によります。

コード解説

Google Calender Data API

以下のURLがGoogle Calender Data API の祝日取得のためのURLです。

my $feed_base
  = 'http://www.google.com/calendar/feeds/japanese@holiday.calendar.google.com/public/full';

クエリ文字列の作成

上記の元になるURLに条件を指定したクエリ文字列を連結します。指定する日付は開始日を含み、終了日を含まないものになります。

# この日を含む開始日
my $start_date = '2007-01-01';

# この日を含まない終了日
my $end_date = '2008-01-01';

# フィードの最大取得件数
my $max_results = 100;

my $query = "start-min=${start_date}&start-max=${end_date}&max-results=${max_results}";
my $feed_url = $feed_base . '?' . $query;

このサンプルでは以下のURLを作成しています。

 [http://www.google.com/calendar/feeds/japanese@holiday.calendar.google.com/public/full?start-min=2007-01-01&start-max=2008-01-01&max-results=100]

あとは上記URLの情報をWebから取得して、XMLデータなのでこれを解析して使いやすい形にして、OSに応じて文字コードをエンコードします。

WebからXMLデータを取得する。

LWP::UserAgentは、HTTPクライアントを作成するためのモジュールです。Webブラウザがやっていることをプログラム上で行えます。

use LWP::UserAgent;
my $http_client = LWP::UserAgent->new;
my $response = $http_client->get($feed_url);

my $holidays_xml;
if ($response->is_success) {
  $holidays_xml = $response->content;
}
else {
  die "フィードの取得に失敗しました。";
}

XMLを解析して使いやすいデータにする。

XMLを解析するにはXML::Simpleを使用します。XML::SimpleはXMLデータをPerlのデータ(ハッシュ、配列)に変換するためのモジュールです。

use XML::Simple;

# XMLを解析
my $xml_parser = XML::Simple->new();
$XML::Simple::PREFERRED_PARSER = 'XML::Parser';
my $holidays_data = $xml_parser->XMLin( $holidays_xml );

my $holidays = [];
for my $key (keys %{$holidays_data->{'entry'}}) {
  my $holiday_day = $holidays_data->{entry}{$key}{'gd:when'}{startTime};
  my $holiday_name = $holidays_data->{entry}{$key}{title}{content};
  push @$holidays, {day => $holiday_day, name => $holiday_name};
}

XML変換後はデータに以下のようにしてアクセスできます。

# 祝日の日付
$holidays_data->{'entry'}{識別子となるURL}{'gd:when'}{startTime};

# 祝日の名前
$holidays_data->{entry}{識別子となるURL}{title}{content};

文字コードを変換する

Webから受け取ったXMLの文字コードはUTF-8です。XML::SimpleがXMLをPerlのデータに変換した時点で、文字はPerlの内部表現( UTF-8 )に変換されます。

これを正しく出力するためには、Perlの内部表現から適切な文字コードにエンコードする必要があります。

(出力する文字列がたとえUTF-8であろうともエンコードは必要です。内部表現UTF-8から外部表現UTF-8に変換すると考えると理解しやすいです。公式には「UTF-8フラグを落とす」といいますがわかりにくい)

use Encode;
my $encode_to;
if ($^O eq 'MSWin32') {
  $encode_to = 'shift-jis';
}
else {
  $encode_to = 'utf8';
}

# データすべてをエンコード
for my $holiday (@$holidays) {
  for my $key (keys %$holiday){
    $holiday->{$key} = encode($encode_to, $holiday->{$key});
  }
}
  • Perlとはテキスト処理の記述性とパフォーマンスに優れ、正規表現が言語に組み込まれているプログラミング言語です。
  • Linuxサーバーでのフィルタリングプログラム、複数行の文字列を処理、ファイル内容の検索・置換などが得意
  • Perlはgitopensslなど広く普及したUnix/Linuxミドルウェアの補助ツールとして採用実績あり。後方互換性とポータビリティの高さがひとつの理由と推測。
  • 大量のテキストを扱うWeb開発も得意。ロングテールSEOを意識したWebサイト、アドテクやソーシャルゲームでの50ms以内のJSONの生成など。