Поиск по блогу

четверг, 23 апреля 2009 г.

Чем можно посмотреть HTTP запросы?

Снифферы нужны для просмотра/изменения заголовков HTTP-запросов.

Решила не делать полномасштабный обзор снифферов, так как в жизни пользовалась всего тремя разными программами (а этого явно недостаточно, чтобы давать советы, что именно использовать). Вы можете найти их в интернете. Естественно, перед запуском проверьте на вирусы :)

Расскажу о том, чем я в последнее время предпочитаю просматривать запросы.

LiveHTTPHeaders — это плагин для Firefox, который позоляет просматривать GET/POST запросы. Он удобен тем, что всегда доступен из моего любимого браузера. :) Чтобы начать просматривать заголовки, достаточно установить его и запустить из главного меню: "Инструменты — Просмотр HTTP заголовков".



Дальше вы просто загружаете страницы в фаерфоксе, а все запросы логируются в LiveHTTPHeaders.



Вывод результатов для просмотра можно настроить не в отдельном окне, а на боковой панели. Для этого надо нажать Ctrl+Shift-L или выбрать в меню "Вид — Боковая панель — LiveHTTPHeaders".

Чтобы быть в курсе обновлений блога, можно подписаться на RSS.

среда, 22 апреля 2009 г.

HTTP protocol, HTTP requests

Пусть вас не смущает заголовок на буржуйском. Просто блоггер.ком — хитрая штука, тут очень своеобразно и не очень гибко генерируются названия документов.
___

Раз уж я собралась писать статьи "от А", то сегодня поговорим на тему, с которой необходимо ознакомиться, прежде чем писать более-менее серьезные программы для работы с интернетом. Эта тема — протокол HTTP.

Часто возникают задачи, связанные с отправкой запроса на сервер и, соответственно, получением ответа от него. Например, отправка данных через форму. Можно, конечно, для этих целей использовать TWebBrowser (автоматизировать заполнение и отправку формы — элементарно, и механизм кукисов этим компонентом поддерживается), но это неэкономично и ресурсоемко. Именно поэтому я начала писать про Indy, а потом еще и про сокеты напишу. :) Но для работы с Indy надо иметь представление о формате обмена данными между клиентом и сервером. К этому и переходим.

Браузер и веб-сервер обмениваются данными по протоколу HTTP. Запрос по этому протоколу в общем виде состоит из указания метода запроса, заголовков (Header) и тела запроса.

Основные разновидности HTTP-запросов: GET, HEAD и POST.

GET-запрос
GET - означает "получить". С помощью GET-запроса мы можем получить содержимое какого-либо документа.
Когда наш браузер хочет получить содержимое странички, например, http://www.blogok.ru/2009/03/17/kak-zapretit-redaktirovanie-vyborochnyx-strok-v-cxgrid/, то он отправляет GET запрос, в котором указывает, что он хочет получить, откуда пользователь узнал об этой страничке (HTTP-REFERER) и кто посылает запрос (USER-AGENT).

Пример GET-запроса "из жизни":

GET /2009/03/17/kak-zapretit-redaktirovanie-vyborochnyx-strok-v-cxgrid/ HTTP/1.1
Host: www.blogok.ru
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.9.0.8) Gecko/2009032609 Firefox/3.0.8
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://www.blogok.ru/
Cookie: PHPSESSID=562b6b2d17e9207d1551922da511c156


Как видите, методом запроса является GET, протокол — HTTP 1.1. Все, что ниже, — заголовок. Помимо адреса страницы, содержимое которой браузер пытается получить, он передает в заголовке еще кучу всяких параметров. И далеко не все нам потом пригодятся. Имена и параметры заголовков разделены двоеточнием. А сам заголовок отделен от тела запроса двумя переводами строк.

Как видно из данного примера, браузер разбирает URL на "составляющие", а именно путь к файлу (Path='/2009/03/17/kak-zapretit-redaktirovanie-vyborochnyx-strok-v-cxgrid/') и имя сервера, к которому он обращаеться (Host='www.blogok.ru'). Referer — с какой страницы был осуществлен переход. User-Agent — "идентификация разновидности" браузера.

