Клуб Фоток

Python-скрипт для скачивания всех фоток или отдельных альбомов пользователя

В отличие от публиковавшегося ранее скрипта мой вариант позволяет выбирать между скачиванием всех альбомов, явным заданием желаемого их списка или интерактивным режимом. Можно использовать заголовки фоток в качестве имён файлов и даты съёмки/публикации — в качестве дат изменения файлов.

 

Для запуска требуется Python 3.2. Для вывода справки используйте параметр -h (или --help).

 



#!/usr/bin/env python

import os
import time
import re
import urllib.request
import json
import argparse

user_url = "http://api-fotki.yandex.ru/api/users/{}/albums/?format=json"
album_url = "http://api-fotki.yandex.ru/api/users/{}/album/{}/photos/?format=json"

CREATED = 1
PUBLISHED = 2

def grab(user_id, album_id, dest, use_title, use_date):
    url = album_url.format(user_id, album_id)
    album = json.loads(urllib.request.urlopen(url).read().decode("utf-8"))
    if not "entries" in album:
        return
    album_dir = os.path.join(dest, album["title"])
    if not os.path.isdir(album_dir):
        os.makedirs(album_dir)
    print('Downloading album "{}" (id: {})...'.format(album["title"], album_id))
    for image in album["entries"]:
        if use_date == CREATED and "created" in image:
            t = time.mktime(time.strptime(image["created"], "%Y-%m-%dT%H:%M:%SZ"))
        elif use_date == PUBLISHED:
            t = time.mktime(time.strptime(image["published"], "%Y-%m-%dT%H:%M:%SZ"))
        else:
            t = time.time()
        if use_title and image["title"].lower() not in ["", ".jpg"]:
            filename = os.path.join(album_dir, image["title"])
            if not image["title"].lower().endswith(".jpg"):
                filename += ".jpg"
            if os.path.exists(filename):
                print('"{}" already exists. Skipped.'.format(filename))
                continue
            try:
                f = open(filename, mode="wb")
                f.write(urllib.request.urlopen(image["img"]["orig"]["href"]).read())
                f.close()
                os.utime(filename, (time.time(), t))
                continue
            except IOError:
                pass
        filename = os.path.join(album_dir, re.search("\d+$", image["id"]).group() + ".jpg")
        if os.path.exists(filename):
            print('"{}" already exists. Skipped.'.format(filename))
            continue
        try:
            f = open(filename, mode="wb")
            f.write(urllib.request.urlopen(image["img"]["orig"]["href"]).read())
            f.close()
            os.utime(filename, (time.time(), t))
        except IOError:
            print('"{}" cannot be saved. Skiped.'.format(filename))

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Downloads albums from Yandex.Fotki. Skips files that already exist.")
    parser.add_argument("user")
    parser.add_argument("-a", "--albums", nargs="*", metavar="ID", help="list of album ids to proceed (download all if empty, prompt for every album if the argument is omitted)")
    parser.add_argument("-d", "--dest", default="", metavar="DIR", help="output directory")
    parser.add_argument("-t", "--use-title", action="store_true", help="use title as file name (if possible)")
    date_group = parser.add_mutually_exclusive_group()
    date_group.add_argument("-c", "--use-cdate", dest="use_date", action="store_const", const=CREATED, help="use creation date as modification date (if available)")
    date_group.add_argument("-p", "--use-pdate", dest="use_date", action="store_const", const=PUBLISHED, help="use publishing date as modification date")
    args = parser.parse_args()

    url = user_url.format(args.user)
    user = json.loads(urllib.request.urlopen(url).read().decode("utf-8"))
    if "entries" in user:
        for album in user["entries"]:
            if album["imageCount"] == 0:
                continue
            album_id = re.search("\d+$", album["id"]).group()
            if (args.albums is None and input('Download album "{}" (id: {})? '.format(album["title"], album_id)) in ["y", "Y"]) or (args.albums is not None and (args.albums == [] or album_id in args.albums)):
                grab(args.user, album_id, args.dest, args.use_title, args.use_date)
34 комментария
Станислав Клинков
28 января 2016, 00:10

Что-то в этом есть.

Осталось только написать скрипт бэкапа своего блога целиком себе на жесткий диск. ;-)

У меня есть такой, на php-cli :)

Станислав Клинков
28 января 2016, 00:10

Заделись пожалуйста, если не жалко.

Не жалко конечно, но никак не могу дооформить код и отказаться от PEAR.

Обещаю очень скоро этим занятся.

Осталось добавить поддерждку oauth :)

Пономарев Сергей
28 января 2016, 00:10

А можно поинтересоваться, чисто из интереса, причиной выбора кривого битбакета? Чем он лучше соурсфорга или гуглокода? :)

Пономарев Сергей
28 января 2016, 00:10

там можно создавать приватные репозитории B-)

А для тех кто в танке, програмку такую написать можно? Я бы сам написал да не умею.

Программка уже написана, только для её выполнения надо установить Python с сайта python.org. Сохраните код из поста в файл fotki.py и запускайте из командной строки:

