Пользователь
0,0
рейтинг
10 марта 2013 в 11:08

Разработка → Экспорт фотоальбомов из ВКонтакта

Преамбула


Дело было вечером, делать было нечего и тут мне в голову пришла мысль: «Как же мне выгрузить все фотографии из ВКонтакта на компьютер?» Недолго думая, я написал утилиту для этого и решил поделиться с общественностью, возможно я не один такой.

Поехали


В качестве инструмента для работы с API, путём кратких поисков, была выбрана библиотека vk_api. Для работы с сетью она использует Requests, поэтому и эта библиотека требуется для запуска.

Пощупать


GitHub Pages проекта


Само приложение получилось крайне простым и небольшим, но с задачей своей справляется. Весь код уместился в одном единственном файле.

Исходный код
#!/usr/bin/env python

"""
    :mod:`vkporter`
    ~~~~~~~~~~~~~~~

    A micro tool for export photo albums from `vk.com <https://vk.com>`_.
     It's based on `VK_API <https://github.com/python273/vk_api>`_
     by Kirill Python <mikeking568@gmail.com>,
     `Requests <python-requests.org>`_
     and `ProgressBar <https://code.google.com/p/python-progressbar/>`_.

    :copyright: (c) 2013 by Andrey Maksimov.
    :license: BSD, see LICENSE for more details.
"""

__author__ = 'Andrey Maksimov <meamka@me.com>'
__date__ = '09.03.13'
__version__ = '0.1.1'

import argparse
import datetime
from getpass import getpass
import os
import time
import sys

try:
    import requests
except ImportError:
    print("Cannot find 'requests' module. Please install it and try again.")
    sys.exit(0)

try:
    from vk_api import VkApi
except ImportError:
    print("Cannot find 'vk_api' module. Please install it and try again.")
    sys.exit(0)


def connect(login, password):
    """Initialize connection with `vk.com <https://vk.com>`_ and try to authorize user with given credentials.

    :param login: user login e. g. email, phone number
    :type login: str
    :param password: user password
    :type password: str

    :return: :mod:`vk_api.vk_api.VkApi` connection
    :rtype: :mod:`VkApi`
    """
    return VkApi(login, password)


def get_albums(connection):
    """Get albums list for currently authorized user.

    :param connection: :class:`vk_api.vk_api.VkApi` connection
    :type connection: :class:`vk_api.vk_api.VkApi`

    :return: list of photo albums or ``None``
    :rtype: list
    """
    try:
        return connection.method('photos.getAlbums')
    except Exception as e:
        print(e)
        return None


def get_photos(connection, album_id):
    """Get photos list for selected album.

    :param connection: :class:`vk_api.vk_api.VkApi` connection
    :type connection: :class:`vk_api.vk_api.VkApi`
    :param album_id: album identifier returned by :func:`get_albums`
    :type album_id: int

    :return: list of photo albums or ``None``
    :rtype: list
    """
    try:
        return connection.method('photos.get', {'aid': album_id})
    except Exception as e:
        print(e)
        return None


def download(photo, output):
    """Download photo

    :param photo:
    """
    url = photo.get('src_xxxbig') or photo.get('src_xxbig') or photo.get('src_xbig') or photo.get('src_big')

    r = requests.get(url)
    title = photo['pid']
    with open(os.path.join(output, '%s.jpg' % title), 'wb') as f:
        for buf in r.iter_content(1024):
            if buf:
                f.write(buf)


def sizeof_fmt(num):
    """Small function to format numbered size to human readable string

    :param num: bytes to format
    :type num: int

    :return: human readable size
    """
    for x in ['bytes', 'KB', 'MB', 'GB', 'TB']:
        if num < 1024.0:
            return "%3.1f %s" % (num, x)
        num /= 1024.0


