Если нельзя, но очень хочется, то нужно обязательно и ничего в мире не стоит того, чтобы делать из этого проблему!


Интересна Java? Кликай по ссылке и изучай!
Если тебе полезно что-то из того, чем я делюсь в своем блоге - можешь поделиться своими деньгами со мной.
с пожеланием
столько времени читатели провели на блоге - 
сейчас онлайн - 

четверг, 15 марта 2012 г.

Как с помощью xpath вытянуть внутренности html странички?

Есть музычка, которую я постоянно слушаю, когда работаю. Об этом писал раньше. Так вот на сайте периодически (хоть и редко) меняются урлы серверов. Когда-то в далеком-далеком прошлом я все-пре-все сохранил в один плейлист, который долго мне служил. Но время прошло и теперь там ни один сервер не грузится. Помню в прошлом на создание этого плейлиста методом открывания каждой из пары десятков ссылок ушло пол часа. На этот раз я решил тех же пол часа инвестировать в эксперименты с xpath.

Итак нам понадобится плагин FirePath для Firefox. После установки этого плагина (и перезагрузке firefox) в окне debug появится вкладка FirePath. Отправимся на исходную страничку и наберем в FirePath следующий код:
//.[contains(text(),'AAC')]/..//a[contains(@href,'.pls')]/@href
После нажатия Enter получим что-то похоже на


Дальше скопируем все ссылки. Сделать это напрямую из FirePath не получилось, а потому пришлось немного извратом заняться. Что сделал? Сохранил исходную страничку на рабочий стол. Открыл в редакторе и вконец ее добавил следующий код.
<script src="http://dfn.dl.sourceforge.net/project/js-xpath/js-xpath/1.0.0/xpath.js" type="text/javascript">
</script>
<script type="text/javascript">
    window.onload = function() {
        // я немного переписал xpath выражение, потому как с помощью xpath.js оригинальный вариант не работал. 
        var xpath = "//.[contains(text(),'Download')]/.[contains(@href,'.pls')]/@href";
        var elements = document.evaluate(xpath, document, null, XPathResult.ANY_TYPE, null);

        function toString(iterator){
            var result = '';
            var item;
            while (item = iterator.iterateNext()){
                result += (item.nodeType == 1 ? item.innerHTML.replace(/</g, "<").replace(/>/g, ">") : item.nodeValue);
            }
            return result;            
        }      
        
        document.clear(); // W3C DOM очень не рекомендует использовать этот метод, но я рискнул
        document.write(toString(elements));        
    }
</script>
Текст примера и xpath.js взят с http://js-xpath.sourceforge.net/xpath-example.html

После стоило всего лишь перегрузить страничку и получить список линков, которые я вставил в текстовый файл и назвал его m3u, а когда тот открыл в winamp то был приятно удивлен - он все сам попарсил и загрузил каждый pls.


Очень приятно осознавать, что невозможного не бывает. Эксперименты заняли немного больше чем планировал - 50 минут. Но я кое в чем прокачался. Поди знай, где этот опыт пригодится.

Я попробовал обобщить код загрузки до такого.
<html>
<body>
<iframe id="iframe" src="http://blablabla.com"></iframe>
<script src="http://dfn.dl.sourceforge.net/project/js-xpath/js-xpath/1.0.0/xpath.js" type="text/javascript">
</script>
<script type="text/javascript">
    window.onload = function() {
        // я немного переписал xpath выражение, потому как с помощью xpath.js оригинальный вариант не работал. 
        var xpath = "//.[contains(text(),'Download')]/.[contains(@href,'.pls')]/@href";
          
        var iframe = document.getElementById("iframe").contentWindow.document;
        var elements = document.evaluate(xpath, iframe, null, XPathResult.ANY_TYPE, null);

        function toString(iterator){
            var result = '';
            var item;
            while (item = iterator.iterateNext()){
                result += (item.nodeType == 1 ? item.innerHTML.replace(/</g, "<").replace(/>/g, ">") : item.nodeValue) + "</br>";
            }
            return result;            
        }      
        
        document.clear(); // W3C DOM очень не рекомендует использовать этот метод, но я рискнул
        document.write(toString(elements));        
    }
</script>
</body>
</html>
Но в месте где я пытался получить document iframe я получал ошибку связанную судя по всему с авторскими правами. Это я понял когда наткнулся на комментарий "хватит пытаться взломать авторский контент" при гуглинге "iframe get document error". По этой причине я не стал выкладывать никаких оригинальных исходников, а всю информацию про сайт, с которого я доставал линки, скрыл. Код (html) в примерах - выдуман мной. А пост написан в целях демонстрации нового инструментария.

Есть у тебя есть информация, как обойти "iframe get document error" поделись в комментах. Я же не стал больше инвестировать в это времени, быть может когда-то в будущем... Поставленная задача была решена, но все же любопытно...

4 комментария:

  1. Для html больше подходить jquery и ее язык запросов sizzle, к тому же в FF и Chrome, можно это всё делать без самой jQuery, а использовать document.querySelectorAll():

    var matchElements = document.querySelectorAll('a[href$=".png"]');
    [].slice.apply(matchElements).map(function(x){return x.getAttribute('href')})

    ОтветитьУдалить
  2. А вообще у нас была написано два больших краулера, работающих на xpath, правда server-side.

    ОтветитьУдалить
  3. Проверил свой код - работает во всех соверменных браузерах: FF 10, IE 9, Opera 11.61, Chrome 17, Safari 5

    ОтветитьУдалить
  4. Саша, а можешь описать этот свой опыт с примерами у себя в блоге? Почитал бы с удовольствием.

    ОтветитьУдалить