Введение
Был полезный пост "Автоматизация закачки подкастов на mp3 плеер". Полезный для меня, поскольку ну не использую iTunes и прочий подобный софт (я не хочу это обсуждать :). Мне только нужно скачать пачку подкастов, которые периодически собираются в ленте ридера. И PHPу предпочитаю Python.
Хотелось бы услышать советы — я только изучаю Python. И мне нравится писать посты с примерами для начинающих. Замечаний бы, критики… Но к делу.
Организация процесса
Список по��кастерских лент я храню в Google Reader. Ленты помечены своим тегом, и аккуратно лежат в своей папке:
Для выкачивания новых подкастов, попавших в папку Podcasts, написал небольшой скрипт на Python. В качестве основы взял библиотеку />pyrfeed, в которой реализован полезный класс GoogleReader.
Исходный код библиотеки доступен и включает небольшой пример работы с ней. Есть документация. Правда, я нашел документацию только по API к Google Reader, а не работе с самой библиотекой. Там же есть пример утилиты с Gui-интерфейсом для чтения RSS-лент.
Исходный код
Ссылка на архив с исходником в конце.А здесь исходник главного скрипта:
import sys
import os
import time
import urlparse
import urllib
import progressBar
import GoogleReader
downloadDir = "myDownloadDir";
logFile = downloadDir + "PodcastsDownloadTool.log";
tag = "Podcasts";
login = "myGoogleReaderLogin";
password = "myGoogleReaderPassword";
def GetLocalFileNameFromURL(fullpath):
(filepath, filename) = os.path.split(urlparse.urlparse(fullpath).path)
return downloadDir + filename
def LogMessage(message):
f = open(logFile,"a")
print >> f, message;
f.close();
pass
def DownloadFile(url, filename):
progressBar.ResetProgressBar();
urllib.urlretrieve(url, filename, reporthook = progressBar.ProgressBarReportHook);
pass
def ProcessPodcastDownloading():
# Check and create dir
if not os.path.exists(downloadDir):
os.mkdir(downloadDir);
# Login to Google Reader
gr = GoogleReader.GoogleReader();
gr.identify(login, password);
if gr.login():
print "Login OK";
else:
print "Login KO";
return
xmlfeed = gr.get_feed(feed = "user/-/label/%s" % tag, n = 17, xt = "user/-/state/com.google/read");
for entry in xmlfeed.get_entries():
try:
googleID = entry['google_id'];
if entry.has_key('enclosure'):
# Prepare vars and print info
URLToDownload = entry['enclosure'];
localFilePath = GetLocalFileNameFromURL(URLToDownload);
print "Title: %s" % entry['title'];
print "Download from URL: %s ..." % URLToDownload;
print "Local file: %s" % localFilePath;
# Download file
DownloadFile(url=URLToDownload,filename=localFilePath)
# Log message
LogMessage("%s %s %s %s\n" % (time.strftime('%x %X'), URLToDownload, googleID, entry['published']));
print "Downloaded.";
# Mark as readed
gr.set_read(googleID);
print "Marked.";
except:
#Print and log error
print "Error: ", sys.exc_info();
LogMessage("%s\nError: %s\nEntry: %s\nException info: %s\n%s\n" % ("="*80, time.strftime('%x %X'), entry, sys.exc_info(), "="*80));
pass
if __name__=='__main__' :
ProcessPodcastDownloading();
Пояснения к коду
Основные параметры задаются в начале скрипта:- downloadDir – каталог, куда будут скачиваться подкасты
- logFile – лог файл
- tag – имя тега/папки в Google Reader, в которой будут просматриваться ленты
- login и password – логин и пароль в Google Reader
А дальше ничего сложного:
- аутентификация в сервисе Google Reader
- получение распарсенной RSS-ленты
- цикл по записям с выводом информации и записью в лог
- собственно, скачивание файлов
- метка записей прочитанными
Саму библиотеку pyrfeed в приложение не включаю. Её достаточно скачать, внести пару строчек (о которых далее), и положить в допустимое для import’а место. Например, в директорию Lib каталога, куда установлен Python — тогда библиотека станет доступна всем скриптам.
У меня каталоги GoogleReader и web располагаются в той же директории, где находится мой скрипт.
Интерфейс
Это консольная утилита. Делайте выводы.Просто отображение процесса загрузки выглядит так:

Прогресс-бар взят из какого-то примера. Точно не помню откуда. Примеров в интернете много и большинство друг на друга похожи. Исходник есть в приложении.
Патч для feed.py
К сожалению, класс GoogleFeed не извлекает из полученного XML ссылку на файл для скачивания.Я решил эту проблему, добавив к парсингу XML после такого фрагмента:
elif dom_entry_element.localName == 'link' :
if dom_entry_element.getAttribute('rel')=='alternate' :
entry['link'] = dom_entry_element.getAttribute('href')Такой кусочек:
if dom_entry_element.getAttribute('rel')=='enclosure' :
entry['enclosure'] = dom_entry_element.getAttribute('href')Получилось вот так:
elif dom_entry_element.localName == 'link' :
if dom_entry_element.getAttribute('rel')=='alternate' :
entry['link'] = dom_entry_element.getAttribute('href')
if dom_entry_element.getAttribute('rel')=='enclosure' :
entry['enclosure'] = dom_entry_element.getAttribute('href')
elif dom_entry_element.localName == 'category' :Недостатки, которые меня устраивают
- Не поддерживается докачка. В случае сбоя RSS-запись не будет помечена как прочитанная. При следующем запуске скрипта файл будет выкачан заново.
- Отсюда следующий момент – при следующем запуске скрипта, ошибочные записи (например, в записи нет ссылки на файл для скачивания, так бывает) будут повторно обрабатываться. Можно бы их метить специальным тегом и пропускать в дальнейшем. Но меня устраивает последующий ручной просмотр ленты на предмет не прочитанных записей.
- Хранение конфигурации – логин и пароль в открытом виде. Логин еще не так страшно, а вот пароль… Можно использовать функцию getpass() или хранить его в другом месте.
Можно автоматизировать запуск скрипта при подключении USB-флешки или плеера, например при помощи утилиты USB Detect & Launch (о нем уже было сказано на хабре).
Финиш
И Исходники в архиве.А заметку скопипастил со своей страницы.