if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='', version='%(prog)s ' + __version__)
    parser.add_argument('username', help='vk.com username')
    # parser.add_argument('password', help='vk.com username password')
    parser.add_argument('-o', '--output', help='output path to store photos',
                        default=os.path.abspath(os.path.join(os.path.dirname(__file__), 'exported')))

    args = parser.parse_args()

    # expand user path if necessary
    if args.output.startswith('~'):
        args.output = os.path.expanduser(args.output)

    start_time = datetime.datetime.now()
    try:
        password = getpass("Password: ")

        # Initialize vk.com connection
        connection = connect(args.username, password)

        # Request list of photo albums
        albums = get_albums(connection)
        print("Found %s album%s:" % (len(albums), 's' if len(albums) > 1 else ''))
        ix = 0
        for album in albums:
            print('%3d. %-40s %4s item%s' % (
            ix + 1, album['title'], album['size'], 's' if int(album['size']) > 1 else ''))
            ix += 1

        # Sleep to prevent max request count
        time.sleep(1)

        if not os.path.exists(args.output):
            os.makedirs(args.output)

        for album in albums:
            response = get_photos(connection, album['aid'])
            output = os.path.join(args.output, album['title'])
            if not os.path.exists(output):
                os.makedirs(output)

            processed = 0

            for photo in response:
                percent = round(float(processed) / float(len(response)) * 100, 2)
                sys.stdout.write(
                    "\rExporting %s... %s of %s (%2d%%)" % (album['title'], processed, len(response), percent))
                sys.stdout.flush()

                download(photo, output)
                processed += 1

    except Exception as e:
        print(e)
        sys.exit(1)

    except KeyboardInterrupt:
        print('VKPorter exporting stopped by keyboard')
        sys.exit(0)

    finally:
        print("Done in %s" % (datetime.datetime.now() - start_time))




Примеры


По умолчанию экспорт происходит в папку ./exported
$ ./vkporter.py username@vk.com

Путь для экспорта можно указать при запуске
$ ./vkporter.py -o ~/Documents/Exported username@vk.com


Выглядит это примерно так:
image

Общение


Буду благодарен на репорты о багах на github.com/amka/VKPorter/issues
Andrey M. @Amka
карма
16,7
рейтинг 0,0
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама

Самое читаемое Разработка

