Разбор сайта Python + Grab

Разбор сайта Python + Grab

Всем привет! Давно наша команда ничего не писала в блог. Сейчас правила и стиль написания немного упростятся, поэтому мы планируем написать еще много мелких, но интересных публикаций в ближайшем будущем. Сегодня я хочу рассказать вам об одной из самых интересных тем — парсинг сайтов. Делать мы это будем на моем любимом скриптовом языке Python. Заинтересовавшихся прошу под кат.

Предистория

Очень давно мой хороший друг (автор игры Sunset, привет GameDev. ru!) сбросил мне ссылку на довольно известный сайт игрового журнала Kanobu. Суть записи блога в том, что некий уважаемый Amatsu опубликовал свой плейлист музыки во встроенном плеере. Вся прелесть даного события в том, что в списке находятся музыкальные компоизиции из лучших игр. Давно известен тот факт, что фильмы и игры часто используют очень хорошую музыку (много авторов стали популярными благодаря этому).

Первым делом я начал искать кнопку "Скачать все". Плеер не очень удобный да и проще манипулировать файлами уже у себя на компьютере. В комментариях я наблюдал ту же картину: много кто пытался сделать то же, что и я.

Но мы же с вами, уважаемые друзья, программисты, а, значит, всесильны :) Во всяком случае в тех частях нашего мира, которые относятся к компьютерам.

Рассмотр площадки

Первым делом, я начал смотреть структуру плеера в html-разметке. Благо, в вебките (google chrome) есть отличный встроенный "дебаггер" страниц. Правая кнопка на нужном нам элементе и "Inspect Element".

Первым делом, порадуемся, что структура плеера очень проста, а ссылки на mp3-файлы прямые :).

Весь плеер заключался между блоком с id="musiclist". Далее идет еще один блок-враппер с многообщеющим классом "items". Ну а далее самое интересное: a-блоки, каждый из которых содержит ровно одну запись песни в плейлисте.

На скрине я выделил один развернутый блок песни. Следующий выделенны блок просто показывает очередную запись.

Описание работы

Теперь все наше задание сводится к получению дочерних а-блоков указанного выше родительского div'a. Информация, которую нам надо распарсить из каждого a-блока/записи в плейлисте: путь к mp3-файлу (href-аттрибут главного а-блока)

Автор и название песни

Инструменты

Как я уже упоминал, мы будем использовать python. Для получения страницы и ее парсинга я выбрал библиотеку Grab (давно хотел попробовать ее в действии). Автор давненько уже описал ее на хабрахабре (http://habrahabr. ru/post/127584/). Это просто обертка над urllib. Для скачивания музыки по прямым ссылкам я выбрал gnu-утилиту wget.

May the force be with you

Первым делом, импортируем нужные нам библиотеки: from grab import * import re, os re — регулярные выражения (Да-да, все мы помним, что парсить dom-дерево регулярными выражениями — зло) os — поможет нам запустить внешний процесс (в нашем случае — wget)

Давайте же получим код странички, над которой будет проводиться операция g = Grab(log_file='result. html') g. go('http://kanobu. ru/blog/id101135/') html = g. response. body

Первой строкой создаем Grab-объект. Аргументом я указал имя файла, в который запишется все полученное содержимое страницы (для дебага). Далее, собственно, идет загрузка страницы из всемирной сети. В последней же мы сохраняем body (т. е. тело) ответа, в котором и находится основной html-код, нужный нам (который мы видели на первом скрине).

Воруем информацию

Внимание! Тот, кто парсит dom-дерево регулярными выражениями попадает под действие уголовного кодекса. В будущем, я бы посоветовал вам использовать прекрасную библиотеку BeautifulSoup, о которой уже не раз писал в этом блоге.

Самое интересное, наверное, вытащить сам адрес песни, расположенной на серварах Kanobu. Смотрим на любой адрес: http://audio. kanobu. ru/****/**/**/****.mp3?***

Первым делом, я поиском по всей странице проверил ключевые слова audio. kanobu. Этот адрес используется только в плеере, именно поэтому я рискнул использовать регулярные выражения: mp3List = re. findall(r'http://audio. kanobu. ru/.*mp3', html) print mp3List[0] # Debug only

Не думаю, что стоит в этой маленькой и никому ненужной статье описывать принципы работы регулярных выражений, об этом написано кучу книг. Поэтому я ограничусь тем, что комбинация '.*'. указывает на то, что после 'kanobu. ru/' и перед 'mp3' есть неограниченное количество символов.

Вторая строка выводит нам первую найденную запись. Например: http://audio. kanobu. ru/2010/08/06/509a2de7-711d-45e6-a2b8-2bd869ada7ab/35-blurry. mp3

Excellent!

Да тыквится имя твое!

Теперь осталось только узнать связку Автор и Название песни, продолжаем преступление, испольуем регулярные выражения: titleList = re. findall(r'width=\"24\"\ height=\"24\"\ alt=\"(.*)\"\ title', html); print titleList[0] # Debug only!

Я подумал, что проще всего вытащить название из img-блока, у которого в alt-аттрибуте и прописано полное название трека его автора.

Вторая строка вывела:

Blurry (Ace Combat 5: The Unsung War) - Puddle of Mudd

Осталось только загрузить каждую песню по адресу из массива 'mp3List', используя имена из 'titleList'.

До того, как показать весь оставшийся код, расскажу о wget:

Для загрузки нужно просто передать первым аргументом любой правильный адрес. Для указания имени файла, при сохранении на жесткий диск, нужно задать аргумент '-O FILENAME'.

Print 'Start downloading...\n' for i in range(len(titleList)): address = mp3List[i] # Берем адрес песни title = titleList[i] # И ее название (по тому же индексу)

# Сохраняем песню в папку Music с вытащенным именем и расширением mp3 os. system('wget ' + address + ' - O "Music/' + title + '.mp3"') print title + ' Is downloaded!\n'

Пример того же кода от Александра, но используя библиотеку BeautifulSoup: from grab import * from bs4 import BeautifulSoup import os music_folder = os. path. join(os. path. expanduser('~'), 'Music', 'Kanobu') g = Grab(log_file='result. html') g. go('http://kanobu. ru/blog/id101135/') html_doc = g. response. body soup = BeautifulSoup(html_doc) music_div = soup. find("div", "clips musicplayer items") for link in music_div. select('a[href^="http://audio. kanobu. ru/"]'): url = link['href'] author = link. u.string title = link. strong. string

# print "%s -- %s : %s" % (author, title, url) os. system('wget %s - O "%s/%s - %s. mp3"' % (url, music_folder, author, title)) print "[ok] ... %s\n" % title


Карта сайта


Информационный сайт Webavtocat.ru