#!/usr/bin/perl # crossreviewから自分のレビューを読み込んで、 # metaWeblog API経由でブログのエントリにするスクリプト use strict; use encoding "utf-8"; use Encode; use LWP::UserAgent; use XML::Simple; use XMLRPC::Lite; use Data::Dumper; use CGI qw/:standard :no_xhtml/; use IO::File; use Time::Local; # 使い方: # 1. このスクリプトを適当な名前に変えて適当なディレクトリに設置 # 2. 「crossreviewのアカウント」「WordPressの設定」「Amazon」を書き換える # 3. スクリプトを設置したディレクトリに cache ディレクトリを作成 # 4. CRONで定期的に実行するか、反映したい時に手作業で実行 # (現在はCGIとして動作する作りになっています) # このスクリプトの実行には、 # LWP::UserAgent, XML::Simple, SOAP::Lite, XMLRPC::Lite のモジュールが必要です。 # また、Amazon Web Servicesのデベロッパートークンも必要です。 # 出力をいじりたい時は、142~150行あたりをいじって下さい。 # このスクリプトをWordPressに対して実行したい場合、事前に以下のURLに書いたxmlrpc.phpの修正を適応して下さい。 # http://fukaz55.main.jp/archives/205 # WordPressでmetaWeblog.newPostに日付を渡して叩くと正常に動作しない件 # このスクリプトを使って生じた不利益に関しては、私は責任は取れません(念のため)。 # 何かありましたら、tsuyoshi.fukazawa@gmail.comまでお願いします。 # --------------------------------------------------------------------- # crossreviewのアカウント my $id = 'アカウントID'; # WordPressの設定 my $APPKEY = 'WordPress'; my $RPCURL = 'http://あなたのサイト/xmlrpc.php'; # metaWeblog APIのエントリポイント my $BLOGID = '0'; my $USERNAME = 'ユーザー名'; my $PASSWORD = 'パスワード'; my $ENCODE = 'utf-8'; # ブログの文字コード # Amazon my $asoid = "fukaz55-22"; # AmazonアソシエイトID my $devkey = "あなたのデベロッパートークン"; # デベロッパートークン # UserAgent my $ua; # レビュー my %items; # 保存するファイル名 my $cachedir = "cache"; # キャッシュを保存するディレクトリ my $ITEM_DUMP = "$cachedir/crossreview.dmp"; # ファイルハンドル my $fh = IO::File->new; # --------------------------------------------------------------------- print header(-type => 'text/html', -charset => 'UTF-8'); # 前回までの結果を読み込み if ($fh->open($ITEM_DUMP, 'r')) { my $data = join('', $fh->getlines()); $fh->close; my $VAR1; # Data::Dumperで生成した変数名の定義 %items = %{eval($data)}; } # RSSを取得 $ua = LWP::UserAgent->new; my $url = "http://crossreview.jp/$id/archive.xml"; my $res = $ua->get($url); die if (!$res->is_success); # XMLを解析 my $parser = XML::Simple->new; my $xml = $parser->XMLin($res->content); # レビューアイテムを取得 my @newiems = (); foreach my $item (@{$xml->{channel}->{item}}) { my $guid = $item->{guid}->{content}; # 新規レビュー? if (!defined($items{$guid})) { $item->{entry_id} = 0; push @newiems, $item; } else { # 既存レビューの修正? if ($items{$guid}->{description} ne $item->{description}) { $item->{entry_id} = $items{$guid}->{entry_id}; push @newiems, $item; } } } # エントリに追加 foreach my $item (@newiems) { # Amazonから情報を取得 $item->{link} =~ /reviews\/([0-9A-Z]{10})$/; # リンクの末尾にある英数字がASIN my $asin = $1; my $detail = getAmazonCommodity($asin); # 情報を取得 my $title = $detail->{ItemAttributes}->{Title}; my $this_imageurl = defined($detail->{MediumImage}->{URL}) ? $detail->{MediumImage}->{URL} : "noimage.jpg"; # 適当なnoimage画像を用意して下さい my $link = "http://crossreview.jp/amazon/asin/$asin?name=$id"; my $manufacturer = $detail->{ItemAttributes}->{Manufacturer}; my $price = $detail->{OfferSummary}->{LowestNewPrice}->{FormattedPrice}; my $author = ''; my $author_ref = $detail->{ItemAttributes}->{Author}; if ($detail->{ItemAttributes}->{Artist}) { $author_ref = $detail->{ItemAttributes}->{Artist}; } $author = $author_ref; if (ref($author_ref) eq 'ARRAY') { $author = join(' ', @{$author_ref}); } my $releaseDate = ''; if ($detail->{ItemAttributes}->{PublicationDate}) { $releaseDate = $detail->{ItemAttributes}->{PublicationDate}; } if ($detail->{ItemAttributes}->{ReleaseDate}) { $releaseDate = $detail->{ItemAttributes}->{ReleaseDate}; } my ($utime, $year, $month, $day, $hour, $min, $sec) = parsePubDate($item->{pubDate}); my $posted = sprintf("%04d-%02d-%02d %02d:%02d", $year, $month, $day, $hour, $min); # レーティング部分を切り分ける my $description = $item->{description}; $description =~ /^rating:([0-9]+)\s/; my $rating = $1; $description =~ s/^rating:[0-9]+\s+(.+)$/$1/m; # 記事を生成 my $content =<
$title
$author ($manufacturer) / $price
$description [$rating]
$posted | Permalink
CONTENT # WordPressに投稿 (metaWeblog) ($sec, $min, $hour, $day, $month, $year) = gmtime($utime); # GMTにする my $content_st = { 'title' => encode($ENCODE, "[crossreview]$title"), 'description' => encode($ENCODE, $content), 'dateCreated' => sprintf("%04d%02d%02dT%02d:%02d:%02d+00:00", $year + 1900, $month + 1, $day, $hour, $min, $sec), 'categories' => ('Review'), }; my $s = XMLRPC::Lite->proxy($RPCURL); my $ret; if (!$item->{entry_id}) { # 新規 $ret = $s->call('metaWeblog.newPost', $BLOGID, $USERNAME, $PASSWORD, $content_st, 1)->result; $item->{entry_id} = $ret; # 復帰値はエントリID } else { # 修正 $ret = $s->call('metaWeblog.editPost', $item->{entry_id}, $USERNAME, $PASSWORD, $content_st, 1)->result; } # 記事を記録する my $guid = $item->{guid}->{content}; $items{$guid} = $item; } # レビューを保存 if ($fh->open($ITEM_DUMP, 'w')) { $fh->print(Dumper(\%items)); $fh->close; } print h1("DONE."), end_html; # --------------------------------------------------------------------- # pubDataを解析して日本時刻に変換 sub parsePubDate { my $pattern = '(Mon|Tue|Wed|Thu|Fri|Sat|Sun) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) (\d{1,2}) (\d{2}):(\d{2}):(\d{2}) ([+-]\d{4}) (\d{4})'; my %monthes = qw(Jan 1 Feb 2 Mar 3 Apr 4 May 5 Jun 6 Jul 7 Aug 8 Sep 9 Oct 10 Nov 11 Dec 12); my $pubdate = shift; # pubDateを解析 if ($pubdate =~ /$pattern/) { my ($week, $month, $day, $hour, $min, $sec, $timezone, $year) = ($1, $2, $3, $4, $5, $6, $7, $8); $month = $monthes{$month}; # 日本時刻に変換 my $utime = timelocal($sec, $min, $hour, $day, $month - 1, $year); ($sec, $min, $hour, $day, $month, $year) = localtime($utime); return ($utime, $year + 1900, $month + 1, $day, $hour, $min, $sec); } else { return (0, 1970, 1, 1, 0, 0, 0); } } # --------------------------------------------------------------------- # ASINからAmazon商品情報を取得 sub getAmazonCommodity { my $asin = shift; my $url = "http://webservices.amazon.co.jp/onca/xml?Service=AWSECommerceService&SubscriptionId=$devkey&AssociateTag=$asoid&Operation=ItemLookup&ItemId=$asin&ResponseGroup=Medium"; # 取り込む my $res = $ua->get($url); return undef if (!$res->is_success); # XMLを読み込んで解析 my $parser = XML::Simple->new; my $xml = $parser->XMLin($res->content); return $xml->{Items}->{Item}; }