Archive

Archive for the ‘HTTP’ Category

Автоматизация подписки на рассылку FeedBurner. Часть 3

March 9th, 2010 No comments

Заключительная часть трилогии о том, как взять feedburner’овскую капчу, заставить пользователя ввести её и подписать его на рассылку feedburner.

Часть 1, Часть 2

В этой статье разберем серверную часть программы – php-скрипт, задача которого обратиться к сервису feedburner, получить капчу, передать пользователю, принять расшифровку капчи от пользователя и передать feedburner. Я использовал ZendFramework, но в основном по мелочи.

Итак, весь скрипт состоит из двух больших блоков. Первый – для случая, когда мы только получаем капчу, второй – для случая, когда пользователь её уже расшифровал.

Когда мы обращаемся к фидбернеру в первый раз отрабатывает следующий скрипт:

$client = new Zend_Http_Client(/* здесь должна идти строка с адресом рассылки, которую генерирует feedburner */);
$client->setParameterPost(array(
	        'loc'  => 'ru_RU',
	        'uri'   => /* данные вашей рассылки */,
	        'email' => /* данные вашей рассылки */,
	    ));
$resp = $client->request('POST');	// выполняем POST запрос
$headers = $resp->getHeaders();
 
// меняем относительные пути на полные
$response =  str_replace('captcha?','http://feedburner.google.com/fb/a/captcha?', $resp);
$response =  str_replace('="/fb','="http://feedburner.google.com/fb', $response);
 
// В ответ на наш запрос feedburner генерирует форму
// для заполнения с рядом скрытых (hidden) полей.
// Значение этих полей нам нужно достать и отправить
// обратно фидбернеру при следующем обращении
// Здесь я опушу большую часть однотипных действий
$pos1 = strpos($response, 'action="');
$action = substr($response, $pos1 + 8);
$pos11 = strpos($action, '"');
$action = substr($action, 0, $pos11);
 
$pos1 = strpos($response, 'input type="hidden" name="uri"');
$uri = substr($response, $pos1 + 38);
$pos11 = strpos($uri, '"');
$uri = substr($uri, 0, $pos11);

А далее нам остается только сформировать собственный кусок кода HTML, который AJAX вернет клиенту:

<form>
	<input type="hidden" id="fbaction" name="fbaction" value=""/>
	<input type="hidden" id="fburi" name="fburi" value=""/>
	<input type="hidden" id="fbemail" name="fbemail" value=""/>
	<input type="hidden" id="fbtoken" name="fbtoken" value=""/>
	<input type="hidden" id="fbcookie" name="fbcookie" value=""/>
 
</form>

$action, $uri, $email, $token – то, что мы достали из кода, сгенерированного фидбернером. $headers[‘Set-cookie’] – куки которые, установил фидбернер, их также нужно передать.

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

// клиент для HTTP-запросов
$client = new Zend_Http_Client($action);
// устанавливаем параметры, которые получили в прошлый
// раз от фидбернера
$client->setParameterPost(array(
		'loc'  => 'ru_RU',
	        'token'  => $_GET['token'],
	        'uri'   => $_GET['uri'],
	        'captcha'   => $_GET['captcha'],
	        'email' => $_GET['email']
	    ));
// не забываем добавить куки
$cookie = Zend_Http_Cookie::fromString($_GET['cookie']);
$client->setCookie($cookie);
// делаем POST запрос к фидбернеру
$response = $client->request('POST');

Вот и все. В $response у нас попадет ответ от фидбернера. Он скажет, что, либо регистрация прошла успешно, либо мы неправильно ввели капчу, либо плохой e-mail и т.п. Я ничего лучше не придумал, как проверять полученный текст на наличие каких-то ключевых слов. Это, в общем-то, тривиальная задача.

Анализ трафика HTTP

February 9th, 2010 No comments

Продолжение серии статей об Интернет-ботах.

Часть 1, Часть 2, Часть 3

Когда вы набираете в браузере адрес URI, он делает примерно то же самое, что мы делали в предыдущей статье с помощью Telnet-клиента. Но отправляет больше заголовков. Например, информацию о нем самом, о версии вашей ОС, передает cookies при их наличии. При переходе по ссылке отправляется адрес, откуда пользователь пришел на сайт. Различных заголовков очень много и описывать их все здесь не имеет смысла.

Для создания программы, эмулирующей браузер (Интернет-бот), необходим тщательный анализ цепочки HTTP запросов браузера и ответов на них.

Средства анализа

Существуют различные средства анализа трафика. Можно, например, установить специальный сетевой драйвер-фильтр. Однако значительно проще воспользоваться плагином к браузеру. Мне нравится вот этот (для Firefox): Live HTTP Headers.

Итак, нужен плагин. Этот или другой, главное, чтобы он сканировал заголовки как запросов, так и ответов.

