ВКонтакте многими нелюбим, однако он предоставляет замечательное и стабильное хранилище музыки. В рамках описываемого ниже скрипта мы научимся скачивать оттуда песню по названию, парсить чарты радиостанций и паковать скачанные нами песни в 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