Комментарии (38)

  • +2
    Есть еще альтернативный вариант через расширение для фф addons.mozilla.org/ru/firefox/addon/vkontakte-photo/
    • 0
      спасибо кэп, работает. И даже вроде загружает в оригинальном разрешении. Буду теперь делать бэкапы в скрытых папках =)
      • 0
        Рад стараться.
  • +1
    SaveFrom умеет так делать, причём он кроссбраузерный.
    Однако, этот скрипт тоже может помочь, например, для загрузки фотографий на сервер.
    Сделали бы вы ещё такое для аудиозаписей…
    • 0
      Так можете посмотреть исходный код вот этого аддона: addons.mozilla.org/ru/firefox/addon/vkontakteru-downloader/?src=collection&collection_id=553245ed-e8b5-412f-8ce3-2ecef382c541
      Он успешно справляется с загрузкой медиаконтента.
      • 0
        Мне нужна загрузка на свой сервер, у которого из браузеров только links.
        • 0
          Так Вам и говорят, посмотрите исходный код :)
          • 0
            Посмотреть могут многие, а вот разобраться в нём — нет.
    • 0
      Для аудиозаписей, конечно, можно, но мне кажется там всё же надо больше интерактивности, которую я не очень люблю в консоли. То ли дело GUI приложение :)
      • +3
        Я писал скрипт на PHP (жду кучу минусов от хейтеров), состоящий из двух частей.
        Первая часть — авторизация. На неё заходишь с браузера, проходишь стандартную авторизацию oAuth, а скрипт кладёт рядом с собой файлик с токеном. При авторизации скрипт в scope прописывает параметр offline, который разрешает использовать токен при смене IP.
        Вторая часть — генератор. Её нужно вызвать из консоли, командой php <имяскрипта>. Она запрашивает аудиозаписи у того, кто залогинился, создаёт .sh файлик с командами для загрузки (wget) и выполняет его. После его работы в папочке будут лежать все мои аудиозаписи, названные нормальными именами (а не хэшами).
        Для чего всё это? Ответ прост, для радио. Для нон-стоп режима. Очень удобно, просто слил туда огромную базу треков, и слушаешь, например, на работе или в институте, где есть вай-фай.
        • +2
          sh с wget внутри? Вот это попахивает извращением) Почему не заюзали curl?
          Нормальные имена вытаскивали с помощью чего? Я так понимаю ID3 после скачивания проходили
          А самое главное — токен на своем компе нужно было получить, потом по ftp/sftp/scp заливали на сервер?
          • +1
            Сервер стоит у меня дома, поэтому проблемы с совместимостью айпишников не было.
            Нет, зачем. у меня все записи поименованы хорошо, брал имена из приходящего мне JSONа.
            Почему не заюзал CURL? Потому что неохота менять 30-секундный лимит выполнения.
            После того, как PHP выполнит своё грязное дело, просто запускаем .sh и уходим чаёвничать.
      • 0
        Amka, а что насчет VKMusic? Я пользуюсь этим приложением, если нужно скачать медиа контент из контакта. Очень радует его работа =) Возможно это то, что тебе подойдет ;)
        • 0
          Я, в общем, не скачиваю оттуда музыку, окромя их официального клиента под смартфон. Это были мои размышления на пожелания namikiri
    • 0
      Скачиваете плейлист со всеми аудио, закидываете на сервер, на сервере с помощью aria2 закачиваете по списку в несколько потоков.
    • 0
      вот запилил korzhyk.github.com/VKMusic/ krogin
      • 0
        Можно установить:

        $ easy_install VKMusic

        или

        $ pip install VKMusic
    • 0
      Попробуйте пожалуйста saver.zamp3.ru/. Есть возможность синхронизации с Google Drive.
  • 0
    Алгоритм ранжирования на окне уже записали?
  • +3
    Подумал, что на скрине прогресс-бары разных потоков загрузки, ан нет — просто ПД))
  • –3
    На хабре недавно проскакивала прога Songo плеера вконтакте.
    Как думаете стоит ли написать прогу на дельфи для прослушивания Музыки вконтакте онлайн ??
    Есть Желающие помочь пишите в личку!!!

    Жаль что хром не может сворачиватся в трей как Винамп…
  • 0
    Почему выбран такой тип оформления параметров?
    :param num: bytes to format
    :type num: int

    :return: human readable size

    Это какой-то стандарт?
    • 0
      Автор писал в IDEA (сужу по .gitignore), там по умолчанию reStructuredText для доков. Sphinx потом генерирует хорошую доку.
      • +1
        Писал в PyCharm, да, но у нас и в других проектах используется Sphinx, так что привычно было использовать его.
  • 0
    Да: docutils.sourceforge.net/docs/ref/rst/restructuredtext.html#field-lists.
    Еще есть epytext, мне он больше нравится: epydoc.sourceforge.net/manual-epytext.html#fields

    UPD: это к комментарию выше.
    Автору могу посоветовать использовать enumerate, не изменять аргументов функций и вообще почитать доку. Хотя код оформлен гламурненько =)
  • +1
    www.olexandr.org/blog/c-pervyj-blin.html
    вот, в конце прошлого года пробовал писать свое первое приложение на шарпе
  • +2
    я когда-то написал экспорт всех заметок в Эвернот
    • 0
      Работает ли это сейчас?
      На github.com есть?
      • 0
        должно работать. оно как приложение вк сделано, но чтоб добавить в общественный каталог там нужны какие-то голоса

        на гитхабе нет
  • 0
    Еще бы кто-нибудь написал приложение для переноса альбомов из Вконтакте в Facebook. Был проект «Итутитам», но данный функционал там перестал работать.
  • –1
    Я все мечтаю написать скрипт по экспорту аудиозаписей со стены группы вконтакте (не из альбома, а именно со стены). Только что-то как-то никак не реализую мечту свою.
    • 0
      есть люди которые многое делают с аудио — они плеер пишут meridianvk.com, думаю можно их спросить как
      • 0
        ну там только слушать можно… а мнеб на телефон залить)
  • 0
    А как бы сохранить «фотографии со мной»?

    Вот как раз их хотелось бы сохранить, например, перед удалением странички.
    Заранее благодарю!
  • 0
    было дело, делал аналог в такой же связке по экспорту фоток из livejournal'а

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.