vk.com — Сохранение аудиозаписей, документов, содержимого стены

Я уже давно заметил, что данные в социальных сетях хранятся плохо. Например, сделанный вами репост окажется пустым, если автор оригинальной записи ее удалит. Недавние проблемы с аудиозаписями в vk стали последней каплей, и я решил сохранить локально все данные, которые могут представлять интерес на случай ядерной войны. Поискав готовые решения, я не нашел ничего, что бы устроило меня, поэтому за несколько дней был написан скрипт на Python.

Цели


Сохранить все, что можно: аудиозаписи, документы, стену. Со стены нужно утащить все приложения к постам, и комментарии со всеми приложениями тоже лишними не будут. Нужно это как минимум затем, чтобы сохранились все посты с музыкой и комментарии, где друзья отправляли хорошие треки или котиков. Сразу скажу, что в моих целях не было читабельного бэкапа дополнительной информации (лайки, время создания записи и прочее).

За дело!


Процесс создания подобного приложения уже не раз описан на хабре, поэтому повторять все подробности не стану, опишу шаги работы вкратце, а еще скажу пару слов о пролемах. Чтобы статья не была перегружена исходниками, в конце будет ссылка на github.

Соображения по ходу разработки



Продолжим

Код обращения к api взят из статьи хабраюзера dzhioev, и добавлена обработка ситуаций, описанных выше. Чтобы было, что сохранять (в случае с обработкой стены), надо сначала узнать количество постов:
        #determine posts count
        (response, json_stuff) = call_api("wall.get", [("owner_id", args.id), ("count", 1), ("offset", 0)], args)
        count = response[0]

Дальше запрашиваем каждый пост по отдельности и разбираем его
        for x in xrange(args.wall_start, args.wall_end):
            (post, json_stuff) = call_api("wall.get", [("owner_id", args.id), ("count", 1), ("offset", x)], args)
            process_post(("wall post", x), post, post_parser, json_stuff)

Результат запроса — это набор данных в JSON, которые разбираются в стандартные для python'а структуры с помощью json.loads() из стандартной библиотеки. В итоге, имеем хэш-массив, в котором некоторые поля (ключ-значение) несут полезную нагрузку, а остальные нас не интересуют. Чтобы руками не писать, какое поле каким методом обрабатывать, воспользуемся мощью рефлексии: будем искать метод, имя которого совпадает с интересующим ключом.
        for k in raw_data.keys():
            try:
                f = getattr(self, k)
                keys.append(k)
                funcs.append(f)
            except AttributeError:
                logging.warning("Not implemented: {}".format(k))
        logging.info("Saving: {} for {}".format(', '.join(keys), raw_data['id']))

        for (f, k) in zip(funcs, keys):
            f(k, raw_data)


Парсим

Теперь нужно разбираться с полями ответа. Интересные — это attachments, text, comments. Attachments — это список приложений к посту (аудио, картинки, документы, заметки), надо уметь скачивать каждый тип. Определяемся, каким методом обрабатывать каждый attachment, аналогичным способом: по типу аттача ищем метод с подходящим именем. Вот пример «качалки» для аудио:
    def dl_audio(self, data):
        aid = data["aid"]
        owner = data["owner_id"]
        request = "{}_{}".format(owner, aid)
        (audio_data, json_stuff) = call_api("audio.getById", [("audios", request), ], self.args)
        try:
            data = audio_data[0]
            name = u"{artist} - {title}.mp3".format(**data)
            self.save_url(data["url"], name)
        except IndexError: # deleted :(
            logging.warning("Deleted track: {}".format(str(data)))
            return

        # store lyrics if any
        try:
            lid = data["lyrics_id"]
        except KeyError:
            return
        (lyrics_data, json_stuff) = call_api("audio.getLyrics", [("lyrics_id", lid), ], self.args)
        text = lyrics_data["text"].encode('utf-8')
        ...

К сожалению, изъятые по просьбе правообладателей аудиозаписи больше не доступны, для них возвращается пустой ответ.

А остальное?


Методы обработки картинок, текста, заметок, закачки документов и остальное — в github. Скажу только, что все аналогично приведенным примерам. Еще скрипт имеет аргументы командной строки, их описывать в статье смысла нет. Примеры и прочие подробности — в readme.

TODO

Я не стал делать сохранение фотоальбомов, потому что у меня там ничего важного не хранится, да и код kilonet из его статьи неплохо работает. Еще не сохраняются видеозаписи и заметки, мне это показалось не сильно нужным.

На последок

Код далек от идеала и не отличается отсутствием костылей, но выполняет поставленную задачу. Надеюсь, кому-то пригодится моя поделка, для сохранения своих записей/документов/музыки, или для обучения.

UPD 18.12.2016

Юзер hiwent говорит, что с 16.12.2016 года vk закрыли возможность использовать API для работы с аудиозаписями. В связи с этим, функционал скрипта, предусмотренный для сохранения аудиозаписей, не работает. В связи с этим можно попробовать «прикинуться» родным приложением vk, апример андроид-версией, или kate mobile. Для них возможность работать с аудиозаписями никуда не пропадет, хотя может быть методы отличаются.
@Rast1234
22.06.2013 01:41 UTC
Первоисточник