python fotki.py имяпользователя 

Спасибо. Отлично работает

Кстати, занятная деталь. Если в названии альбома присутствует слэш /, то скрипт сделает из текста после него (слэша) вложенную папку. Т.о. альбом "2011/11/11 - Бла бла бла" будет создан в директории 11, которая будет лежать в директории 2011, а сам будет называться "11 - Бла бла бла"

проще было б коли зсделал бы скрипт для мозиллы в грейсманки. сидеть ещё питоны осваивать больно надо
Дак в чем проблема, напишите же ) а для использования этого скрипта притон знать вовсе не нужно. Я, например, даже исходник не читал, просто скопировал в файл и запустил на выполнение.
Чертов андроид. Питон, я хотел сказать, а не притон)))
ололо

Всем привет! Недавно тоже столкнулся с такой же проблемой "как выкачать оригиналы фотографий с Яндекс.Фотки?"
Вариант с кодами не получается - оригиналы он не скачивает.
Попробовал team23 - ошибка всё время...
Так что для меня это, похоже, один из последних вариантов. Ну, кроме ручками, естественно))

Уважаемые, только подскажите - а как пользоватся этим Питоном?? Никогда раньше до этого с ним дело не имел!! Скачал с сайта python-3.2.2 и установил. Что дальше надо запускать? Куда копировать этот скрипт? Или подскажите ссылки где про это расписано подробнее?

И ещё есть вопросик: я хочу чтобы при скачивании этим скриптом имена файлов получались такие же как заголовки закачанных фоток. Что именно в этом скрипте или где-то в другом месте нужно сделать чтобы этого добиться?

Уважаемые, только подскажите - а как пользоватся этим Питоном?? Никогда раньше до этого с ним дело не имел!! Скачал с сайта python-3.2.2 и установил. Что дальше надо запускать? Куда копировать этот скрипт? Или подскажите ссылки где про это расписано подробнее?

Сохраните текст скрипта в файл с расширением .py, например, fotki.py

Теперь, если Python должным образом зарегистрировался в системе при установке, можно просто запускать fotki.py на выполнение. Ну или писать "python fotki.py" в командной строке.

 

И ещё есть вопросик: я хочу чтобы при скачивании этим скриптом имена файлов получались такие же как заголовки закачанных фоток. Что именно в этом скрипте или где-то в другом месте нужно сделать чтобы этого добиться?

Запустите скрипт с параметром -t

Приложение для скачивания альбомов в исходном качестве.

Каждая созданная папка соответствует имени альбома. Фотографии также именуются в соответсвии с их именем на сайте.

Для запуска необходим .NET Framework 4.0

Публично доступные фотографии могут быть загружены без ввода пароля.

 

 Пример работы 

 Скачать приложение (архив, 2 файла) 

 

 

после выбора альбома пишет: 

Downloading (may take a lot of time)...
Произошла одна или несколько ошибок.

Если ваш альбом находится в публичном доступе, напишите его название, я мог бы попробовать найти ошибку

Доделал программу, пробуйте.


Скачать

Благодарю, работает!

скажите, а если оригиналы запрещены для показа их возможно скачать? 

Фотографии скачиваются в максимальном доступном разрешении, т.е. если пользователь скрыл оригиналы, то лишь только он, зная пароль, может скачать оригиналы.

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

При любых комбинациях скачиваотся фотки в размере 600 × 800, если не вводить пароль то нет доступа к запароленным альбомам

(в  Яндекс.Диск обешали сделать синхронизацию с Я.Ффотками, будем ждать)

С питоном я не особо дружу, но все же пришлось добавить рекурсию для альбомов с более чем 100 фотографиями.

https://github.com/sxua/yandex-fotki-dumper

Спасибо. Не знал о такой особенности API. Мой скрипт, кстати, тоже на Гитхабе лежит: https://github.com/fedyakov/fotki

Константин
28 января 2016, 00:10

можете дать скрипт для скачивания ОДНОЙ фотографии,очень надо

Константинъ Ходаковскій
28 января 2016, 00:10

Скрипт скачивает не больше 100 альбомов и не больше 100 фотографий в каждом из них — это ограничение API Яндекс.Фоток. Его невозможно обойти?

Жаль, что когда вручную указываешь номер альбома за пределами этой сотни, всё равно скрипт не скачивает его, так как полагается на выборку альбомов через API, где он, конечно, отсутствует.

А вот этот комментарий выше не поможет? http://clubs.ya.ru/fotki/51820/58440#reply-fotki-58440

Константинъ Ходаковскій
28 января 2016, 00:10

Нет, не помогает. Да и не может помочь в принципе, так как именно API Яндекс обрезает списки альбомов после 100 и списки фотографий после 100. То есть через API, как я понимаю, это невозможно реализовать. Единственный выход выдирать из HTML, но этот метод нужно постоянно адаптировать к изменениям в работе сайта, так что он не годится.

К сожалению, не берёт старые по времени альбомы даже при переборе.
Никто не подскажет ПО для массовой скачки фото под Windows?