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

вторник, 26 мая 2009 г.

Пример авторизации на сайте с помощью idHTTP.Post

Несмотря на то, что все мои заготовки статей канули в Лету вместе с другими данными (в том числе исходниками), которые были на флешке, я не пала духом и попытаюсь написать что-нибудь полезное заново.

Сегодня расскажу, как использовать idHTTP.Post для авторизации на сайте. Я возьму для примера сайт LiveJournal.com.

Немного теории для начинающих. Итак, вызов метода Post компонента idHTTP отличается от вызова Get-а только тем, что помимо URL-а необходимо передать параметры. Параметры можно передавать в виде StringList-а, или каких-нибудь Stream-ов, или чего-нибудь еще подходящего.)

Пример Post-процедуры (параметры передаются в виде StringList-а):

procedure TForm1.Button1Click(Sender: TObject);
var
LoginInfo: TStringList;
Response: TStringStream;
begin
try
LoginInfo := TStringList.Create;
Response := TStringStream.Create('');
LoginInfo.Add('username=MyName');
LoginInfo.Add('password=MyPass');
IdHTTP1.Post('http://mywebsite.xxx/login.php',LoginInfo,Response);
Showmessage(Response.DataString);
finally
begin
Response.Free;
LoginInfo.Free;
end;
end;
end;


Пример Post-функции (параметры передаются в виде IdMultiPartFormDataStream-а):

uses IdMultipartFormData;
{ .... }

procedure TForm1.Button1Click(Sender: TObject);
var
data: TIdMultiPartFormDataStream;
begin
data := TIdMultiPartFormDataStream.Create;
try
// добавляем нужные параметры
data.AddFormField('param1', 'value1');
data.AddFormField('param2', 'value2');
// для примера выводим в мемо все, что вернулось
Memo1.Lines.Text := IdHTTP1.Post('http://localhost/script.php', data);
finally
data.Free;
end;
end;


Сейчас попробуем применить полученные знания. Идем на LiveJournal.com, включаем сниффер, логинимся на сайте и смотрим, какие параметры надо передавать ('mode=login', 'user=логин', 'password=пароль'). Авторизация не произойдет, если на стороне клиента не будут сохранены кукисы. Для сохранения кукисов среди компонентов Indy существует TidCookieManager. IdCookieManager подключается к idHTTP через свойство CookieManager.
idHttp.CookieManager := IdCookieManager;

В этом случае при запросах в заголовок добавляются кукисы, автоматически сохраненные в IdCookieManager. IdCookieManager можно найти на закладке Indy Misc или создать динамически.
idCookieManager

Поместим на форму 2 TEdit-а, TMemo и кнопку, на которую повесим следующий работающий код авторизации:

procedure TForm1.Button1Click(Sender: TObject);
var
Http : TidHttp;
CM : TidCookieManager;
Data : TStringList;
StrPage, UserID, UserName : String;
i : integer;
begin
try
Http := TIdHTTP.Create(Self);
Data := TStringList.Create;
CM := TidCookieManager.Create(Http);
Http.AllowCookies := true;
Http.CookieManager := CM;
Http.HandleRedirects := true;

Http.Request.Host:='livejournal.com';
Http.Request.UserAgent:='Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.9.0.10) Gecko/2009042316 Firefox/3.0.10';
Http.Request.Accept:='text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8';
Http.Request.AcceptLanguage:='ru,en-us;q=0.7,en;q=0.3';
Http.Request.AcceptCharSet:='windows-1251,utf-8;q=0.7,*;q=0.7';
Http.Request.Referer:='http://www.livejournal.com/';

Data.Add('mode=login');
Data.Add('user=' + Edit1.Text);
Data.Add('password=' + Edit2.Text);
StrPage := Http.Post('http://www.livejournal.com/login.bml?ret=1', Data);
finally
Data.Free;
CM.Free;
Http.Free;
end;

if Pos('<input class="logoutlj_hidden" id="user" name="user" type="hidden" value="'+Edit1.Text,StrPage) <> 0 then
ShowMessage('Авторизация прошла успешно')
else
ShowMessage('Авторизация провалилась');

Memo1.Lines.Text := StrPage;
end;


Возвращенные заголовки (после ответа сервера) можно посмотреть так:
idHttp.Response.RawHeaders.GetText;


Сохраненные в CookieManager-е кукисы можно посмотреть так:
for i := 0 to Http.CookieManager.CookieCollection.Count - 1 do
StrPage := StrPage + CM.CookieCollection.Items[i].CookieText + #13#10;


Вот что записал туда LiveJourmal.com:
Cookies LJ
Да, ЖЖ, мы тоже love you a lot :)
___

