jQuery + Ajax - парсим PR в несколько потоков
Сегодня выкладываю один интересный кейс по веб-программированию (давненько я этого не делал).
Суть дела: все знают, что ассинхронные запросы на сервер это очень модно. Типичный пример: сервис Блосье.ру. Мы вводим адрес блога, нажимаем на стрелочку, и в ответ страница дает ОЧЕНЬ МНОГО запросов на сервер, каждый из которых выполняется отдельно.
Там Ajax реализован с помощью Prototype и суть сводиться к тому, что мы к отдельному слою (div) с определенным идентификатором “привязываем” свой поток.
Мой кейс: как реализовать подобное “многопоточное” приложение, если заранее неизвестно количество потоков? Давайте более конкретизируем задачу:
пользователь вводит в TEXTAREA несколько URL, по одной на каждой строке. Нажимает на кнопку/ссылку, скрипт не перегружая (!) страницу создает список, состоящий из адресов. К каждому элементу списка присоединяется поток, который парсит PageRank и в случае успеха выводит рядом с адресом.
Вот такая, с виду незатейливая задача. Я привык работать с jQuery и для того, чтобы ее реализовать мне понадобилось два вечера.
То ли просто запутался, то ли задача действительно не из тривиальных… Информации или туториала с подобным содержанием я не нашел… В любом случае привожу свое решение.
Результат вы можете увидеть здесь: jQuery + Ajax - парсим PR в несколько потоков.

Ознакомились с примером? Давайте теперь пошагово проанализируем, что здесь происходит.
Шаг 1. Структура документа
Собственно подключаем jQuery и формируем необходимую нам CSS структуру документа. Значимые элементы на странице: textarea с id=”url” - отсюда мы будем брать адреса, ссылка классом “calculate” - к клику по ней мы “привяжем” основной обработчик. Ну и слой class=”result”, который будет заполняться списком. Также укажу заранее, что список будет содержать слой class=”loading”, где будет помещена модная анимация. Это слой должен быть изначально скрыт на странице, поэтому в css не забываем указать display: none;
Шаг 2. Обработчик клика “Узнать PR”
Итак, вешаем на ссылку “Узнать PR” следующую функцию:
<script type="text/javascript"> $(document).ready(function(){ $(".calculate").click(function (){ $(".result").html('<ul></ul>') var i; var urls = $('#url').val().split(/\n/); for (i=0; i <= urls.length-1; i++){ $(".result ul").append("<li><img style='margin: 0 2px -4px 0;' src='http://www.kachayev.ru/price/images/m_url.png'><B>URL: "+urls[i]+"</B> <div class='loading' id='l_"+i+"'><img src='loading.gif'></div></li>"); } $("div.result").find('div').ajaxStart(function(){ $(this).show() return false; }); for(i=0; i <= urls.length-1; i++){ $.post( "pr.php", "url="+urls[i]+"&num="+i, function(data){ var ans = data.split(/\|/); $("#l_"+(ans[0])).html(ans[1]); $("#l_"+(ans[0])).show; } ); } }); }); </script>
Эта запись означает, что при клике на ссылку, выполниться указанная функция.
Первое действие:
$(".result").html('<ul></ul>');
Мы находим слой с классом “result” и заменяем его содержимое на пустой список. Это делается для того, чтобы была возможность несколько раз обрабатывать различные сайты не перегружая страницу.
Следующий участок кода
var urls = $('#url').val().split(/\n/); for (i=0; i <= urls.length-1; i++){ $(".result ul").append("<li><img style='margin: 0 2px -4px 0;' src='http://www.kachayev.ru/price/images/m_url.png'><B>URL: "+urls[i]+"</B> <div class='loading' id='l_"+i+"'><img src='loading.gif'></div></li>"); }
получает строку, введеную в текстовое поле и разбивает ее в массив построчно. Каждая иттерация цикла находит список ul в слое с классом “result” и добавляет (!) к нему новую строку - элемент списка с прописанным адресом (следующим из массива адресов) и слоем с атрибутами class=’loading’ и динамично изменяющимся id=’l_0′, id=’l_1′ и т.д. Единство класса дает нам возможность задать настройки всех этих слоев одной строкой css, а динамическая нумерация id - возможность к каждому привязать свой поток.
Шаг 3. Готовим пользователя - показываем, что процесс пошел
В ajax-страничках показывать анимированные load-bar это не только модно. Это еще и необходимо: иначе пользователь подумает, что после его запроса страничка просто “отморозилась” и уйдет. Мы тоже предупредим пользователя о том, что его запрос обрабатывается. Для этого отобразим сейчас скрытые div`ы, содержащие изображение вращающихся шариков. Ответственный за это следующий код:
$("div.result").find('div').ajaxStart(function(){ $(this).show() return false; });
Он привязывает к событию ajaxStart функцию, которая находит все div внутри div с классом “result” и отображает их.
Шаг 4. Куда давать запрос?
Запрос мы будем давать на специальный скрипт pr.php, который принимает post-протоколом следующие параметры:
- урл страницы, PR которой нужно подсчитать;
- номер div`а, в котором нужно вывести результат;
Ну первое понятно зачем :), а вот второе я использовал для того, чтобы “объяснить” функции, принимающей результат куда же этот результат нужно “вставить”. Другого решения просто не придумал. pr.php отдает в ответ строку вида “X|Y”, где X - номер слоя, Y - PR запрашиваемой страницы.
Думаю организовать pr.php не сложно. Дай бог, о парсинге PR в Инете пишут много. Если возникнуть проблеми с этим - стучите в аську, помогу
Шаг 5. Спрашиваем и отвечаем.
Теперь пришло время собственно сформировать ajax запрос(ы). В jQuery это организовать предельно просто:
for(i=0; i <= urls.length-1; i++){ $.post( "pr.php", "url="+urls[i]+"&num="+i, function(data){ var ans = data.split(/\|/); $("#l_"+(ans[0])).html(ans[1]); $("#l_"+(ans[0])).show; } ); }
Итак, каждая иттерация цикла отправляет post запрос на pr.php, передавая в качестве параметров URL для обработки и номер слоя, куда поместить результат. При успешном завершнеии, будет вызвана функция, которая получит в строку data html код ответа. Напомню, что формат ответа “X|Y”, поэтому мы делим ответ на две составляющие ans[0] и ans[1]. Ищем слой с соответсвующим id, записываем в него значение PR.
Шаг 6. Наслаждаемся результатом трудов своих.
Да-да, это просто жизненно необходимо :).
Креативной вам веб-разработки и легкого Ajaxa.
Спонсор поста: Лицензионный Kaspersky Internet Security 2009. Много очень полезных фишек для активного интернет пользователя, особенно радует возможность обеспечения безопасности работы в сетях Wi-Fi и VPN, предотвращение кражи данных, передаваемых через SSL-соединение и блокирование ссылок на фишинговые сайты (хотя с последним человечество будет бороться еще очень долго…).
Понравился пост? Будь в курсе последних событий: подпишись на RSS-ленту.!
Также читайте по теме:
- 10 октября

