Google Reader API
Google ReaderのAPIの仕様は非公開ですが、個人的に解析されている方もいて、少ないながら資料もあるので、使ってみました。
目的
ニュースサイトのRSSをGoogle Readerに登録して使っています。
カテゴリごとにフィードがあるのですが、複数のカテゴリに属している記事は、複数のフィードに重複して含まれることになります。
それらの重複記事を事前にフィルタし、既読状態にすることが目的です。
あえて載せていませんが、広告などの不要記事を既読にするといった使い方もできます。
手順
- 認証
- トークン取得
- 記事リスト(reading list)取得
- 指定記事を既読にする
1. 認証
# リクエスト設定 my %req = ( service => 'reader', Email => $email, Passwd => $password, source => 'test_reader', continue => 'http://www.google.com/', ); # 認証URI に POST my $ua = LWP::UserAgent->new; my $res = $ua->post('https://www.google.com/accounts/ClientLogin', \%req); die $res->status_line if $res->is_error; # 受け取ったパラメータを次回以降のリクエストのヘッダに設定 my $content = $res->content; my ($auth) = $content =~ /Auth=(.+?)\n/; $ua->default_header( 'Authorization' => "GoogleLogin auth=$auth" ); my ($sid) = $content =~ /SID=(.+?)\n/; $ua->default_header( 'Cookie' => "SID=$sid" );
2. トークン取得
# トークン取得URI に GET $res = $ua->get('http://www.google.com/reader/api/0/token'); die $res->status_line if $res->is_error; # 受け取ったパラメータを保持 $content = $res->content; my ($token) = $content =~ m!//(.+?)$!;
3. 記事リスト(reading list)取得
my $continuation = ""; my $loops = 0; while ($loops++ < 100) { # 大量のリストを要求するので、少し間をあける sleep 1; # entry のリストを要求する。 # 前回の続きを要求するときは、前回の continuation (/feed/gr:continuation/text()) を # クエリ文字列に設定してリクエストする。 $res = $ua->get('http://www.google.com/reader/atom/user/-/state/com.google/reading-list' . '?c=' . uri_escape($continuation)); die $res->status_line if $res->is_error; $content = $res->content; # feed を XML パーサで解析する。 my $feed = XMLin($content, ForceArray => ['entry', 'category'], KeyAttr => [], ForceContent => 1); ... # 続きを要求するために、continuation を保存 if ($feed->{'gr:continuation'}{content}) { $continuation = $feed->{'gr:continuation'}{content}; } else { last; } }
4. 指定記事を既読にする
- 記事エントリには「ID」が付けられており、記事に対する操作を行うときは、対象記事のIDを指定します。
- 記事エントリには、0個以上のラベルおよびステートが付けられています。エントリに既読ステートを追加することにより、その記事を既読状態にすることができます。
- 記事エントリに付けられたラベルにより、フィードが属するフォルダを判別することもできます。以下の例では、「news」フォルダ以外の記事は処理しないようにしています。
# <entry> を全部処理 entries: foreach my $entry (@{$feed->{entry}}) { my $isnews = 0; # <entry> 内の <category> を全部処理 foreach my $cat (@{$entry->{category}}) { if ($cat->{term}) { if ($cat->{term} =~ m!/state/com.google/read$!) { # 既読アイテム next entries; } elsif ($cat->{term} =~ m!/label/news$!) { # news フォルダのアイテム $isnews = 1; } } } next if !$isnews; # <entry> 直下の <title> のテキストを取得 my $title; if ($entry->{title} && $entry->{title}{content}) { $title = $entry->{title}{content}; } else { next; } my $ismulti = 0; # title/text() が重複する news アイテムは、既読にする。 # title/text() を %entrytitles に登録していくことで、重複を検知する。 if ($entrytitles{$title}) { $entrytitles{$title}++; $ismulti = 1; } else { $entrytitles{$title} = 1; } if ($ismulti) { # 指定アイテムを既読にする my %req = ( i => $entry->{id}{content}, a => 'user/-/state/com.google/read', T => $token, ); $res = $ua->post('http://www.google.com/reader/api/0/edit-tag', \%req); } }
ちょっとメモ
全然関係ないですが、RubyでSSL接続する際のサーバ証明書についてです。
「IEでGoogleのログインページに行き、証明書をエクスポートする」と解説されているサイトが多かったのですが、これではなぜかRubyがエラーを返してきてしまい、うまくいきませんでした。
もしかすると、エクスポートする際のオプションが間違っていたのかもしれません。
試しにFirefoxでエクスポートした証明書を使ってみたら、問題なく動いたので、それ以上は調べていません。
参考にしたサイト
- GoogleReaderAPI - pyrfeed
- リファレンス形式でわかりやすくまとめられています。少し古いためか、一部、実際と異なる箇所がありました。
- Google Reader APIの認証がまた変わった? - イントレ。
- 認証方法について、参考にさせていただきました。