Запускаем его и вводим в браузере «www.ya.ru». Я вижу вот что:

http://ya.ru/
 
GET / HTTP/1.1
Host: ya.ru
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.0; ru; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: ru,en-us;q=0.7,en;q=0.3
Accept-Encoding: gzip,deflate
Accept-Charset: windows-1251,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
 
HTTP/1.x 200 OK
Server: nginx
Date: Mon, 25 Jan 2010 22:21:14 GMT
Content-Type: text/html; charset=utf-8
Last-Modified: Tue, 12 Jan 2010 15:29:03 GMT
Transfer-Encoding: chunked
Connection: keep-alive
Content-Encoding: gzip

Это стартовые строки и заголовки реального браузерного запроса и ответа ему. Здесь видно, что Firefox умеет принимать сжатый ответ, о чем сообщил серверу Яндекса. Тот это понял и прислал сообщение, упакованное методом gzip.

Отправка формы

Для примера, оставим комментарий на Свиттере.

К сожалению, большинство комментариев, посупающих на модерацию, именно такие :) Итак, подготавливаем форму, как на картинке, запускаем плагин мониторинга HTTP, нажимаем «Отправить».

Запрос:

POST /wp-comments-post.php HTTP/1.1
Host: svitter.ru
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.0; ru; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: ru,en-us;q=0.7,en;q=0.3
Accept-Encoding: gzip,deflate
Accept-Charset: windows-1251,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
Referer: http://svitter.ru/?p=378
Content-Type: application/x-www-form-urlencoded
Content-Length: 350
 
author=%D0%9E%D0%BA%D0%BD%D0%B0+%D0%9F%D0%92%D0%A5&email=x%40x.com&url=x.com&comment=%D0%9A%D1%83%D0%BF%D0%B8%D1%82%D1%8C+%D0%BE%D0%BA%D0%BD%D0%B0+%D0%9F%D0%92%D0%A5%2C+%D0%B4%D0%BE%D1%81%D1%82%D0%B0%D0%B2%D0%BA%D0%B0+%D0%BF%D0%BE+%D0%9C%D0%BE%D1%81%D0%BA%D0%B2%D0%B5&submit.x=54&submit.y=12&submit=Submit+Comment&comment_post_ID=378&comment_parent=0

Браузер отправляет запрос методом POST, передвая введенную нами информацию в теле сообщения. Оно имеет такой вид:

param1=value1&param2=value2&param3=value3

Где param1, param2, param3 – имена параметров, а value1, value2, value3 – их значения. Таких пар имя-значение может быть сколь угодно много. Пробелы браузер заменил на «+», кирилицу и прочие специальные символы на их коды вида %XX или %XX%YY (если символ кодируется двумя байтами).

author=%D0%9E%D0%BA%D0%BD%D0%B0+%D0%9F%D0%92%D0%A5&email=x%40x.com&url=x.com&comment=%D0%9A%D1%83%D0%BF%D0%B8%D1%82%D1%8C+%D0%BE%D0%BA%D0%BD%D0%B0+%D0%9F%D0%92%D0%A5%2C+%D0%B4%D0%BE%D1%81%D1%82%D0%B0%D0%B2%D0%BA%D0%B0+%D0%BF%D0%BE+%D0%9C%D0%BE%D1%81%D0%BA%D0%B2%D0%B5&submit.x=54&submit.y=12&submit=Submit+Comment&comment_post_ID=378&comment_parent=0

Следует читать как:

author=Окна ПВХ&
email=x@x.com&
url=x.com&
comment=Купить окна ПВХ, доставка по Москве&
submit.x=54&
submit.y=12&
submit=Submit+Comment&
comment_post_ID=378&
comment_parent=0

Вот так можно оставлять комментарии на Свиттере Telnet-клиентом. Просто добавьте воды введите нужные заголовки и тело запроса.

Ответ:

HTTP/1.x 302 Moved Temporarily
Via: 1.1 RGW
Connection: Keep-Alive
Proxy-Connection: Keep-Alive
Transfer-Encoding: chunked
Expires: Wed, 11 Jan 1984 05:00:00 GMT
Date: Tue, 26 Jan 2010 16:05:10 GMT
Location: http://svitter.ru/?p=378&cpage=1#comment-349
Content-Type: text/html
Server: nginx/0.7.62
Keep-Alive: timeout=20
Cache-Control: no-cache, must-revalidate, max-age=0
Pragma: no-cache
X-Powered-By: PHP/5.3.1
Set-Cookie: comment_author=%D0%9E%D0%BA%D0%BD%D0%B0+%D0%9F%D0%92%D0%A5; expires=Sat, 08-Jan-2011 21:25:10 GMT; path=/
Set-Cookie: comment_author_email=x%40x.com; expires=Sat, 08-Jan-2011 21:25:10 GMT; path=/
Set-Cookie: comment_author_url=http%3A%2F%2Fx.com; expires=Sat, 08-Jan-2011 21:25:10 GMT; path=/
Last-Modified: Tue, 26 Jan 2010 16:05:10 GMT

