ВКонтакте многими нелюбим, однако он предоставляет замечательное и стабильное хранилище музыки. В рамках описываемого ниже скрипта мы научимся скачивать оттуда песню по названию, парсить чарты радиостанций и паковать скачанные нами песни в zip-архив. Песни будут пронумерованы согласно месту в чарте, и 100 песен обычно легко влазят на компакт-диск — автомобилистам понравится.
Также в одной из главных ролей сайт moskva.fm, заботливо собравший в одном месте список большого числа радиостанций с чартами. Все очень тривиально, но думаю многим начинающим программистам будет интересно.
Скрин того, что получилось:

По щелчку по логотипу происходит скачивание свежего zip-архива топ100 этой станции, содержащего файлы в mp3 формате.
Итак, пойдем от меньшего к большего:
Проект SimpleHTMLDOM — это неприхотливый аналог SimplyXML и других библиотек работы с HTML/DOM. Отличительные особенности: писал китаец, что видно по названию, абсолютно плюет на ошибки в разметке, пытаясь разбирать файл как получится; падает в segmentation fault после пары использований; люто ест память, т.к. для каждого узла хранит в самом же объекте родителей и детей, внутренности можно наглядно посмотреть выведя через print_r объект, также есть небольшие, сразу незаметные, но очень крутые штуки, например, можно искать по отрицательным индексам, т.е. если нам нужно получить третий с конца страницы div, то никаких трудностей нам это не составит.
Пойдем дальше — напишем функцию, которая будет получать песню по названию и сохранять в определенном нами месте.
Подборка логотипов с указанием московской частоты cтанций + красивая png
Также в одной из главных ролей сайт moskva.fm, заботливо собравший в одном месте список большого числа радиостанций с чартами. Все очень тривиально, но думаю многим начинающим программистам будет интересно.
Скрин того, что получилось:

По щелчку по логотипу происходит скачивание свежего zip-архива топ100 этой станции, содержащего файлы в mp3 формате.
Итак, пойдем от меньшего к большего:
error_reporting(E_ALL); //мы будем использовать проект simplehtmldom include_once('simplydom.php'); //100 файлов х 50 станций = 5000 файлов //поэтому ставим тайм-лимит 9000 set_time_limit(9000);
Проект SimpleHTMLDOM — это неприхотливый аналог SimplyXML и других библиотек работы с HTML/DOM. Отличительные особенности: писал китаец, что видно по названию, абсолютно плюет на ошибки в разметке, пытаясь разбирать файл как получится; падает в segmentation fault после пары использований; люто ест память, т.к. для каждого узла хранит в самом же объекте родителей и детей, внутренности можно наглядно посмотреть выведя через print_r объект, также есть небольшие, сразу незаметные, но очень крутые штуки, например, можно искать по отрицательным индексам, т.е. если нам нужно получить третий с конца страницы div, то никаких трудностей нам это не составит.
Пойдем дальше — напишем функцию, которая будет получать песню по названию и сохранять в определенном нами месте.
/* * функция получает на входе название или часть названия песни $title * ищет эту песню и скачивает в папку $path, * сохраняя в файл с названием "$number $title.mp3" */ function getSongByTitle($title,$path,$number) { // вконтакте требует наличие UserAgent $user_agent = 'Mozilla/5.0 (Windows; U; Windows NT 6.0; ru; rv:1.9.2.13)'; $cookie = ''; // наши данные для доступа $login = '*******@gmail.com'; $password = '********'; //инициализируем cURL $ch = curl_init(); //мы будем слать POST запрос curl_setopt($ch, CURLOPT_POST, true); //установим UserAgent curl_setopt($ch, CURLOPT_USERAGENT, $user_agent); //нам не нужно выводить на экран результат запроса //мы будем его использовать для получения ссылки на скачивание curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); //установим таймаут в рамках разумного curl_setopt($ch, CURLOPT_TIMEOUT, 10); //если вдруг нам отдадут Location: ... curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); //и собственно куда мы будем слать наш запрос curl_setopt($ch, CURLOPT_URL, 'http://login.vk.com/?act=login'); //формируем POST-запрос $post = array( 'act' => 'login', 'q' => '', 'al_frame' => '1', 'expire' => '', 'captcha_sid' => '', 'captcha_key' => '', 'from_host' => 'vkontakte.ru', 'email' => $login, 'pass' => $password ); curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($post)); //действуем $answer = curl_exec($ch); //самое главное - получаем вконтактовскую сессию $sid = substr($answer, strpos($answer, "setCookieEx('sid', '") + 20, 60); $cookie = 'remixsid=' . $sid; //теперь мы будем делать GET curl_setopt($ch, CURLOPT_POST, false); //используем cookie curl_setopt($ch, CURLOPT_COOKIE, $cookie); //новый URL curl_setopt($ch, CURLOPT_URL, 'http://vkontakte.ru/al_search.php?al=1&c[q]='.urlencode($title).'&c[section]=audio'); //получаем страничку поиска песни $answer = curl_exec($ch); curl_close($ch); //вконтакте отдает и не совсем json и не совсем html //ну в общем было решено сделать так $answer = substr($answer,strpos($answer,'{"section":"audio"')); $answer = substr($answer,strpos($answer,'<!> ')+4); $answer = trim($answer); //если вдруг мы уже скачали файл, то ничего не делаем if (!file_exists($path . $number . ' ' . $title . '.mp3')) { if (strpos($answer,'По Вашему запросу не найдено популярных результатов')==false) { //используем библиотеку simplydom, $html = str_get_html($answer); //ищем первый же input, в 99% случаев это //самая нормальная и качественная версия $filelink = $html->find('input',0)->attr['value']; //ссылка на песню находится в формате http://....mp3,bitrate //если кто-то хочет - может дополнительно использовать bitrate $filelink = explode(",",$filelink); $filelink = $filelink[0]; echo "Пытаюсь получить песню $filelink \n"; $ch = curl_init(); //открываем файл для записи (выше мы проверили, что его нет) $fp = fopen($path . $number . ' ' . $title . '.mp3', 'w'); //мы получаем ответ от cURL непосредственно в файл curl_setopt($ch, CURLOPT_FILE, $fp); curl_setopt($ch, CURLOPT_USERAGENT, $user_agent); curl_setopt($ch, CURLOPT_URL, $filelink); curl_setopt($ch, CURLOPT_COOKIE, $cookie); $answer = curl_exec($ch); fclose($fp); echo "Получил песню $filelink \n"; //если не сделать очистку, то после пары песен PHP выдаст seg.fault $html->clear(); unset($html); } else { echo "Песня не найдена\n"; } } } /* * функция создает zip-архив, получая на входе список файлов и папку назначения */ function create_zip($files = array(),$destination = '') { if(file_exists($destination)) { return false; } $valid_files = array(); if(is_array($files)) { foreach($files as $file) { if(file_exists($file)) { $valid_files[] = $file; } } } if(count($valid_files)) { $zip = new ZipArchive(); if($zip->open($destination,ZIPARCHIVE::CREATE) !== true) { return false; } foreach($valid_files as $file) { $zip->addFile($file,$file); } $zip->close(); return file_exists($destination); } else { return false; } } $filename = array(); $filename[] = array('href'=>'http://www.moskva.fm/stations/FM_90.8/top100','fm'=>'90_8'); // тут длинный список станций, с которых мы будем получать чарты //можно взять список с любого другого сборника чартов и настроить парсинг $filename[] = array('href'=>'http://www.moskva.fm/stations/FM_101.2/top100','fm'=>'101_2'); foreach ($filename as $item) { //всё как и раньше - получаем страничку с чартом $user_agent = 'Mozilla/5.0 (Windows; U; Windows NT 6.0; ru; rv:1.9.2.13) Gecko/20101203'; $ch = curl_init(); curl_setopt($ch, CURLOPT_USERAGENT, $user_agent); curl_setopt($ch, CURLOPT_URL, $item['href']); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); $answer = curl_exec($ch); $answer = trim($answer); curl_close($ch); echo 'Получил чарт станции' . $item['href'] . ' '; $html = str_get_html($answer); //в $filesarray мы будем хранить список файлов в виде абсолютных путей к ним $filesarray = array(); for ($i = 0; $i < 100; $i++) { echo '----' . $i . '-------- '; $song = $html->find('td[class=name] p a[class=song]', $i)->innertext; $artist = $html->find('td[class=name] p a[class=artist]', $i)->innertext; $fullsongname = $artist . ' - ' . $song; echo 'Скачиваю песню ' . $i . ' ' . $fullsongname . "\n"; if (!is_dir($_SERVER['DOCUMENT_ROOT'].'/mp3/'.$item['fm'])) { mkdir($_SERVER['DOCUMENT_ROOT'].'/mp3/'.$item['fm'],0755); } //это сделано для того, чтобы на всех автомагнитолах после записи диска //песни располагались по порядку их следования в чарте if ($i+1<10) { $number = '0'.$i+1; } else { $number = $i+1; } //скачиваем песню getSongByTitle($fullsongname,$_SERVER['DOCUMENT_ROOT'].'/mp3/'.$item['fm'].'/',$number); //и добавляем полученный файл в массив $filesarray[] = $_SERVER['DOCUMENT_ROOT'].'/mp3/'.$item['fm'].'/' . $number . ' ' . $fullsongname . '.mp3'; echo "Скачал песню\n"; } if (!is_dir($_SERVER['DOCUMENT_ROOT'].'/zip')) { mkdir($_SERVER['DOCUMENT_ROOT'].'/zip',0755); } //пакуем в архив для удобной скачки create_zip($filesarray,$_SERVER['DOCUMENT_ROOT'].'/mp3/zip/'.$item['fm'].'.zip'); //если не сделать очистку, то после пары песен PHP выдаст seg.fault $html->clear(); unset($html); }
Подборка логотипов с указанием московской частоты cтанций + красивая png