Search
Write a publication
Pull to refresh

Парсер аудио ВКонтакте PHP + phantomJS

Привет, Хабр! Представляю вашему вниманию свой скромный проект для парсинга аудио Вконтакте.
Так как слушать музыку напрямую вконтакте не круто и не всегда возможно/удобно, я подумал, что неплохо бы иметь возможность стягивать свой плэйлист и плэйлисты друзей. Недостатком тех программ, что я юзал, было то, что приходилось качать по одной песне. Если плэйлист большой, то это не удобно и жутко долго. От своего приложения я хотел, чтобы оно могло качать всё и сразу, и чтобы музыка сортировалась по исполнителям.

В начале я думал, что обойдусь cURL, но как оказалось, контакт хитёр и выгружает по умолчанию ~50 песен. Но об этом позже.

1. Авторизация ВК

Тут я особо не изворачивался. Для того, чтобы получить свой профиль ВК, просто прикручиваем свои кукисы. Кука, которая нам нужна, называется remixsid.



2. Получение контента страницы с помощью phantomJS

Скачать фантом можно отсюда. Для Linux версии достаточно его просто распаковать и добавить линк в /usr/bin (по желанию). О том, что это и с чем его едят, можете ознакомиться тут.
Как я уже говорил, контакт выгружает не весь список аудио по умолчанию. Он подгружает его динамически в процессе прокручивания окна. К тому времени как я решил подключить фантом, у меня уже была готовая структура для парсинга странички, написанная на php, поэтому я решил не переписывать это на js. Сам фантом здесь только проскролливает окно и отдает контент страницы.

        // return vk page content
        private function parseUrl($url) {
            // get remixsid value
            $sid = $this->RemixSid();
            // get scrolled page
            $command = 'phantomjs '.$_SERVER['DOCUMENT_ROOT'].'/js/phantom.vk.js' . " $sid $url";
            $response = shell_exec($command);
            return $response;
        }


Листинг
Листинг
/*
 * it must run from phantomjs
 * args[0] - remixsid cookie value
 * args[1] - target vk url
 */
var sys = require("system"),
    page = require("webpage").create();
    
phantom.addCookie({
    'name': 'remixsid',
    'value': phantom.args[0],
    'domain': 'vk.com'
});

page.settings = {
	loadImages: false,
	javascriptEnabled: true,
	userAgent: 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1',
};

page.open(phantom.args[1], function() {
    var tries = 0,
    t = setInterval(function() {
        page.scrollPosition = { top: page.scrollPosition.top + screen.height, left: 0 };
        ++tries;
            if (tries === 40) {            
                console.log(page.content);
                clearInterval(t);
                phantom.exit();           
            }
    },100);
});




Думаю, тут всё должно быть понятно. Объект page умеет работать с веб-страницами, передавать данные POST, GET, PUT, выполнять JS непосредственно в контексте открытой страницы и многое другое.

Внешние переменные доступны через массив args, глобального объекта phantom. На протяжении 4 секунд скрипт проскролливает страницу и отдает её контент page.content. Мне этого хватает, чтобы спарсить овер 2000+ песен.

Вывод в phantomJS осуществляется с помощью обычного console.log();

3. Парсим?

Если посмотреть исходный код странички, то мы найдем возле каждого трэка ссылку на поддомен vk.me, откуда собственно и загружаются аудиозаписи
image

Я не прикручивал библиотек для разбора html типа этой. А обошелся обычным регэкспом:
        public function actionDownload() 
        {   
            $data = '';
        // TODO: include html simple dom
$audioRegExp = '/<input[\s\S]+?id=["\']audio_info[_0-9]+["\'][\s\S]+?value=[\'"](.+?)[\'"][\s\S]+?<b>\s*<a.*?>(.+?)<\/a>[\s\S]+?<span\sclass=["\']title[\'"]>\s*?(?:<a.*?>)?(.+?)</i';
            $songs = array();
            
            if (isset($_POST['type'])) {
                switch ($_POST['type']) {
                    case 'link': {
                        $data = $this->parseUrl($_POST['target']);
                        break;
                    }
                    case 'file': {
                        if ($_FILES && $_FILES['target']) {
                            $file = $_FILES['target']['tmp_name'];
                            if (!empty($file))
                                $data = file_get_contents($file);
                        }                           
                        break;
                    }
                    default: {
                        throw new CHttpException(400,'неверный тип загружаемых данных');
                        break;
                    }
                }
                preg_match_all($audioRegExp, $data, $parse);
                $songs = self::serializeVkSongs($parse);
                
            }

           $this->render('download', array('songs' => $songs, 'count' => self::$songsCount)); 
            
        }


Кому интересно узреть всё и сразу: github.com/zjiodeu/vkMusicParser
Всем спасибо. Если есть вопросы — пишите, отвечу в комментах.

Спасибо за внимание.
Tags:
Hubs:
You can’t comment this publication because its author is not yet a full member of the community. You will be able to contact the author only after he or she has been invited by someone in the community. Until then, author’s username will be hidden by an alias.