Как стать автором
Поиск
Написать публикацию
Обновить

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

Время на прочтение7 мин
Количество просмотров29K
Чем ближе дата закрытия 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


Теги:
Хабы:
Всего голосов 40: ↑37 и ↓3+34
Комментарии31

Публикации

Ближайшие события