Стартовая строка ответа говорит о том, что надо сделать редирект, а заголовок Location поясняет, куда именно. Как правило, скрипт обработки запроса POST делает перенаправление. Во-первых, это легче запрограммировать, а, во-вторых, пользователь сможет безболезненно обновлять страницу (без предупреждений о том, что данные формы будут снова отправлены).

Обратите внимание на заголовки Set-Cookie. Таким образом сервер сообщает браузеру, что введенные автором коментария данные (имя, email и url) нужно сохранить в cookies. Благодаря этому, при отправке следующего комментария останется ввести лишь текст сообщения.

А что же делать, если для доступа к сайту необходима авторизация? Об этом я расскажу в следующей статье. (скоро)

Что важно знать о HTTP

January 28th, 2010 Comments off

Продолжение серии статей об Интернет-ботах.

Часть 1, Часть 2, Часть 3

HTTP (Hyper Text Transport Protocol) – это тот самый язык, на котором разговаривают браузеры с веб-серверами.

Самое важное о HTTP:

  • протокол предполагает наличие сервера и клиента (клиент посылает запрос «хочу страницу index.html», сервер отвечает «на тебе эту страницу, вот ее содержимое»)
  • это текстовый протокол (запросы и ответы имеют понятный человеку вид, их можно читать в обычном текстовом редакторе)
  • каждое сообщение состоит из стартовой строки, заголовков и тела (об этом подробнее дальше)

svideteli_osvidetelstvovanija

Перечисленные особенности делают HTTP очень простым и расширяемым. Например, когда возникла задача сохранять информацию на машине клиента, протокол переписывать не пришлось. Все что надо было сделать – добавть один новый заголовок запроса (Cookie) и один – ответа (Set-Cookie).

Ниже по тексту я буду предлагать вам делать разные вещи. Например, скачать Яндекс Telnet-клиентом. «Пощупав» HTTP своими руками, проще понять его принцип. Но можно и просто читать, специально для вас у меня припасены скриншоты :)

Минимальный HTTP запрос

Скачаем содержимое сайта www.ya.ru без браузера. Для этого подойдет Telnet-клиент, который наверняка есть в вашей ОС. Чтобы воспользоваться им в Windows, запустите интерпретатор командной строки (cmd.exe). Далее набирайте текст, как на картинке, и нажимайте Enter.

1

Появился пустой черный экран. Вводите:

GET / HTTP/1.1

Нажимайте Enter. Пусть вас не смущает, что ничего не отображается на экране. Продолжайте ввод:

Host: www.ya.ru

Нажимайте Enter дважды.

Это был HTTP-запрос. А вот и ответ:

2

Что же мы сделали:

  1. подключились к серверу ya.ru на 80-ый порт (стандартный для HTTP)
  2. отправили сообщение, состоящее из стартовой строки и одного заголовка
  3. получили ответ, состоящий из стартовой строки, семи заголовков и тела

В стартовой строке запроса необходимо указать HTTP метод, URI документа и версию HTTP. В заголовке Host – имя хоста. Это был минимальный запрос. Если что-нибудь убрать, сервер скажет «Bad request».

Ответ начинается со стартовой строки «HTTP/1.1 200 OK», что означает, что наш запрос обработан успешно. Нам присылают желанный документ, содержимое которого находится в теле HTTP ответа. Именно его мы увидим, если нажмем в браузере кнопку «Исходный код страницы». Из заголовков хотел бы обратить ваше внимание только на Content-Length – здесь указан размер тела сообщения в байтах.

Пустая строка означает, что заголовки закончились и начинается тело сообщения. Именно поэтому мы нажимали Enter дважды в конце запроса.

Методы HTTP

Стартовая строка запроса начинается с названия метода, то есть имени основной операции, производимой над ресурсом.

Основные методы:

  • GET – используется при наборе адреса вручную или переходе по ссылке
  • POST – используется при отправке формы

Думаю, что распределение частоты запросов примерно такое:

  • 99.9% – GET
  • 0.1% – POST (читают Интернет намного чаще, чем пишут)
  • 0% – другие методы (имеют скорее историческую ценность)

Примечание: не стоит воспринимать эти цифры буквально.

При обращении к серверному скрипту обычно передаются параметры запроса. Например, URI http://svitter.ru/?p=621 означает, что я хочу прочитать статью #621. Методом GET можно передать парамтеры только через URI. С помощью POST их можно передавать как через URI, так и в теле сообщения.

В следующей статье я напишу, как анализировать HTTP трафик. Это необходимо для создания программы, эмулирующей браузер (ведь нам нужен Интернет-бот, помните? :) ).