Есть http://i.pr-cy.ru/, у которого уже все есть - +ТИЦ и счетчик лиру. Но для личного пользования неплохо, если особенно совместить с библиотекой Жилинского, у которого уже есть массовая проверка.
Собственно, сам парсинг PR не критичен
Это как пример того, что можно делать. Главная задача была организовать “красивое” выполнение нескольких потоков, когда их количество и сущность заранее не известна.
Да, оптимизация AJAX неплохая.
Было бы еще неплохо выложить код php скрипта
2Devaka:
Собственно, заметка не этому была посвящена, хотя заявку принял
У меня уже очень много по парсингу материалов подобралось, поэтому я обязательно выложу как нибудь коллекцию скриптов для парсинга различных фишек.
Хорошая статья ! Простое решение интересной задачи !
Алексей, хочу уточнить такую деталь: запросы выполняются в мультипоточном режиме (или в виде его эмуляции) или же все запросы выполняются последовательно ?
И отслеживает ли jquery ограничения браузеров на число одновременных ajax запросов (в IE кажется не более 2 по дефолту) ?
наверное в меня сейчас будут кидаться камнями )
Алексей, понимаю что заметка посвящена другому, но чтобы уж код был совсем оптимизированный - надо бы
for (i=0; i <= urls.length-1; i++)
в обоих циклах заменить “urls.length-1″ на какуюнить переменную, предварительно присвоив ей это значение, это одно из золотых правил, и Вы его наверняка знаете )
иначе при каждой итерации цикла будет выполнятся urls.length-1… не фатально, но при больших проектах если не обращать внимание на такие мелочи - скорость работы может резко снизиться
зы.статейка понравилась )
Хотелось бы найти толковый парсер PR, к сожалению, много перелопатил но ничего не нашел толкового. МОжет кто поделится рабочим скриптом?
удали плз мой предыдущий ответ вместе с этим - домен урод какойто перекупил, не хочу чтобы ссылка с моего ника на него вела =(