В качестве отступления от темы статьи делюсь ссылкой на сайт о программировании на Delphi для начинающих и не только.
___

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

вторник, 12 мая 2009 г.

Для начинающих работать с компонентом idHTTP в Delphi

Найти компонент idHTTP можно на вкладке Indy Clients.

idHTTP

После того, как поместите его на форму, посмотрите его параметры и свойства в Object Inspector-е. Вы увидите, что работать с протоколом HTTP с помощью этого компонента достаточно просто. Для "составления" правильных заголовков запросов к серверу будем плотно работать с TIdHTTP.Request. Многие поля вам уже знакомы (я упоминала о них в вводной статье о протоколе HTTP и HTTP-заголовках). Там же есть возможность привязки к объекту idHTTP компонента для удобной работы с кукисами (компонент idCookieManager) и настройка работы через прокси.

Рассмотрим способы отправки запросов Get и Post. С такими названиями существуют и функции, и процедуры. Я уже упоминала про Get в вводной статье об Indy. Непосредственно перед отправкой запроса следует настроить свойства вышеупомянутого IdHTTP.Request-а, если есть необходимость. Например, UserAgent в idHTTP по умолчанию Mozilla/3.0 (compatible; Indy Library), и, чтобы не палиться, следует его заменить на что-нибудь более безобидное :) А если вы создаете экземпляры компонента idHTTP динамически для парсинга страниц какого-нибудь большого сайта, то юзерагента можно вообще брать рандомом из заранее подготовленного списка.

Пример использования процедуры idHTTP.Get без дополнительных настроек:

var
mStream: TMemoryStream;

mStream := TMemoryStream.Create;
try
idHttp := TIdHTTP.Create(nil);
{ тут следует "настроить" параметры idHTTP }
{ ... }
try
idHttp.Get(URL, mStream);
finally
idHttp.Free;
end;
finally
mStream.Free;
end;


Или с помощью функции получить содержимое страницы в строковую переменную:

Str := idHttp.Get(URL);


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

Какие еще аспекты работы с idHTTP следует отметить?
После посылки запроса проверить ответ сервера можно, посмотрев содержимое свойства

idHTTP.Response.ResponseText


Стандартым ответом о том, что все прошло удачно, является HTTP/1.0 200 OK.

Бывают и другие ответы сервера (про коды ответов я упоминала в одной из предыдущих записей). Остановлю внимание только на двух наиболее часто встречающихся группах:
2хх: Успешно. Сигнал был успешно принят, понят и принят к обработке.
Зхх: Перемаршрутизация. Необходимо предпринять определенные действия, чтобы выполнить запрос.

Исключения, возникающие при работе компонентов Indy (тип EIdHTTPProtocolException), классифицируются особым образом.

Except
on E:EIdHTTPProtocolException do
ShowMessage(E.ErrorMessage);


Классификация исключений может пригодиться. У меня был случай, когда написанный парсер работал без проблем, но спустя какое-то время отказался работать. Помог анализ ответа сервера: на сайте временно поставили перенаправление (Код 302 Found: HTTP_FOUND — Запрошенный ресурс был временно перемещен на новый URI), возможность которого я в начальной версии не предусмотрела. С тех пор во всех своих парсерах я проверяю код ответа: не 302 ли случаем? (Если код ответа 301 (Moved Permanently: HTTP MOVED PERMANENTLY — Запрошенный документ был перенесен на новый URI), то информация берется без проблем, если у idHTTP свойство HandleRedirects := true, а вот с 302 это не прокатывает. Так же отдельно я обрабатываю код 404). Еще у компонента надо грамотно настроить все таймауты, чтобы, если обнаружится исключительная ситуация, запрос не "подвисал".

Пример кода для обработки исключений разного типа:
procedure TForm1.Button1Click(Sender: TObject);
begin
Memo1.Lines.Clear;
try
Memo1.Lines.Add(IdHTTP1.Get(Edit1.Text));
except on e : EIDHttpProtocolException do
Begin
if e.ErrorCode = 302 then
begin
try
// получаем новый адрес - адрес перенаправления
Memo1.lines.add(idhttp1.Get(IdHTTP1.Response.Location));
except on e:Exception do
// предусматриваем, что исключение может возникнуть и тут
ShowMessage('Ошибка при получении нового адреса.'+e.Message);
end;
end
else
//http 404, 501 и так далее
ShowMessage('Ошибка другого вида, не 302:'+e.Message);
end;
on e:Exception do
ShowMessage('Ошибка: ' + e.Message);
end;
end;



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

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

Поделиться