Сохранение данных Google Reader

в 12:30, , рубрики: backup, Google, googlereader, opensource, python, rss, метки: , , , , ,

Чем ближе дата закрытия Google Reader тем более насущным становится вопрос не только переноса подписок в аналогичный сервис, но и сохранения всех текущих записей.

Найденные решения, в том числе и на хабре(здесь и здесь), не подошли в основном по двум причинам: нет возможности сохранения в БД и медленная скорость работы. Пришлось собрать свой велосипед — grbackup, который

grbackup -e fake@gmail.com -p password -ba -o mongodb://localhost:27017 -w 20

за 20 минут сохранил 328250 записей из 102 подписок в локальную БД MongoDB.

Основные возможности:

  • сохранение всех записей, которые можно получить при помощи Google Reader API
  • сохранение записей в различные хранилища
  • использование формата идентичного тому, что отдает Google Reader через API
  • параллельное получение/сохранение записей
  • расширяемость: возможность добавить новый вид хранилища

Доступные виды хранилищ определяются расширениями(плагинами) и задаются при помощи опции (-o, --output) вида type:uri.
На момент написания статьи доступны следующие расширения:

  • simple: вывод в терминал (используется только в режиме просмотра)
  • json: запись в json-файл (json:/path/to/file.json)
  • mongodb: запись в MongoDB (mongodb://[username:password@]hostN[:portN]]][/[db][?opts]])
  • redis: запись в Redis (redis://username:password@host[:port]/dbindex)

Работоспособность проверена на Ubuntu(64) и Win7(64).
Книгу предложений и замечаний можно найти здесь.
Ниже находится подробное описание утилиты.

Установка

pip install grbackup

или

easy_install grbackup

или

pip install git+git://github.com/wistful/grbackup.git

Опций командной строки

Авторизация

  • -e, --email: почтовый адрес используемый для входа в Google Reader
  • -p, --password: пароль

grbackup поддерживает два действия:

  • просмотр:-l, --list
  • сохранение: -b, --backup

Действие можно выполнить над одним из четырех типов данных:

  • подписки; -s, --subscriptions
  • записи: -t, --topics
  • отмеченные записи: -x, --starred
  • все предыдущие вместе взятые: -a, --all

Дополнительные опции:

  • -w, --workers: максимальное количество одновременно обрабатываемых подписок (по умолчанию 1)
  • -o, --output: URI показывающий куда сохранять записи
  • -n, --count: количество записей получаемых от Google Reader за один запрос (по умолчанию 200). Слишком большое число может привести к получению данных более мелкими порциями (ох уж этот google).

Все опции, а также описание плагинов можно просмотреть используя опцию -h, --help:

grbackup -h

вывод предыдущей команды

Usage: grbackup [options] [args]

Examples:

   list subscriptions: grbackup -e email@gmail.com -p password -ls
   list topics: grbackup -e email@gmail.com -p password -lt http://feed.com
   list starred: grbackup -e email@gmail.com -p password -lx
   list all items: grbackup -e email@gmail.com -p password -la

   backup subscriptions: grbackup -e email@gmail.com -p password -bs -o json:/tmp/subscriptions.json
   backup topics: grbackup -e email@gmail.com -p password -bt http://myfeed.com -o json:/tmp/myfeed.json
   backup starred into MongoDB: grbackup -e email@gmail.com -p password -bx -o mongodb://localhost:27017
   backup all items into Redis: grbackup -e email@gmail.com -p password -ba -o redis://localhost:6379/3

Available plugins:

  mongodb:  save items into MongoDB
            output scheme:   mongodb://[username:password@]hostN[:portN]]][/[db][?opts]]
            output examples: mongodb://localhost:27017
                             mongodb://user:pwd@localhost,localhost:27018/?replicaSet=grbackup
            
  json:     save items into file
            output scheme:   json:/path/to/file.json
            output examples: json:/home/grbackup/grbackup.json
                             json:/tmp/grbackup/grbackup.json
            
  redis:    save items into Redis
            output scheme:   redis://username:password@host[:port]/dbindex
            output examples: redis://localhost:6379/3
                             redis://user:password@localhost:6379/0
            

Options:
  Auth Options:
    -e EMAIL, --email=EMAIL
                        gmail account
    -p PWD, --password=PWD
                        account password

  Command Options:
    -b, --backup        backup items
    -l, --list          list items

  Scope Options:
    -a, --all           processing all items
    -s, --subscriptions
                        processing subscriptions only
    -t, --topics        processing topics only
    -x, --starred       processing starred topics only

  MongoDB Options:
    --mongodb-db=MONGODB_DB
                        the name of the database[default: greader]
    --mongodb-scol=MONGODB_SUBSCRIPTIONS
                        collection name for subscriptions[default:
                        subscriptions]
    --mongodb-tcol=MONGODB_TOPICS
                        collection name for topics[default: topics]
    --mongodb-tstar=MONGODB_STARRED
                        collection name for starred items[default: starred]
    --mongodb-w=MONGODB_W
                        <int> Write operations will block until they have been
                        replicated to the specified number [default: 1]
    --mongodb-j         block until write operations have been committed to
                        the journal [default: False]

  Redis Options:
    --redis-scol-prefix=REDIS_SUBS
                        subscriptions key prefix[default: subscription]
    --redis-tcol-prefix=REDIS_TOPICS
                        topics key prefix[default: topic]
    --redis-xcol-prefix=REDIS_STARRED
                        starred key prefix[default: starred]

  Other Options:
    -w WORKERS, --workers=WORKERS
                        number of workers [default: 1]
    -o OUTPUT, --output=OUTPUT
                        output uri
    -n COUNT, --count=COUNT
                        the number of topics that can be read at once
                        [default: 200]
    -c CODING, --coding=CODING
                        output coding [default: utf8]
    -v, --verbose       verbose output
    -h, --help  

Использование

список подписок:

grbackup -e email@gmail.com -p password -ls

список записей конкретной подписки:

 grbackup -e email@gmail.com -p password -lt http://habrahabr.ru/rss/hub/python/

список всех отмеченных записей:

grbackup -e email@gmail.com -p password -lx

список всех записей:

grbackup -e email@gmail.com -p password -la

сохранение подписок в json-файл:

 grbackup -e email@gmail.com -p password -bs -o json:/tmp/subscriptions.json

сохранение всех записей конкретной подписки в json-файл:

grbackup -e email@gmail.com -p password -bt http://habrahabr.ru/rss/hub/python/ -o json:/tmp/python.json

сохранение всех отмеченных записей в MongoDB:

grbackup -e email@gmail.com -p password -bx -o mongodb://localhost:27017

сохранение всех записей в Redis с использованием 20 потоков:

grbackup -e email@gmail.com -p password -ba -o redis://localhost:6379/3 -w 20

Плагины

JSON

Общий формат URI: json:/path/to/file.json
Поддержка многопоточности: да
Пример использования:

grbackup -e email@gmail.com -p password -ba -o json:/home/grbackup/grbackup.json

Записи сохраняются в отдельный файл в виде списка объектов.
Существует три типа объектов:

  • подписки: {«type»: «subscription», «value»: subscription}
  • отмеченные записи: {«type»: «starred», «value»: record}
  • обычная запись: {«type»: «topic», «subscription»: subscription_url, «value»: record}
MongoDB

Общий формат URI: mongodb://[username:password@]hostN[:portN]]][/[db][?opts]]
Поддержка многопоточности: да
Пример использования:

grbackup -e email@gmail.com -p password -ba -o mongodb://localhost:27017 -w 20

Записи раскладываются по трем коллекциям: subscriptions, topics, starred.
Имена коллекций можно изменять.

Redis

Общий формат URI: redis://username:password@host[:port]/dbindex
Поддержка многопоточности: да
Пример использования:

grbackup -e email@gmail.com -p password -ba -o redis://user:password@localhost:6379/0 -w 20

Для хранения записей используется тип данных Hashes.
Ключи могут быть трех типов: «subscription:record_id», «starred:record_id», «topic:record_id», где record_id — уникальный идентификатор записи.
Префиксы ключей можно изменять.

Свой плагин

Модуль должен находится в пакете grb_plugins, имя модуля не имеет значения.
Структура модуля:

  • plugin_type — строковый тип, содержит имя плагина
  • support_threads — логический тип, указывает на возможность использования нескольких потоков
  • descriptions — строковый тип, содержит описание плагина
  • add_option_group — функция добавляющая дополнительные опции комадной строки
  • writer — контекстный менеджер возвращающий объект с методами:
    • put_subscription(subscription) — вызывается при сохранение подписки, subscription — словарь
    • put_starred(topic) — вызывается при сохранении отмеченной записи, topic — словарь
    • put_topic(self, subscription_url, topic) — вызывается при сохранении записи (опция '-t', '--topics'),
      topic — словарь, subscription_url — строковый адрес подписки
    • put_all(subscription, topic) — вызывается при сохранении записи с использованием опции '-a', '--all',
      subscription и topic — словари

Пример плагина использующего logging для сохранения записей в файл

#!/usr/bin/env python
# coding=utf-8
from optparse import OptionGroup
import logging

plugin_type = "myplugin"
support_threads = True
description = """save items using logging
output scheme:   myplugin:/path/to/logfile.log
output examples: myplugin:/tmp/storage.log
"""

def add_option_group(parser):
    # Plugin Options
    myplugin_group = OptionGroup(parser, "myplugin Options")
    myplugin_group.add_option("--myplugin-format",
                              dest="format",
                              type="str",
                              default="%(asctime)s %(message)s",
                              help="record format"
                              "[default: %default]")
    myplugin_group.add_option("--myplugin-datefmt",
                              dest="datefmt",
                              type="str",
                              default="%m/%d/%Y %I:%M:%S %p",
                              help="date format"
                              "[default: %default]")
    parser.add_option_group(myplugin_group)


class WriteMyPlugin(object):

    def __init__(self, logger):
        self.logger = logger

    def put_subscription(self, subscription):
        subscription_url = subscription['id'][5:]
        self.logger.warning("write subscription: %s", subscription_url)

    def put_all(self, subscription, topic):
        subscription_url = subscription['id'][5:]
        self.put_subscription(subscription)
        self.put_topic(subscription_url, topic)

    def put_starred(self, topic):
        self.logger.warning("write starred: %s", topic.get('title', ''))

    def put_topic(self, subscription_url, topic):
        self.logger.warning("write topic: %s %s",
                            subscription_url,
                            topic.get('title', ''))


class writer(object):

    def __init__(self, opt):
        path = opt.output[opt.output.index(":") + 1:]
        self._logger = logging.getLogger("myplugin")
        handler = logging.FileHandler(path)
        handler.setFormatter(logging.Formatter(opt.format, opt.datefmt))
        self._logger.addHandler(handler)

    def __enter__(self):
        return WriteMyPlugin(self._logger)

    def __exit__(self, *exc_info):
        pass

Автор: wistful

Источник

Поделиться

* - обязательные к заполнению поля