将 Google Reader 的加星条目导出到 Pocket

标签:Python, Google Reader

鉴于 Google Reader 即将关闭,而我没找到好的替代品,所以急需导出几千条加星条目。
前几天测试了下把知乎日报分享到 Pocket,看上去体验还不错,于是决定先保存到 Pocket 吧。

因为没多少时间来写,我就简要说明下原理吧,其他的自己看代码吧。
步骤如下:
  1. 获取 Pocket 授权
    1. 创建一个 Pocket 应用。Permissions 全选(反正是给自己用),Platforms 选择 Web。创建完拿到该应用的 CONSUMER KEY。
    2. 用 consumer key 从 https://getpocket.com/v3/oauth/request 获取 request token。如果你想做 Web 应用的话,选个正确的 redirect_uri,否则乱写一个网址也行。
    3. 拿到 request token 后,打开浏览器,访问 https://getpocket.com/auth/authorize?request_token=YOUR_REQUEST_TOKEN&redirect_uri=YOUR_REDIRECT_URI。登录后选择 authorize。注意 Python 2.7 的 webbrowser 打开 Chrome 有 bug,所以我优先选择了 Safari 和 Firefox,实在不行就手动复制粘贴网址吧。
    4. 回到程序来,敲下回车,让程序继续运行。这时,程序会当成这个 request token 已经被用户授权了。如果是 Web 应用的话,自己处理下回掉地址,识别下是哪个用户吧。
    5. 用 consumer key 和 request token 从 https://getpocket.com/v3/oauth/authorize 获取 access token。
  2. 获取 Google Reader 授权
  3. 遍历获取 Google Reader 的加星条目。注意每次最多获取 1000 条。
  4. 获取加星条目的 URL,生成要导入的请求数据。
  5. 用 consumer key 和 access token 往 https://getpocket.com/v3/send 发送导入请求。

为了方便测试,我加入了 empty_pocket_items() 函数,请谨慎使用。

最后,代码如下:
import logging
logging.basicConfig(level=logging.INFO)

from urllib import urlencode
from urllib2 import urlopen, Request
from urlparse import parse_qs
import webbrowser

try:
    import ujson as json
except ImportError:
    import json


GOOGLE_EMAIL = ''  # your google account email address
GOOGLE_PASSWORD = ''  # your google account password
POCKET_CONSUMER_KEY = ''  # you can create one from http://getpocket.com/developer/apps/new

GOOGLE_LOGIN_URL = 'https://www.google.com/accounts/ClientLogin'
GOOGLE_STAR_URL = 'https://www.google.com/reader/api/0/stream/contents/user/-/state/com.google/starred?n=1000'
POCKET_OAUTH_REQUEST_URL = 'https://getpocket.com/v3/oauth/request'
POCKET_OAUTH_AUTHORIZE_URL = 'https://getpocket.com/v3/oauth/authorize'
POCKET_AUTHORIZE_URL = 'https://getpocket.com/auth/authorize?request_token=%s&redirect_uri=https://getpocket.com/'
POCKET_GET_URL = 'https://getpocket.com/v3/get'
POCKET_MODIFY_URL = 'https://getpocket.com/v3/send'


def get_pocket_request_token():
    f = urlopen(POCKET_OAUTH_REQUEST_URL, urlencode({
        'consumer_key': POCKET_CONSUMER_KEY,
        'redirect_uri': 'https://getpocket.com/'
    }))
    request_token = f.read()[5:]

    try:
        browser = webbrowser.get('safari')
    except webbrowser.Error:
        try:
            browser = webbrowser.get('firefox')
        except:
            browser = webbrowser  # may not work with Chrome / Opera
    pocket_authorize_url = POCKET_AUTHORIZE_URL % request_token
    browser.open_new_tab(pocket_authorize_url)

    raw_input('Please open "%s" and press Enter key after authorized.' % pocket_authorize_url)
    return request_token


def get_pocket_access_token(request_token):
    f = urlopen(POCKET_OAUTH_AUTHORIZE_URL, urlencode({
        'consumer_key': POCKET_CONSUMER_KEY,
        'code': request_token
    }))
    data = parse_qs(f.read())
    return data['access_token'][0]


def send_pocket_request(access_token, actions):
    f = urlopen(POCKET_MODIFY_URL, urlencode({
        'consumer_key': POCKET_CONSUMER_KEY,
        'access_token': access_token,
        'actions': actions
    }))

    result = json.loads(f.read())
    if result['status'] != 1:
        logging.error('Failed to send pocket request.')


def get_pocket_items(access_token, count=1000, detail_type='simple'):
    POCKET_GET_URL
    parameters = {
        'consumer_key': POCKET_CONSUMER_KEY,
        'access_token': access_token
    }
    if count:
        parameters['count'] = count
    if detail_type:
        parameters['detail_type'] = detail_type
    f = urlopen(POCKET_GET_URL, urlencode(parameters))
    return json.loads(f.read())


def empty_pocket_items(access_token):
    while True:
        pocket_items = get_pocket_items(access_token)
        pocket_items = pocket_items['list']
        if not pocket_items:
            return

        actions = [{
            'action': 'delete',
            'item_id': item_id
        } for item_id in pocket_items.iterkeys()]

        logging.info('Deleting %s items...', len(actions))
        actions = json.dumps(actions)
        send_pocket_request(access_token, actions)


def get_google_auth():
    request = Request(GOOGLE_LOGIN_URL, urlencode({
        'service': 'reader',
        'Email': GOOGLE_EMAIL,
        'Passwd': GOOGLE_PASSWORD,
        'source': 'mobilescroll'
    }))

    f = urlopen(request)
    lines = f.read().split()
    return lines[2][5:]


request_token = get_pocket_request_token()
access_token = get_pocket_access_token(request_token)
# empty_pocket_items(access_token)
google_auth_headers = {'Authorization': 'GoogleLogin auth=' + get_google_auth()}
continuation = ''
total = 0

while True:
    if continuation:
        star_url = '%s&c=%s' % (GOOGLE_STAR_URL, continuation)
    else:
        star_url = GOOGLE_STAR_URL
    request = Request(star_url, headers=google_auth_headers)
    f = urlopen(request)
    data = json.loads(f.read())

    items = data['items']
    count = len(items)
    logging.info('Fetched %s items.', count)

    actions = []
    for item in items:
        try:
            url = item['alternate'][0]['href']
            actions.append({
                'action': 'add',
                'url': url,
                # 'tags': ['google reader']  # uncomment this line if you need this tag
            })
        except (KeyError, IndexError):
            pass

    count = len(actions)
    actions = json.dumps(actions)
    send_pocket_request(access_token, actions)
    total += count
    logging.info('Saved %s items.', count)

    continuation = data.get('continuation')
    if not continuation:
        logging.info('Done. Saved %s items.', total)
        break

6条评论 你不来一发么↓ 顺序排列 倒序排列

    向下滚动可载入更多评论,或者点这里禁止自动加载

    想说点什么呢?