読者です 読者をやめる 読者になる 読者になる

ゆーすけべー日記

はてなBlogってどーなの!?

DMMのWeb APIに今更気づいたので...

Perl Technologies DMM

ムフフなビデオも網羅的に扱うDVDや動画の提供サービス「DMM」のWeb APIがいつの間にか公開していたらしく、なにぶんノーマークだったもので昨日の夜知ってビックリした。というかDMMは一生API出さないだろうなんて決め込んでいたのが良くなかったですね。

スクリーンショット 2013-05-14 8.21.38.png

ってことでとあるAV女優の商品一覧を出力するようなスクリプトを書いてみました。API固有の「癖」でいくつか実装する際の注意すべきポイントがあるのでそれをまず紹介します。Perlコードですが参考になるかもです。

リクエストパラメータにはタイムスタンプがいる

リクエストのパラメータにはタイムスタンプが必須です。形式は

2013-05-14 08:03:16

というもの。僕はDateTime派なので、以下のコードで現在のタイムスタンプの文字列をつくっています(*ある方から指摘を受けてコードを修正させていただきました!)。

use DateTime;
my $timestamp = DateTime->now( time_zone => 'Asia/Tokyo' )->strftime('%F %T');
print "$timestamp\n";

この文字列は後でAPIにリクエストを送る時に使います。

リクエストパラメータはeuc-jpでエスケープさせる

イマドキじゃない!?リクエストのパラメータはeuc-jpでエスケープさせることが必要なのです。通常のutf-8でエスケープさせたパラメータ値を含むURLを構築するにはURIモジュールの「query_form」メソッドが重宝するのですが、今回の場合はURIモジュール使わない方がいい?ってことでハッシュでつくったパラメータのキーとバリューの組み合わせを、URLに落とし込むには以下のコードを記述しました。

use URI::Escape qw/uri_escape/;
use Encode;
use utf8;

my $params = {
    key1 => '値その1',
    key2 => '値その2'
};
my $url = 'http://affiliate-api.dmm.com';
my $queries;
for my $key ( keys %$params ) {
    my $value = uri_escape( encode( 'euc-jp', $params->{$key} ) );
    push @$queries, "$key=$value";
}
$url .= '?' . join '&', @$queries;
print "$url\n";

返却されるXMLもeuc-jp

レスポンスとして返されるXMLもeuc-jpな作りになっております。とりあえず簡単にXML::SimpleでPerlのデータ構造へパースする場合この文字コードの関係で細工がいります。「$url」変数に正しいリクエストURLがあるとした場合のコード。

use LWP::UserAgent;
use XML::Simple qw//;
use YAML;

my $ua = LWP::UserAgent->new;
my $res = $ua->get($url);
die $res->status_line if $res->is_error;
my $content = encode('utf-8',$res->content);
$content =~ s!euc-jp!utf-8!i;
my $xs = XML::Simple->new();
my $data = $xs->XMLin($content);

print Dump $data;

XMLの先頭にある、コイツ

<?xml version="1.0" encoding="euc-jp"?>

のencodingの値として「euc-jp」になっているのでそのままだとXML::Simple、もしくはXML::Simpleで使用しているモジュールがXMLの文字列はutf-8なのに強制的に「euc-jp」で解釈してしまう。なので「$content =~ s!euc-jp!utf-8!i」として強引に置換をかましています。

完成したスクリプト

use strict;
use warnings;
use LWP::UserAgent;
use URI::Escape qw/uri_escape/;
use DateTime;
use Encode;
use XML::Simple qw//;
use utf8;

my $timestamp = DateTime->now( time_zone => 'Asia/Tokyo' )->strftime('%F %T');
my $params = {
    api_id       => 'your_api_id',
    affiliate_id => 'your_affiliate_id',
    operation    => 'ItemList',
    version      => '2.00',
    timestamp    => $timestamp,
    site         => 'DMM.co.jp',
    service      => 'digital',
    floor        => 'videoa',
    sort         => 'review',
    keyword      => '成瀬心美',
    hits         => 20,
};
my $url = 'http://affiliate-api.dmm.com';
my $queries;

for my $key ( keys %$params ) {
    my $value = uri_escape( encode( 'euc-jp', $params->{$key} ) );
    push @$queries, "$key=$value";
}
$url .= '?' . join '&', @$queries;

my $ua  = LWP::UserAgent->new;
my $res = $ua->get($url);
die $res->status_line if $res->is_error;
my $content = encode( 'utf-8', $res->decoded_content );
$content =~ s!euc-jp!utf-8!i;
my $xs   = XML::Simple->new();
my $data = $xs->XMLin($content);

for my $item ( @{ $data->{result}{items}{item} } ) {
    print encode_utf8( $item->{title} ) . "\n";
}

これを実行すると...

スクリーンショット 2013-05-14 8.26.57.png

出来ましたね。検証するために急いでつくったのでまだ楽な方法があるかもなんで、その場合はご教授いただければ幸い! ちなみに、僕がつくった18禁のエロサイトではもう既にこのAPIを利用して、動画に出演している女優さんにマッチしたDMMの動画パッケージが出るようにしてみてます!