Алексей Качаев | Web-developer, фрилансер, менеджер

PHP, jQuery, AJAX, CodeIgniter, ZendFramework, Web2.0, блоггинг, Wordpress, бизнес, StartUp, Инветоры, web-проекты, бизнес-идеи, фриланс, интерфейсы

jQuery + Ajax - парсим PR в несколько потоков

Опубликовано: Алексей Качаев |

Алексей Качаев. jQuery + AjaxСегодня выкладываю один интересный кейс по веб-программированию (давненько я этого не делал).

Суть дела: все знают, что ассинхронные запросы на сервер это очень модно. Типичный пример: сервис Блосье.ру. Мы вводим адрес блога, нажимаем на стрелочку, и в ответ страница дает ОЧЕНЬ МНОГО запросов на сервер, каждый из которых выполняется отдельно.

Там Ajax реализован с помощью Prototype и суть сводиться к тому, что мы к отдельному слою (div) с определенным идентификатором “привязываем” свой поток.

Мой кейс: как реализовать подобное “многопоточное” приложение, если заранее неизвестно количество потоков? Давайте более конкретизируем задачу:

пользователь вводит в TEXTAREA несколько URL, по одной на каждой строке. Нажимает на кнопку/ссылку, скрипт не перегружая (!) страницу создает список, состоящий из адресов. К каждому элементу списка присоединяется поток, который парсит PageRank и в случае успеха выводит рядом с адресом.

Вот такая, с виду незатейливая задача. Я привык работать с jQuery и для того, чтобы ее реализовать мне понадобилось два вечера. :) То ли просто запутался, то ли задача действительно не из тривиальных… Информации или туториала с подобным содержанием я не нашел… В любом случае привожу свое решение.

Результат вы можете увидеть здесь: jQuery + Ajax - парсим PR в несколько потоков.

Алексей Качаев. Использование jQuery

Ознакомились с примером? Давайте теперь пошагово проанализируем, что здесь происходит.

Шаг 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-ленту.!

Также читайте по теме:

9 комментариев на “jQuery + Ajax - парсим PR в несколько потоков”

  1. Есть http://i.pr-cy.ru/, у которого уже все есть - +ТИЦ и счетчик лиру. Но для личного пользования неплохо, если особенно совместить с библиотекой Жилинского, у которого уже есть массовая проверка.

  2. Собственно, сам парсинг PR не критичен :) Это как пример того, что можно делать. Главная задача была организовать “красивое” выполнение нескольких потоков, когда их количество и сущность заранее не известна.

  3. Да, оптимизация AJAX неплохая.

  4. Было бы еще неплохо выложить код php скрипта :)

  5. 2Devaka:

    Собственно, заметка не этому была посвящена, хотя заявку принял :)
    У меня уже очень много по парсингу материалов подобралось, поэтому я обязательно выложу как нибудь коллекцию скриптов для парсинга различных фишек.

  6. Хорошая статья ! Простое решение интересной задачи !

    Алексей, хочу уточнить такую деталь: запросы выполняются в мультипоточном режиме (или в виде его эмуляции) или же все запросы выполняются последовательно ?
    И отслеживает ли jquery ограничения браузеров на число одновременных ajax запросов (в IE кажется не более 2 по дефолту) ?

  7. наверное в меня сейчас будут кидаться камнями )
    Алексей, понимаю что заметка посвящена другому, но чтобы уж код был совсем оптимизированный - надо бы

    for (i=0; i <= urls.length-1; i++)

    в обоих циклах заменить “urls.length-1″ на какуюнить переменную, предварительно присвоив ей это значение, это одно из золотых правил, и Вы его наверняка знаете )

    иначе при каждой итерации цикла будет выполнятся urls.length-1… не фатально, но при больших проектах если не обращать внимание на такие мелочи - скорость работы может резко снизиться

    зы.статейка понравилась )

  8. Хотелось бы найти толковый парсер PR, к сожалению, много перелопатил но ничего не нашел толкового. МОжет кто поделится рабочим скриптом?

  9. удали плз мой предыдущий ответ вместе с этим - домен урод какойто перекупил, не хочу чтобы ссылка с моего ника на него вела =(

Оставьте комментарий