Google ReaderからInstaPaperにポスト

Google Readerで、スターをつけた記事をInsta Paperに登録してくれる、InstaReaderというサービスがあるのを知った。

お、これはいいね、と思ったが、Sign Upが必要とか(あたりまえ)。えええ、めんどくさい。

30秒ぐらいぐぐってみると、Insta PaperのAPIって単になげるだけじゃん。Google ReaderのスターってRSSじゃん。というわけで、作ってみた。


実行にはfeedparserが必要です。なお、LDRのpinをInstapaperにポストするpythonスクリプトをかなり参考にさせていただきました。ありがとうございます。

#! /usr/bin/env python
# coding: utf-8

import json
import urllib
import sys, os
import yaml

import feedparser

CONF_FILENAME="conf.yaml"
HIST_FILENAME="hist.yaml"

def conf(service):
  f = os.path.abspath(os.path.dirname(__file__)) + "/" + CONF_FILENAME
  return yaml.load(open(f))[service]

def hist():
  '''
  hist_list はキー link, title, date を含む辞書のリスト
  dateの形式は、ISO 8601 (YYYY-MM-DD)で、
  entryの日付ではなく、instapaperに登録した日付
  hist_list = [{'link': 'http://...', 'title': '...', 'date': '...'},
  {...}, ]
  '''
  f = os.path.abspath(os.path.dirname(__file__)) + "/" + HIST_FILENAME
  if os.path.exists(f):
    return yaml.load(open(f))
  else:
    return []

def append_hist(hist_list):

  f = os.path.abspath(os.path.dirname(__file__)) + "/" + HIST_FILENAME
  fp = open(f,"a")

  output = yaml.dump(hist_list)
  fp.write(output)
  fp.close()

def get_star_entry(hist_list, rssurl):
  try:
    fdp = feedparser.parse(rssurl)
  except:
    print "(Error) can not get the RSS..."
    sys.exit(1)

  hist_link_list = []
  for h in hist_list:
    hist_link_list.append(h["link"])

  entry_list = []
  for entry in fdp['entries']:
    title = ""
    link = ""

    if ( "title" in entry ):
      title = entry.title
    if ( "link" in entry ):
      link = entry.link

    if (link in hist_link_list):
      next
    else:
      entry_list.append({'title':title, 'link': link})
  return entry_list


def add_to_instapaper(entry_list, username, password):
  '''
  entry_list はキー link, title を含む辞書のリスト
  entry_list = [{'link': 'http://...', 'title': '...'}, {...}, ...]
  戻り値はURLとレスポンスコードの辞書
  '''
  from datetime import datetime

  d_str = datetime.now().isoformat()
  INSTAPAPER_API_URL = 'https://www.instapaper.com/api/add'

  pd = {'username':username, 'password':password}
  result_list = []
  for entry in entry_list:
    result = {}
    pd['url'] = entry['link']
    pd['title'] = entry['title'].encode('UTF-8')
    params = urllib.urlencode(pd)
    response = urllib.urlopen(INSTAPAPER_API_URL, params)
    if (response.code != 200):
      next
    result['code'] = response.code
    result['link'] = pd['url']
    result['title'] = pd['title']
    result['date'] = d_str
    result_list.append(result)
  return result_list

if __name__ == '__main__':
  # 過去のPost履歴を取得
  hist_list = hist()

  # Star一覧を取得
  rssurl = conf("googlereader")["url"]
  entries = get_star_entry(hist_list, rssurl)
  
  # Instapaperにpost
  ipac = conf("instapaper")
  result = add_to_instapaper(entries, ipac['username'],
  ipac['password'])
  if result:
    append_hist(result)

これを、例えば instaAdd.py というファイルに保存してください。
さらに同じディレクトリに conf.yaml というファイルを作り、

googlereader:
  url:
  http://www.google.com/reader/public/atom/user/******/state/com.google/starred
instapaper:
  username: *****
  password: *****

と、情報を記入してください。GoogleReaderのURLは、設定->リーダー設定->フォルダとタグ で、「スター付きアイテム」を公開にし「公開ページを見る」のURLを記入してください。

あとはこれをcronで回せばおーけーです。

動作

投稿したエントリは、 hist.yaml というファイルに追記されます。このファイルを元にエントリの重複をチェックしています。このファイルが膨大な大きさになると動作速度に影響が出ることは考えられますが、数万エントリ程度ならば問題ないと思います。