Вступление
Лирическое отступление
Здравствуй, публика Хабрахабра. Я уже некоторое время наблюдаю за Вами, читаю Ваши работы. Честно признаться, меня завораживает тонкий и одновременно смелый мир Хабра. Поэтому, немного поразмыслив, я решил влиться в Вашу компанию. Это, как Вы уже, наверное, заметили, мой первый пост, но я не призываю Вас быть помягче ко мне. Скорее, я хочу испытать все те чувства, которые пережили или переживают бывалые пользователи. Давно хотел это написать здесь — добро пожаловать под кат.
Что, как и, главное, зачем?
Все просто: скрипт, написанный на Python 3.3, позволяющий загрузить указанную композицию с небезызвестного vk.com. Я использовал только стандартные модули: urllib и html.parser. Выражу общее мнение, если скажу, что это тот еще велосипед.
Код
Собственно, код разделен на три условные части: класс для парсинга формы, класс для парсинга списка композиций и главная часть.
Парсинг формы входа
Как я уже упоминал, парсить мы будем при помощи html.parser.
class FormParser(HTMLParser): def __init__(self): HTMLParser.__init__(self) self.url = None self.params = {} self.in_form = False self.form_parsed = False self.method = "GET" def handle_starttag(self, tag, attrs): tag = tag.lower() if tag == "form": if self.form_parsed: raise RuntimeError("Second form") if self.in_form: raise RuntimeError("Already in form") self.in_form = True if not self.in_form: return attrs = dict((name.lower(), value) for name, value in attrs) if tag == "form": self.url = attrs["action"] if "method" in attrs: self.method = attrs["method"] elif tag == "input" and "type" in attrs and "name" in attrs: if attrs["type"] in ["hidden", "text", "password"]: self.params[attrs["name"]] = attrs["value"] if "value" in attrs else "" def handle_endtag(self, tag): tag = tag.lower() if tag == "form": if not self.in_form: raise RuntimeError("Unexpected </form>") self.in_form = False self.form_parsed = True
Класс занимается тем, что находит тег form, input и прилежащие к ним атрибуты, вроде method, action и так далее.
Парсинг списка композиций
Код имеет похожую структуру и приведен ниже.
class TrackSearch(HTMLParser): def __init__(self): HTMLParser.__init__(self) self.url = None self.params = {} self.in_form = False self.form_parsed = False self.method = "GET" def handle_starttag(self, tag, attrs): if self.url == None or len(self.url) < 10: tag = tag.lower() if tag == "input": attrs = dict((name.lower(), value) for name, value in attrs) if attrs["type"] == "hidden": self.url = attrs["value"]
Думаю, ничего сложного здесь нет. Класс парсит список в поисках первой композиции в начале списка — самый релевантный вариант — и сохраняет ссылку на неё в self.url. Проверка len(self.url) < 10 нужна лишь для того, чтобы отсеять первые два input, необходимые для функционирования поиска VK.
Интерфейс и вызовы
Конечно, классов, указанных выше, недостаточно. Чтобы успешно авторизоваться, необходимо правильно обработать cookie. На помощь приходит urllib.request и http.cookiejar. Создаем обработчик.
opener = urllib.request.build_opener( urllib.request.HTTPCookieProcessor(http.cookiejar.CookieJar()), urllib.request.HTTPRedirectHandler())
Теперь, когда других препятствий нет, мы можем начать.
#Сбор необходимой информации print("VK Music Downloader") login = input("Телефон или email > ") password = input("Пароль > ") track = input("Исполнитель и название композиции > ") filename = track + ".mp3" track = urllib.parse.quote(track) #Авторизация print("Авторизация...") parser = FormParser() response = str(opener.open("http://m.vk.com/").read()) parser.feed(response) parser.params["email"] = login parser.params["pass"] = password response = opener.open(parser.url, urllib.parse.urlencode(parser.params).encode()) parser.close() #Поиск print("Поиск композиции...") response = str(opener.open("http://m.vk.com/audio?act=search&q=%s" % track).read()) seacher = TrackSearch() seacher.feed(response) #Загрузка print("Загрузка > %s" % filename) with urllib.request.urlopen(seacher.url) as data, \ open(filename, 'wb') as fout: fout.write(data.read()) seacher.close() input("Загрузка завершена")
Заключение
Пример работы скрипта.
На этом мой первый пост заканчивается. Спасибо тем, кто уделил время, чтобы просмотреть его. Если у Вас появились вопросы, я с радостью отвечу. Всего доброго.
ссылка на оригинал статьи http://habrahabr.ru/post/215377/
Добавить комментарий