Если перевести заголовок запроса на условно-русский, то получается примерно:
"Я, User-Agent, пришел по рекомендации сервера Referer и хочу получить файл Path с сервера Host".

В поле Cookie браузер посылает свои кукисы.


HEAD-запрос
HEAD-запрос можно сравнить с "пингованием", т.е. посылкой пакета. И если сервер ответит, то он доступен. :) В принципе, для проверки доступности сервера он чаще всего и используется.

Пример HEAD-запроса:

HEAD /index.php HTTP/1.0
Host: www.blogok.ru


Тут все аналогично GET-запросу. Разница состоит в том, что на GET-запрос браузер получает ответ от сервера и содержимое документа, а на HEAD-запрос — только ответ сервера.

Ответ сервера снабжен кодом-идентификатором. Расшифровку этих кодов можно посмотреть в любой справочной документации.


POST-запрос
Возможности POST-запроса несколько шире. Это запрос на отправку данных. При помощи метода POST мы, например, можем передать данные после заполнения формы на сайте. Его синтаксис аналогичен синтаксису GET и HEAD заголовков, но от запроса GET он отличается тем, что вместо содержимого документа подаются параметры и значения. В POST-запросе необходимо указывать длину передаваемых данных (Content-Length), и тип передаваемых данных (Content-Type).

Пример — POST-запрос при логине в соцсети vkontakte.ru:

POST /login.php HTTP/1.1
Host: vkontakte.ru
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.9.0.3) Gecko/2008092417 AdCentriaIM/1.7 Firefox/3.0.3 WebMoney Advisor
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
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Referer: http://vkontakte.ru/
Content-Length: 69
Cookie: remixchk=5; remixautobookmark=6; remixlang=0
Pragma: no-cache
Cache-Control: no-cache
op=a_login_attempt&email=xxxxxx%40xxxxxx.ru&pass=xxxxxx&expire=0


Нам интересна последняя строка, в которой передается логин и пароль для авторизации на сайте.

Чтобы успешно залогиниться на сайте, надо не только уметь посылать "правильные запросы", но и правильно интерпретировать ответы сервера. Например, в ответ на посланный нами запрос, сервер вернет нам:

HTTP/1.x 200 OK
Server: nginx/0.6.31
Date: Wed, 08 Apr 2009 19:12:56 GMT
Content-Type: text/html; charset=windows-1251
Connection: keep-alive
Pragma: no-cache
Cache-Control: private, must-revalidate
Set-Cookie: remixmid=5704894; expires=Mon, 12-Apr-2010 11:43:08 GMT; path=/; domain=.vkontakte.ru
Set-Cookie: remixemail=xxxxxx%40xxxxxx.ru; expires=Wed, 31-Mar-2010 00:54:56 GMT; path=/; domain=.vkontakte.ru
Set-Cookie: remixpass=34b46332c9cedb25211e8e7155c510a8; expires=Fri, 09-Apr-2010 21:05:50 GMT; path=/; domain=.vkontakte.ru
Set-Cookie: remixsid=40cf323c0545f0f81a888bf4d8fdec94058faddf1e7b1d17396abd41; expires=Fri, 02-Apr-2010 08:35:11 GMT; path=/; domain=.vkontakte.ru
Content-Encoding: gzip
Vary: Accept-Encoding
Content-Length: 37


Тем самым в браузере, обращающемся к веб-серверу, устанавливаются определенные кукисы.

Пожалуй, на сегодня информации хватит. В следующих сериях смотрите:
- чем можно просмотреть HTTP-заголовки;
- пример использования компонентов Indy для авторизации на сайте.


Чтобы быть в курсе обновлений блога, можно подписаться на RSS.

четверг, 16 апреля 2009 г.

Особое внимание к кодам символов

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

Парсинг сайта с предложениями о работе. Заказчику парсера надо было, чтобы все "было визуально": загрузка страницы поиска, заполнение полей, сабмит формы. Что ж, без проблем.

Заполнила все поля, перехожу к выбору региона по названию из комбобокса (по value — не катит, надо по тексту). Картинка следующая:


На первый взгляд, все просто. Кажется, что можно значение текста в option-зе select-а обработать trim-ом, — и все будет хорошо. Итак, пишу процедурку выбора из селекта по тексту. На входе: текст итема, который надо выбрать и селект, в котором надо выбрать (поиск селекта осуществляется в другой процедуре, по нейму). На всякий случай еще привожу к верхнему регистру, чтобы уж наверняка.

procedure TMainF.SelectItemByTextFromSelectEl(TextStr: string;
SelectEl: IHTMLSelectElement);
var
i : integer;
iDisp : IDispatch;
iColl : IHTMLElementCollection;
iOption : IHTMLOptionElement;
sCity : string;
begin
iDisp := SelectEl.tags('OPTION');
iDisp.QueryInterface(IHTMLElementCollection, iColl);
if not Assigned(iColl) then
begin
ShowMessage('Not assigned!'); exit;
end;

i := 0;
while i <= iColl.length-1 do
begin
iDisp := iColl.item(i,0);
iDisp.QueryInterface(IHTMLOptionElement, iOption);
if Assigned(iOption) then
begin
sCity := AnsiUpperCase(trim(iOption.text));
if sCity = AnsiUpperCase(TextStr) then
begin
iOption.selected := true;
break;
end;
end;
inc(i);
end;
end;


Тестирую — не работает. Тестирую по шагам. Оказывается, что после trim-а строка не обрезается. Смотрим строку посимвольно: она в начале дополнена символами с кодом 160. Смотрим исходник trim-а: в нем обрезаются все символы с кодом до 32 включительно. В итоге — переписываем trim для себя:


function Trim2(const S: string): string;
var
I, L: Integer;
v : set of char;
begin
v:=[#0..#32];
include(v,#160);
L := Length(S);
I := 1;
while (I <= L) and (S[I] in v) do Inc(I);
if I > L then Result := '' else
begin
while S[L] in v do Dec(L);
Result := Copy(S, I, L - I + 1);
end;
end;


В итоге, если обнаружатся еще какие-нибудь символы, смахивающие на пробел и нуждающиеся в обрезке, — просто добавим их потом инклюдом в набор.

Чтобы быть в курсе обновлений блога, можно подписаться на RSS.

понедельник, 6 апреля 2009 г.

Как установить фокус на TWebBrowser (SetFocus не работает)

Статью-продолжение из цикла постов о работе с Indy еще не дописала. Так что сегодня хочу привести здесь один из "рецептов" для работы с компонентом TWebBrowser.

Как правило, при написании приложений всплывают какие-нибудь специфические вопросы. Эти вопросы легко решить с помощью интернета :) Вот, например, недавно, при отладке очередной программы обратила внимание, что не работает SetFocus применительно к объекту WebBrowser. Погуглила, нашла решение (даже 2).


{1}

uses
ActiveX;

begin
WebBrowser1.Navigate('irgendeinedatei.html');
with WebBrowser1 do
if Document <> nil then
with Application as IOleobject do
DoVerb(OLEIVERB_UIACTIVATE, nil, WebBrowser1, 0, Handle,
GetClientRect);
end;

{2}

uses
MSHTML;

begin
WebBrowser1.Navigate('irgendeinedatei.html');
repeat
Application.ProcessMessages;
until WebBrowser1.ReadyState >= READYSTATE_COMPLETE;
if WebBrowser1.Document <> nil then
(Webbrowser1.Document as IHTMLDocument2).ParentWindow.Focus;
end;


Выбрала второе, так как оно показалось мне более простым :) Однако, в нем обнаружился недостаток, который, видимо, не на всех формах можно обнаружить. У меня на форме в верхней части расположен грид, а в нижней - WebBrowser.

TWebBrowser setfocus

После установления фокуса на WebBrowser начинаю скроллить мышь над ним. Все идет гладко до тех пор, пока не достигается конец (или начало — в зависимости от того, в какую сторону скроллить) документа. После этого начинает скроллиться грид, который расположен над документом. Использование варианта под номером {1} устранило этот недочет.

Чтобы быть в курсе обновлений блога, можно подписаться на RSS.

Поделиться