Pull to refresh

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

Reading time 4 min
Views 84K

Преамбула


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

Поехали


В качестве инструмента для работы с 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
Tags:
Hubs:
+42
Comments 39
Comments Comments 39

Articles