Подписка

добавить на Яндекс

Наши проекты

Delphi+Google

Google API

Google API в Delphi - проект с открытым исходным кодом.

Chrono

Chrono

Хронометр - программа для ведения списка задач.

ODFProc

ODFProc

ODFProc - работа с документами OpenOffice в Lazarus и FreePascal.

Поддержка блога

А тут я коплю на лицензию Delphi XE на iPad =).
Сумма пожертвования не фиксирована.

Публикации

Год назад

Случайный пост

Последние

Сообщения форума

Комментарии

Свежие комментарии

Социальные сети

Google

Facebook

Twitter

Опрос

Вы сейчас или в ближайшем обозримом будущем планируете разрабатывать кроссплатформенное приложение с использованием Firemonkey?



Loading ... Loading ...

Блоги и сообщества

Статьи по Delphi DelphiFeeds.ru - Все Delphi-блоги Рунета Сообщество умных людей VR-Online.RU Бесплатный журнал для программистов и всех, кто интересуется IT Статьи и уроки по Delphi Новостной блог о высоких технологиях
Система Orphus
Опубликовал Vlad 24 января 2010 в 18:13.
Категории: Delphi в Web.


Тяжеловатая была неделька. Семь дней в работы, постоянные напряги, всё что-то кому-то надо...жесть. Но все когда-то заканчивается (слава богу, неделя кончилась) и сегодня решил запостить в блог новую статейку. И решил сделать этот пост, опять же, адресным - ответ на комментарий.

Цель сегодняшней работы: авторизоваться на сайте по https-протоколу с использованием библиотеки Synapse.

Суть проблемы: не проходит авторизация при использовании метода HTTPMethod(), не устанавливаются новые cookies и т.д.

Целевой сайт:  https://partner.r01.ru

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

1. Изучаем процесс авторизации

Первое, что я сделал - зарегистрировался на "проблемном" сайте и изучил подробно все запросы и заголовки запросов при авторизации.

В качестве просмотрщика заголовков использовался плагин к FireFox "Live Headers".

Заголовок сообщения при авторизации методом POST выглядит следующим образом:

Ответ сервера при успешной авторизации:

При неудачной авторизации редирект (302) не происходит, несмотря на то, что cookies всё равно устанавливаются.

Таким образом, для того, чтобы авторизоваться на сайте с использованием Synapse нам необходимо:

  1. Сформировать и отправить по протоколу https запрос
  2. Определить в заголовке ответного сообщения либо редирект и перейти на новый адрес (при успешной регистрации) либо получить код 200 и констатировать провал "операции".

2. Век живи - век учись

Первое, с чего я начал работу с Synapse - это отправил на сервер get-запрос с целью получить необходимые cookies, предположив, что авторизация на сайте будет схожа по принципу со способом из этого поста. А кукисы-то и не пришли, несмотря на то, что вроде бы никаких видимых ошибок в работе Synapse замечено не было.

Порывшись немного по Интернету, нашел небольшое примечания к работе с https-протоколом в Synapse. Дело в том, что

для правильной работы с https помимо модуля httpsend, необходимо использовать также модуль ssl_openssl из той же библиотеки.

Вот так вот. Теперь попробуем пройти весь путь авторизации. Открываем Delphi и создаем новый проект. У меня на главной форме размещены следующие элементы:

  • 2 edit'а для воода логина и пароля;
  • button с ничего не говорящим названием "Login"
  • 2 Memo - в первый будем выводить все полученные кукисы и заголовки, а во второй - содержимое полученного документа после успешной авторизации.

Внешний вид программы у меня получился такой:

Может видок и неказистый, но, для тестов вполне достаточно.

Вначале приведу уже рабочий код обработчик события onClick кнопки - в нем мы отправляем запрос и проверяем прошла ли авторизация:

procedure TForm5.Button1Click(Sender: TObject);
 
function GetLocation(const headers:TStringList):string;
var i:integer;
begin
  for I := 0 to headers.Count - 1 do
    if pos('Location: ',headers[i])>0 then
        begin
          Result:=copy(headers[i],10,length(headers[i])-9);
          break;
        end;
end;
 
var stream: TStringStream;
httpsend: THTTPSend;
begin
  Memo1.Clear;
  Memo2.Clear;
  stream:=TStringStream.Create('');
  stream.WriteString('wizard_domain2=&auid=&htid=&;action=1&login='+Edit1.Text+'&passwd='+Edit2.Text);
  httpsend:=THTTPSend.Create;
  httpsend.MimeType:='application/x-www-form-urlencoded';
  httpsend.Document.LoadFromStream(stream);
  if httpsend.HTTPMethod('post','https://partner.r01.ru/?' ) then
    begin
      Memo2.Lines.Add('Отправка запроса. Ответ сервера');
      Memo2.Lines.Add('-----Cokies-----');
      Memo2.Lines.add(httpsend.Cookies.Text);
      Memo2.Lines.Add('-----Headers-----');
      Memo2.Lines.add(httpsend.Headers.Text);
      if httpsend.ResultCode=302 then
        begin
           if pos('/AB/about_abonent.khtml',GetLocation(httpsend.Headers))>0 then
             begin
               httpsend.Document.Clear;
               httpsend.Headers.Clear;
               httpsend.HTTPMethod('get','https://partner.r01.ru/AB/about_abonent.khtml');
               httpsend.Document.SaveToStream(stream);
               Memo1.Lines.Add(KOI8R2ANSI(stream.DataString));
             end
          else
            Memo1.Lines.Add('Авторизация не удалась')
         end
       else
         Memo1.Lines.Add('Авторизация не удалась')
    end;
end;

Обратите внимание на часть кода:

[...]
if pos('/AB/about_abonent.khtml',GetLocation(httpsend.Headers))>0 then
  begin
    httpsend.Document.Clear;
    httpsend.Headers.Clear;
    httpsend.HTTPMethod('get','https://partner.r01.ru/AB/about_abonent.khtml');
[...]

Всё дело в том, что при успешной авторизации редирект приходит на адрес:

/AB/about_abonent.khtml?regbase2_id=da...

и сколько раз я не пробовал получить документ по этому адресу - ничего не получилось. Поэтому поступил так "топорно" и всё сработало.

В ответном сообщении был получен документ содержащий html-код для страницы личного кабинета.

Ещё один "нестандартный" момент при работе с этим сайтом заключается в том, что страница приходит9 в кодировке KOI8-R и, следовательно, без дополнительной обработки текста мы получим вместо русского текста "кракозябры".

Для того, чтобы избежать неприятных моментов с русскими буквами я использовал вот такую нехитрую функции перекодирования текста из KOI8-R в ANSI:

function KOI8R2ANSI(S: string): string;
var
Ansi_CODE, KOI8_CODE: string;
i: integer;
begin
KOI8_CODE := 'бвчздецъйклмнопртуфхжигюыэящшьасБВЧЗДЕЦЪЙКЛМНОПРТУФХЖИГЮЫЭЯЩШЬАС—Ј';
ANSI_CODE := 'АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюя№ё';
Result := S;
for i := 1 to Length(Result) do
  if Pos(Result[i], KOI8_CODE) > 0 then
    Result[i] := ANSI_CODE[Pos(Result[i], KOI8_CODE)];
end;

Вот, пожалуй, и все, что касается авторизации на сайте https://partner.r01.ru.

P.S. Уважаемая,dkdk, надеюсь я не слишком опоздал с помощью и приведенный выше код Вам помог ;)

--------------------------------
Кстати, информация для будущих программистов. Закажите дипломный проект по программированию уже сейчас, а то потом не успеете.

Торопитесь получить сертификат на свои услуги? Срочная сертификация услуг www.rostest.net Вам обязательно поможет.

Прежде, чем покупать - линолеум цены в он-лайн и не тратьте лишнее время на разъезды по магазинам.

Если не знаете как правильно диван, то лучшее решение - это сборка мебели на дому от профессионалов
--------------------------------
Понравилась статья? Тогда:
Делись! Загружай! Плюсуй!
   Отправить PDF на   
Читай ещё статьи на WebDelphi.ru

Комментарии (69)

WP_Cloudy
  • dkdk пишет:

    Спасибо огромное)) помогло. Кстати, не поняла, почему у меня не срабатывало — ssl_openssl был подключен..
    Теперь встал новый вопрос — скачивание файла))
    https://partner.r01.ru/AB/auction2csv.khtml?ext=csv
    должно происходить автоматическое скачивание файла. Пробую получать гетом этот адрес и делать http.document.savetofile..
    причем и в случае, если сперва ходить на выдаваемый адрес (при этом 206 получаю, пытаюсь уже r01 снова идти, а дальше ничего). При этом откуда берется новая кука? Set-Cookie не было, а кука есть..
    Заранее спасибо еще раз))

  • Vlad пишет:

    HTTPGetFile не пробовали? Сообщения об ошибках были?

  • dkdk пишет:

    HTTPGetFile — вообще не нашла (( GetBinary — ничего вообще не выдает..
    про куки и 206 — это я тормоз, забыла кэш вычистить))
    по идее httpsend.HTTPMethod(‘get’,’https://partner.r01.ru/AB/auction2csv.khtml‘); должно в ответ 200 давать, а вообще ничего не дает. Пусто.  Не понимаю( Т.е. дело даже не в savetofile, а в самом гете..

  • Mihail пишет:


    Здравствуйте! Приведенная здесь информация оказалась очень полезной!
    У меня возникла необходимо залогиниться на сайте ecod.ru работающему по протоколу https. Что вроде получилось не без вашего полезного примера)! Правда у данного сайта свои премудрости (при анализе заголовков при регистрации непосредственно из браузера не в одном из ответов сервера нет поля Location . Но перенаправление происходит, после трех Post запросов и двух Get. Все ответы сервера 200 ок!) Вроде я зарегился, но подозреваю о некорректности. Существует какой либо способ проверить цветут яблони на марсе или нет) по мимо заголовков сервера? Явных ошибок не выдает!
    Пытаюсь скачать файл. После регистрации делаю Get запрос содержащий ссылку на необходимый файл в результате! Ответ 200 ок! содержащий строчку Content-Disposition: attachment; filename=»Order_Lenta_4502941838.xml» – это имя нужного мне файла! Причем ответ абсолютно одинаковый с заголовком ответа в браузере, разница лишь в том что в последнем выходит окно на сохранение данного файла! Пытки использовать функции HttpGetBinary, HttpGetText – не к чему не привели! Уж очень нужен этот файл!
    Будете добры помочь новичку, Заранее благодарен!!!
     

  • dkdk пишет:

    Mihail, а у Вас в гет запросе в явном виде файл указан? У меня просто сервер (r01.ru) вообще никакого ответа не выдает..
    Я вот думаю, может у меня что-то с таймаутом, т.к. он и в браузере долго думает перед началом скачивания..
    thx in advance)

  • Mihail пишет:

    <!— /* Style Definitions */ p.MsoNormal, li.MsoNormal, div.MsoNormal {mso-style-parent:»"; margin:0cm; margin-bottom:.0001pt; mso-pagination:widow-orphan; font-size:12.0pt; font-family:»Times New Roman»; mso-fareast-font-family:»Times New Roman»;} code {font-family:»Courier New»; mso-ascii-font-family:»Courier New»; mso-fareast-font-family:»Times New Roman»; mso-hansi-font-family:»Courier New»; mso-bidi-font-family:»Courier New»;} @page Section1 {size:612.0pt 792.0pt; margin:2.0cm 42.5pt 2.0cm 3.0cm; mso-header-margin:36.0pt; mso-footer-margin:36.0pt; mso-paper-source:0;} div.Section1 {page:Section1;} —>

    /* Style Definitions */
    table.MsoNormalTable
    {mso-style-name:»Обычная таблица»;
    mso-tstyle-rowband-size:0;
    mso-tstyle-colband-size:0;
    mso-style-noshow:yes;
    mso-style-parent:»";
    mso-padding-alt:0cm 5.4pt 0cm 5.4pt;
    mso-para-margin:0cm;
    mso-para-margin-bottom:.0001pt;
    mso-pagination:widow-orphan;
    font-size:10.0pt;
    font-family:»Times New Roman»;
    mso-ansi-language:#0400;
    mso-fareast-language:#0400;
    mso-bidi-language:#0400;}

    Нет запрос содержит ссылку!
    Делаю вот таким макаром
    httpsend.HTTPMethod('get','https://ссылка');
    Если по логике, ответ сервера идентичный как и через браузер, может synapse помещает его в системный буфер, тогда как его достать! Я совсем недавно работаю с synapse!
    И еще вопрос не подскажите как программно перемещаться по сайту, так как ссылка на файл находиться в самой глубине сайта! Спасибо)

  • dkdk пишет:

    подозреваю, что искать ссылку с синапс также, как и без него  — делать поиск в получаемом документе по характерным особенностям ссылки. Т.е. после get
    httpsend.document и в нем искать функцией pos необходимую ссылку)
    А с закачкой файла у самой проблемы..)

  • Vlad пишет:

    Опчки…пока я тут в поте лица тружусь на ниве Российского образования в блоге уже прямо целая дискуссия назрела по поводу Synapse :) Отлично. Ребята, dkdk, Mihail прошу Вас, если не получается решить проблему самостоятельно — подождите немного…совсем чуть-чуть. Я решу пару проблем на работе и займусь вашими вопросами, тем более самому жуть как интересно узнать почему не получается качнуть файлик.
    Mihail, по поводу цветущих яблонь :) сходу, сильно не задумываясь и не заглядывая на сайт, могу предложить вариант — немного проанализировать исходники загружаемых страниц и на основе какого-либо уникального куска кода страницы делать вывод об успешности «операции». Ведь как ни крути не может быть так, чтобы нельзя было «вслепую» определить результат. Может мета-теги на страницах особенные есть или комментарии (хотя на них полагаться сильно не стоит, т.к. комменты имеют свойство исчезать).
    Со скачиванием файлов надо посмотреть Synapse, вполне возможно, что ччего-то мы с Вами ещё не знаем. Будем разбираться совместно :)

  • Mihail пишет:

    <!— /* Style Definitions */ p.MsoNormal, li.MsoNormal, div.MsoNormal {mso-style-parent:»"; margin:0cm; margin-bottom:.0001pt; mso-pagination:widow-orphan; font-size:12.0pt; font-family:»Times New Roman»; mso-fareast-font-family:»Times New Roman»;} code {font-family:»Courier New»; mso-ascii-font-family:»Courier New»; mso-fareast-font-family:»Times New Roman»; mso-hansi-font-family:»Courier New»; mso-bidi-font-family:»Courier New»;} @page Section1 {size:612.0pt 792.0pt; margin:2.0cm 42.5pt 2.0cm 3.0cm; mso-header-margin:36.0pt; mso-footer-margin:36.0pt; mso-paper-source:0;} div.Section1 {page:Section1;} —>

    /* Style Definitions */
    table.MsoNormalTable
    {mso-style-name:»Обычная таблица»;
    mso-tstyle-rowband-size:0;
    mso-tstyle-colband-size:0;
    mso-style-noshow:yes;
    mso-style-parent:»";
    mso-padding-alt:0cm 5.4pt 0cm 5.4pt;
    mso-para-margin:0cm;
    mso-para-margin-bottom:.0001pt;
    mso-pagination:widow-orphan;
    font-size:10.0pt;
    font-family:»Times New Roman»;
    mso-ansi-language:#0400;
    mso-fareast-language:#0400;
    mso-bidi-language:#0400;}

    Разобрался!) Делюсь опытом.
    Итак, изначально нам нужно найти ссылочку на наш файл! Для этого делаем Get Запрос на страничку содержащею ссылочку на файл!
    httpsend.HTTPMethod('get','https://ссылка');
    Далее выгружаем результат запроса на жесткий диск
    httpsend.document.SaveToFile('Директория\Страничка.xml');
    Анализируем полученную страничку, находим нужную ссылочку!
    Делаем Get Запрос на найденную ссылку файла!
    Записываем: httpsend.document.SaveToFile('Директория\файл’);
    И вот он, вот он наш файл!
    Наслаждаемся триумфом !!!)))

  • Vlad пишет:

    Mihail, спасибо, что не забыли блог старины Vlad’а и поделились полезной информацией :) Надеюсь, что и далее будете делиться с нами интересными моментами в работе с Synapse

  • Mihail пишет:

    Vlad, Вам спасибо, за полезную статью, она дала правильное направление!)

  • Olegans пишет:

    Уважаемый Vlad. Спасибо за статью! Очень помогла смог авторизоваться на HTTPS сайте используюя библиотеку Synapse. Теперь стоит задача закачать туда на HTTPS  файл. Пока только имею снятый при помощи Live Http headers образец как это делает обычный браузер. Не могу найти пример какие команды надо давать. Подскажите пожалуйста в каком направлении двигаться?

  • Vlad пишет:

    HTTPPostBinary или HTTPPostFile не использовали ещё? Попробуйте, должно сработать

  • Rushan пишет:

    Здравствуйте, Vlad и все посетители данного блога. Есть у меня задумка написать программу для работы с Яндекс-Деньгами. Пробую залогиниться по аналогии с вашим примером — не получается..:

    stream := TStringStream.Create(»);
    stream.WriteString(‘retpath=http%3A%2F%2Fmoney.yandex.ru%2Fhistory.xml%3Fsys-req-id%3D51695425%26sha%3D1859bc1caec64a6f32418d05bdff6e9ea2701775&idkey=12t1265052585bMDTzoyBu&timestamp=1265051458854&login=<логин>&passwd=<пароль>&In=%D0%92%D0%BE%D0%B9%D1%82%D0%B8′);

    httpsend := THTTPSend.Create();
    httpsend.MimeType := ‘application/x-www-form-urlencoded’;
    httpsend.Document.LoadFromStream(stream);
    if httpsend.HTTPMethod(‘post’, ‘https://passport.yandex.ru/passport?mode=auth&from=money&retpath=http%3A%2F%2Fmoney.yandex.ru%2Fhistory.xml%3Fsys-req-id%3D51695425%26sha%3D1859bc1caec64a6f32418d05bdff6e9ea2701775‘) then
    begin

    end;

    а в ответ получаю:
    HTTP/1.1 302 Found
    Server: nginx
    Date: Mon, 01 Feb 2010 20:34:31 GMT
    Content-Type: text/plain; charset=utf-8
    Connection: close
    Set-Cookie: yandex_mail=rushant; path=/; domain=.yandex.ru
    Set-Cookie: yandex_login=rushant; path=/; domain=.yandex.ru
    Set-Cookie: Session_id=1265056471.-5012146.0.16727186.2:123438673:350.8:1265056471740:1598965860:14.64210.7255.5f98480ecd70511da2d7940a9b74c3f2; path=/; domain=.yandex.ru
    Set-Cookie: L=elUAUmB3b0J4fEcKWl9uc3V2YV8HX3cHEE4bVCg2HlETDwwnLyYtRQooWHNDLAcYLRg/RSwJVzciWQYLTFtUcg==.1265056471.6657.230156.a25cf4c710f62878daceb99c5691e68b; path=/; domain=.yandex.ru; expires=Sunday, 02-May-10 20:34:31 GMT
    P3P: policyref=»/w3c/p3p.xml», CP=»NON DSP ADM DEV PSD IVDo OUR IND STP PHY PRE NAV UNI»
    Location: https://passport-ckicheck.yandex.ru/passport?mode=ckicheck&idkey=0Ee1265057671ToEe64_x7&ncrnd=816769
    - Подскажите, что я делаю не так?

  • Vlad пишет:

    Трудно ответить на вопрос, что не так, т.к. с Яндекс.Деньгами дела не имел в плане авторизации. А что должно быть? В смысле как выглядит заголовок сообщения об успешной авторизации? И ещё timestamp=1265051458854 — этот параметр влияет на авторизацию? Если его убрать, что получится?

  • Olegans пишет:

    Спасибо Vlad за совет. Пытаюсь сделать закачку через функцию HttpPostFile. Правда не до конца понятны те переменные которые необходимо указать для этой функции. function HttpPostFile(const URL, FieldName, FileName: string;
    const Data: TStream; const ResultData: TStrings): Boolean;
    С( const URL, FieldName, FileName: string;) вроде все понятно а вот остальное (const Data: TStream; const ResultData: TStrings) не совсем понимаю с чем едят и что я должен указать для них

  • Steff пишет:

    Немного не в тему, поэтому прошу прощения заранее.
    Недавно стояла задача NTLM авторизации. Побороть эту проблему на Delphi я не смог. Использовал сначала indy (с IdAuthenticationNTLM), потому по совету добрых людей попробовал synapse. Авторизация не поддалась :(
    Опыта работы с http у меня практически нет. Не подскажите как реализауется в Delphi NTLM авторизация ? Может есть статьи на эту тему ? Примеры исходников ?
    З.Ы. Проблему свою решил на C#. Но Delphi мне как-то ближе. Хотелось бы разобраться в проблеме до конца…

  • Vlad пишет:

    С этим я Вам врядли помогу, т.к. никогда не встречался с вашей проблемой. Может кто из читателей подскажет

  • gert пишет:

    спасибо !!!!!!

  • Vayrus пишет:

    Привет Влад, тут такая проблема, пытась залогиниться и создать тему на форуме средствами синапса, но что то не выходит, хотя говорит что все ОК, а потом Length Required, может подскажешь где ошибка?


    function ParseErrors(ErrText: String): String;
    const
    A = '';
    B = '';
    C = '<b>';
    D = '</b>';
    begin
    if pos('login error', ErrText) 0 then
    begin
    Result := Trim(Copy(ErrText, pos(A, ErrText) + Length(A), Length(ErrText)));
    Result := Trim(Copy(Result, 1, pos(B, Result) - 1));
    end
    else if pos('Ошибка', ErrText) 0 then
    begin
    Result := Trim(Copy(ErrText, pos(C, ErrText) + Length(C), Length(ErrText)));
    Result := Trim(Copy(Result, 1, pos(D, Result) - 1));
    end else
    RESULT := ErrText;
    end;

    procedure TForm1.CreateThemes(UserName, Password, PostURL: String;
    var FileList: TStringList);
    const
    FS = 'forum_session=';
    var
    i: integer;
    L: TStringList;
    S: String;
    _Content, _Caption: String;
    DATA: TStringStream;
    HTTPSend: THTTPSend;
    CancelOperation: Boolean;
    SID: String;
    begin
    RANDOMIZE;
    S := '';
    SID := '';
    CancelOperation := FALSE;
    //
    HTTPSend:=THTTPSend.Create;
    try
    HTTPSend.KeepAlive:=true;
    HTTPSend.KeepAliveTimeout:=300;
    HTTPSend.TargetHost:='mark-itt.ru';
    HTTPSend.TargetPort:='80';
    HTTPSend.Protocol:='1.1';
    HTTPSend.MimeType:='application/x-www-form-urlencoded';
    HTTPSend.UserAgent := 'Mozilla/5.0 (Windows; U; Windows NT 6.1; ru-RU; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 (.NET CLR 3.5.30729)';
    //
    if FileList.Count = 0 then
    begin
    LOG('Список файлов пуст');
    EXIT;
    end;
    //
    //Проверять на существование файлов в списке и содержимого
    //
    LOG('Авторизация...');
    //
    Data :=TStringStream.Create('', CP_KOI8R);
    try
    DATA.WriteString('UserName=' + UserName);
    DATA.WriteString('&amp;' +'Password=' + Password);
    //
    //авторизуемся на сайте
    HTTPSend.Document.LoadFromStream(Data);
    if HTTPSend.HTTPMethod('post','<a href="http://talks.mark-itt.ru/forum/login" rel="nofollow">http://talks.mark-itt.ru/forum/login</a>') then
    begin
    //
    LOG(HTTPSend.ResultString + ' [' + IntToStr(HTTPSend.ResultCode) + ']');
    //
    httpsend.Document.SaveToStream(DATA);
    //
    if (pos('Logged in', DATA.DataString) 0) or (pos('continue...', DATA.DataString) 0) then
    begin
    //
    if pos(FS, httpsend.Cookies.Text) 0 then
    begin
    S := Copy(httpsend.Cookies.Text, pos(FS, httpsend.Cookies.Text) + Length(FS), Length(httpsend.Cookies.Text));
    SID := Copy(S, 1, pos('.', S) - 1);
    LOG('Авторизация прошла успешно. SID = ' + SID);
    end
    else
    begin
    LOG('SID не найден');
    //Делать выход!!!!!!!!!!!!!!!!!!!!!
    EXIT;
    end;
    //
    end
    else if pos('login error', DATA.DataString) 0 then // ??????...
    begin
    LOG('Ошибка авторизации: ' + ParseErrors(DATA.DataString));
    //Делать выход!!!!!!!!!!!!!!!!!!!!!
    EXIT;
    end
    else
    begin
    LOG('Другие ошибки авторизации: ' + ParseErrors(DATA.DataString));
    //Делать выход!!!!!!!!!!!!!!!!!!!!!
    EXIT;
    end;
    //
    end else
    LOG('Авторизация не удалась');
    //
    finally
    DATA.Free;
    end;
    //
    LOG('Постинг...');
    //
    for i := 0 to FileList.Count - 1 do
    begin
    //
    //очищаем заголовки и тело документа
    httpsend.Document.Clear;
    httpsend.Headers.Clear;
    //
    S := FileList.Strings[i];
    //
    if FileExists(S) then
    begin
    //
    L := TStringList.Create;
    try
    //
    _Caption := ChangeFileExt(ExtractFileName(S), '');
    //
    LOG('Создание темы: ' + _Caption);
    //
    L.LoadFromFile(S);
    _Content := L.Text;
    //
    Data :=TStringStream.Create('', CP_KOI8R);
    try
    Data.WriteString('sid=' + SID);
    Data.WriteString('&amp;' + 'TopicSubject=' + MutateString(_Caption));
    Data.WriteString('&amp;' + 'MsgIcon=' + '1');
    Data.WriteString('&amp;' + 'Message=' + MutateString(_Content, FALSE));
    Data.WriteString('&amp;' + 'EmailNotification=' + 'yes');
    Data.WriteString('&amp;' + 'Signature=' + 'yes');
    Data.WriteString('&amp;' + 'action=' + 'posttopic');
    Data.WriteString('&amp;' + 'Submit=' + 'Submit New Topic');
    //
    HTTPSend.Document.LoadFromStream(Data);
    if HTTPSend.HTTPMethod('post',PostURL) then
    begin
    //
    LOG(HTTPSend.ResultString + ' [' + IntToStr(HTTPSend.ResultCode) + ']');
    //
    httpsend.Document.SaveToStream(DATA);
    //
    if (pos('Готово', DATA.DataString) 0) or
    (pos('продолжить...', DATA.DataString) 0) then // ??????????...
    LOG('Постинг прошел успешно')
    else if pos('Ошибка', DATA.DataString) 0 then
    LOG('Ошибка постинга: ' + ParseErrors(DATA.DataString))
    else
    LOG('Другие ошибки постинга: ' + ParseErrors(DATA.DataString));
    //
    end else
    LOG('Постинг не удался');
    //
    memo2.Lines.Text:=httpsend.Cookies.Text;
    //
    finally
    DATA.Free;
    end;
    //
    finally
    L.Free;
    end;
    // ?????????
    end else
    LOG('Файл не найден: ' + S); // if FileExists(S) then
    //
    if CancelOperation then
    begin
    LOG('Постинг прерван');
    BREAK;
    end;
    {if CancelOperation then // На всякий случай
    BREAK;}
    //
    end; // for I := 0 to FileList.Count - 1 do
    //
    LOG('Выход...');
    //
    if httpsend.HTTPMethod('get','<a href="http://talks.mark-itt.ru/forummisc/logout" rel="nofollow">http://talks.mark-itt.ru/forummisc/logout</a>') then
    begin
    //
    LOG(HTTPSend.ResultString + ' [' + IntToStr(HTTPSend.ResultCode) + ']');
    //
    if httpsend.HTTPMethod('get','<a href="http://talks.mark-itt.ru/forumindex" rel="nofollow">http://talks.mark-itt.ru/forumindex</a>') then
    begin
    //
    LOG(HTTPSend.ResultString + ' [' + IntToStr(HTTPSend.ResultCode) + ']');
    //
    LOG('Выход осуществлен успешно');
    end else
    LOG('Неудачный выход (2)');
    end else
    LOG('Неудачный выход (1)');
    //
    finally
    HTTPSend.FREE;
    end;
    end;

    procedure TForm1.SpeedButton1Click(Sender: TObject);
    var
    L: TStringList;
    begin
    L:= TStringList.Create;
    try
    L.Add(ExtractFilePath(paramStr(0)) + 'СДАМ ........3комн ........Удмуртская.......... 12000.txt');
    CreateThemes('VitaliiKlichko', 'y7eSpN', '<a href="http://talks.mark-itt.ru/forummisc/post/63&#039;" rel="nofollow">http://talks.mark-itt.ru/forummisc/post/63&#039;</a>, L);//122
    finally
    L.Free;
    end;
    end;

  • Vlad пишет:

    HTTPSend.TargetPort:=’80′;
    HTTPSend.Protocol:=’1.1′;
    Это можно не указывать — синапс сам проставит в момент отправки. Length Required у меня синапс орал, когда забывал вычищать гдето Document или Headers от предыдущего запроса. По коду — после какой операции Length Required появляется?

  • Vayrus пишет:

    Орал когда осуществлял выход, то есть:


    LOG('Выход...');
    //
    if httpsend.HTTPMethod('get','<a href="http://talks.mark-itt.ru/forummisc/logout" rel="nofollow">http://talks.mark-itt.ru/forummisc/logout</a>') then
    begin
    //
    LOG(HTTPSend.ResultString + ' [' + IntToStr(HTTPSend.ResultCode) + ']');
    //
    if httpsend.HTTPMethod('get','<a href="http://talks.mark-itt.ru/forumindex" rel="nofollow">http://talks.mark-itt.ru/forumindex</a>') then
    begin
    //
    LOG(HTTPSend.ResultString + ' [' + IntToStr(HTTPSend.ResultCode) + ']');
    //
    LOG('Выход осуществлен успешно');
    end else
    LOG('Неудачный выход (2)');
    end else
    LOG('Неудачный выход (1)');
  • Vayrus пишет:

    Подозреваю что ошибка кроется опять в куках (неправильная кодировка, нехватка данных) или из-за редиректов

  • Vlad пишет:

    if httpsend.HTTPMethod('get','http://talks.mark-itt.ru/forummisc/logout') then
    begin
    //
    LOG(HTTPSend.ResultString + ' [' + IntToStr(HTTPSend.ResultCode) + ']');
    //
    if httpsend.HTTPMethod('get','http://talks.mark-itt.ru/forumindex') then
    begin

    Ну правильно орал. Вызываешь HTTPMethod — получаешь документ + заголовки, потом не очищая заголовки, пробуешь опять GET вызвать. Перед вторым вызовом надо вычистить Document и Headers.

  • Vayrus пишет:

    Ну я понял, что допустил данную ошибку, но постинга все равно не происходит, несмотря на то что со «слов» синапса все в порядке, а мой код показывает «Другие ошибки постинга»… Может я допустил все таки какую то грубую ошибку при работе с синапсом и koi8-r

  • Vayrus пишет:

    Кстати ошибка постинга возвращает страничку с каракулями, но это понятно, только не понятно почему именно саму страницу постинга

  • nmd пишет:

    не получается авторизироваться на гугле(((

  • Vlad пишет:

    Для Гугла есть готовый компонент.

  • nmd пишет:

    компонент это хорошо конечно, но я хотел бы сам еще посмотреть как все там реализовано на простом примере
    но от ссылки не откажусь))

  • Vlad пишет:

    nmd, компонент мой, распространяется бесплатно и имеет открытые исходники — cкачивайте изучайте :) Вот ссылка https://code.google.com/p/delphicelendar/downloads/list и, кстати, в блоге есть несколько постов, посвященных авторизации в службах гугла

  • nmd пишет:

    спасибо Vlad! и еще вопрос по wininet, какую литературу читали и где ее можно посмотреть? названия книг приветствуются хотелось бы на родном языке!

  • Vlad пишет:

    По wininet использовал всегда справку MSDN. Её вполне достаточно, чтобы понять как и что делается :)

  • blubssnisee пишет:

    Регистрируюсь на форуме.

  • Vlad пишет:

    Поздравляю. Только при чём тут мой блог? :)

  • castrol пишет:

    Сейчас стоит задача авторизации на сайте. Пробовал разобраться в этом примере, но у меня при запуске только мемо чистятся а дальше ничего не происходит.,
    Вот код
    unit Unit11111;

    interface

    uses
    Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
    Dialogs, StdCtrls, ExtCtrls, httpsend;

    type
    TForm1 = class(TForm)
    pnl1: TPanel;
    edit3: TEdit;
    edit1: TEdit;
    edit2: TEdit;
    Memo1: TMemo;
    btn1: TButton;
    lbl1: TLabel;
    lbl2: TLabel;
    lbl3: TLabel;
    Memo2: TMemo;
    procedure btn1Click(Sender: TObject);
    private
    { Private declarations }
    public
    { Public declarations }
    end;

    var
    Form1: TForm1;
    function KOI8R2ANSI(S: string): string;
    implementation

    {$R *.dfm}

    procedure TForm1.btn1Click(Sender: TObject);
    function GetLocation(const headers:TStringList):string;
    var i:integer;
    begin
    for I := 0 to headers.Count — 1 do
    if pos(‘Location: ‘,headers[i])>0 then
    begin
    Result:=copy(headers[i],10,length(headers[i])-9);
    break;
    end;
    end;

    var stream: TStringStream;
    httpsend: THTTPSend;
    begin
    Memo1.Clear;
    Memo2.Clear;
    stream:=TStringStream.Create(»);
    stream.WriteString(‘wizard_domain2=&auid=&amp;htid=&;action=1&login=’+Edit1.Text+’&passwd=’+Edit2.Text);
    httpsend:=THTTPSend.Create;
    httpsend.MimeType:=’application/x-www-form-urlencoded’;
    httpsend.Document.LoadFromStream(stream);
    if httpsend.HTTPMethod(‘post’,’https://partner.r01.ru/?‘ ) then
    begin
    Memo2.Lines.Add(‘Отправка запроса. Ответ сервера’);
    Memo2.Lines.Add(‘——Cokies——’);
    Memo2.Lines.add(httpsend.Cookies.Text);
    Memo2.Lines.Add(‘——Headers——’);
    Memo2.Lines.add(httpsend.Headers.Text);
    if httpsend.ResultCode=302 then
    begin
    if pos(‘/AB/about_abonent.khtml’,GetLocation(httpsend.Headers))>0 then
    begin
    httpsend.Document.Clear;
    httpsend.Headers.Clear;
    httpsend.HTTPMethod(‘get’,’https://partner.r01.ru/AB/about_abonent.khtml‘);
    httpsend.Document.SaveToStream(stream);
    Memo1.Lines.Add(KOI8R2ANSI(stream.DataString));
    end
    else
    Memo1.Lines.Add(‘Авторизация не удалась’)
    end
    else
    Memo1.Lines.Add(‘Авторизация не удалась’)
    end;
    end;

    function KOI8R2ANSI(S: string): string;
    var
    Ansi_CODE, KOI8_CODE: string;
    i: integer;
    begin
    KOI8_CODE := ‘бвчздецъйклмнопртуфхжигюыэящшьасБВЧЗДЕЦЪЙКЛМНОПРТУФХЖИГЮЫЭЯЩШЬАС—Ј’;
    ANSI_CODE := ‘АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюя№ё’;
    Result := S;
    for i := 1 to Length(Result) do
    if Pos(Result[i], KOI8_CODE) > 0 then
    Result[i] := ANSI_CODE[Pos(Result[i], KOI8_CODE)];
    end;
    end.

    Почему мемо только чистятся??
    В делфи я новичок, так что не пинайте сильно.
    Если кто подскажет, задача такая, есть домены третьего уровня  нужно добавить в программу возможность менять название домена, запросы на всех доменах третьего уровня одинаковые.

  • Vlad пишет:

    Исходник весь? По-хорошему стоит всё таки установить курсор на строку:
    httpsend.Document.LoadFromStream(stream)
    нажать F4 и посмотреть как вооще у Вас работает программка. То, что чистяться Memo и все говорит только о том, что процедура работает, а вот идёт ли работа дальше корректно — тут F4 и F7 в руки :) Пример в статье рабочий. Проверил ещё раз — авторизует

  • Genniy пишет:

    Vlad, вы так много знаете о synapse. Не могли бы вы подсказать как решить проблему.
    Мне могу получить ни GET ни POST, когда работаю с https. Библиотеку SSL_OpenSSL подключаю. Не могу работать с тем узлом в котором при заходе через браузер пишет «Ошибка в сертификате безопасности этого web-узла». Можно ли как-то обойти эту проверку?
    Спасибо!

  • Vlad пишет:

    2Genniy, не так уж и много знаю :) Просто часто работаю с библиотекой. Вообще, подключить SSL_OpenSSL иногда бывает недостаточно (см. секцию initialization модуля), например, при работе с GMail вместе с модулем требуется ещё таскать пару dll-к про которые я писал здесь попробуйте подключиться к ресурсу, используя dll. Может поможет. С сертификатами, вроде бы тоже можно работать, но как это реализуется — не смотрел, т.к. никогда не требовалось

  • Илья пишет:

    Content-Length: 87
    _token=986d975ddf8e1ebc6077c10781b355dd&_action=login&_timezone=2&_url=&_user=логин&_pass=пароль
     
    Что есть token?…
     
     

  • Vlad пишет:

    Так вам лучше знать что это за параметр. Вы же с сайтом работаете. Токен видимо ключ, генерируемый каким-то скриптом

  • Vladimir пишет:

    Как выяснилось, для корректной работы с Https , помимо прописывания в Uses  httpsend и ssl_openssl, в папку проекта надо еще положить две dll-библиотеки — libeay32.dll и ssleay32.dll. Без них моя программа не хотела логиниться на https-сайте. ПОсле того, как положил их в папку, все заработало.

  • Vlad пишет:

    ну, в принципе я об этом детально говорил в блоге, правда не в этом посте. Простого прописывания ssl_openssl в uses достаточно, когда надо просто «заставить» Thttpsend использовать https://, а для нормально работы с ssl да — обязательно надо иметь dll-ки.

  • Илья пишет:

    Ура! я сделал авторизацию на сайте электронных денег)
    Только вот проблема. Русские буквы передаются как %CA%EE%F5%E0%ED , можно как-то автоматизировать перевод из букв в «это», для последующей отсылки?

  • Руслан пишет:

    Скиньте исходник плиз!

  • Vlad пишет:

    Нету уже этого исходника

  • Ildar пишет:

    Здарствуйте! Я только наичнаю програмировать на delphi и у меня почему то не получаеться авторизоваться get запросом на  http://cfire.mail.ru Я больше чем уверен что дело в какой то маленькой ошибке но никак понять не могу, помогите пожалуйста 

    procedure TForm1.Button1Click(Sender: TObject);
    function GetLocation(const headers:TStringList):string;
    var i:integer;
    begin
    for I := 0 to headers.Count - 1 do
    if pos('Location: ',headers[i])&gt;0 then
    begin
    Result:=copy(headers[i],10,length(headers[i])-9);
    break;
    end;
    end;

    var stream: TStringStream;
    httpsend: THTTPSend;
    begin
    Memo1.Clear;
    Memo2.Clear;
    stream:=TStringStream.Create('');
    stream.WriteString('login='+Edit1.Text+'&amp;password='+ Edit2.text+'&amp;submit=%C2%EE%E9%F2%E8&amp;remember=');
    httpsend:=THTTPSend.Create;
    httpsend.MimeType:='application/x-www-form-urlencoded';
    httpsend.Document.LoadFromStream(stream);
    if httpsend.HTTPMethod('post','<a href="http://cfire.mail.ru/" rel="nofollow">http://cfire.mail.ru/</a>' ) then
    begin
    Memo2.Lines.Add('Отправка запроса. Ответ сервера');
    Memo2.Lines.Add('-----Cokies-----');
    Memo2.Lines.add(httpsend.Cookies.Text);
    Memo2.Lines.Add('-----Headers-----');
    Memo2.Lines.add(httpsend.Headers.Text);
    if httpsend.ResultCode=302 then
    begin
    if pos('/account/',GetLocation(httpsend.Headers))&gt;0 then
    begin
    httpsend.Document.Clear;
    httpsend.Headers.Clear;
    httpsend.HTTPMethod('get','<a href="http://cfire.mail.ru/account/" rel="nofollow">http://cfire.mail.ru/account/</a>');
    httpsend.Document.SaveToStream(stream);
    end
    else
    Memo1.Lines.Add('Авторизация не удалась')
    end
    else
    Memo1.Lines.Add('Авторизация не удалась')
    end;
    end;

    Если кто решит помочь вот  логин и пароль для проверки
    логин — 787187
    BH027PNQMXEr  - пароль

  • skeptik пишет:

    Доброго времени суток!
    Сразу к делу..
    Имеется статистика провайдера, соответственно https.
    Проблема заключается в том что не могу посмотреть Content-Length.
    Пробовал в «Live Headers», «HTTP Analyzer«.
    Может есть какой-то иной способ просмотра посылаемых заголовков?

  • Vlad пишет:

    skeptik, если «Live Headers» и «HTTP Analyzer» не могут показать заголовок Content-Length, то скорее всего сервер просто не посылает такой заголовок клиентам и всё. Можете проверить и пропарсить теже заголовки с помощью WinInet — результат будет тем же

  • skeptik пишет:

    Vlad, т.е. я так понял какие нужно передавать параметры мне не узнать.
    Эх, а такая идея была!!
    Спасибо, что так быстро ответили !

  • Vlad пишет:

    skeptik, не за что. Думаю, что вам ещё не раз встретятся ситуации, когда узнать размер передаваемых данных невозможно. Например, тот же Google в некоторых своих API не передает заголовки Content-Length

  • Dimrix пишет:

    Подскажите как должен выглядеть запрос в моем случае: необходимо авторизироваться на данном сайте https://assa.intertelecom.ua/ru/login
    stream.WriteString(‘&phone=’+Edit1.Text+’&pass=’+Edit2.Text);
    httpsend:=THTTPSend.Create;
    httpsend.MimeType:=’application/x-www-form-urlencoded’;
    httpsend.Document.LoadFromStream(stream);
    if httpsend.HTTPMethod(‘post’,’https://assa.intertelecom.ua/ru/login‘ ) then
    но   httpsend.HTTPMethod возвращает ложь и естествеено ничего не получается…  
    Где моя ошибка не подскажите?

  • Dimrix пишет:

    Считал заголовки нашёл ошибку, изменил запрос на
      stream.WriteString(‘phone=ххх&pass=ууу&ref_link=»https://assa.intertelecom.ua/ru/statistic»&js=1′);

    но проблема осталась

  • Vlad пишет:

    Dimrix, кодировку не пробовали менять перед отправкой запроса? Может в ней и кроется ваша проблема

  • Dimrix пишет:

    Дык в запросе присутствуют лишь латинские символы и цифры… Они в любой кодировке вроде бы остаются сами собой… Или нет?

  • Dimrix пишет:

    Кстати, код ошибки httpsend.ResultCode=500
     

  • Dimrix пишет:

    ну а сам код страницы следующий:

    &lt;form method="post" class="assa_form" action="https://assa.intertelecom.ua/ru/login"&gt; &lt;label for="phone" id="phone_label"&gt; &lt;strong&gt;Номер телефона:&lt;/strong&gt; &lt;input style="width:110px" type="text" id="phone" name="phone" size="15" maxlength="10" value="" /&gt; &lt;/label&gt; &lt;label for="password" id="password_label"&gt; &lt;strong&gt;Пароль:&lt;/strong&gt; &lt;input style="width:110px" type="password" id="password" name="pass" size="15" maxlength="14" value="" /&gt; &lt;/label&gt; &lt;input type="submit" class="submit" value="Вход" onclick="checkLoginForm(this.form); return false;" /&gt; &lt;input type="hidden" name="ref_link" value="https://assa.intertelecom.ua/ru/login"/&gt; &lt;script type="text/javascript"&gt; //&lt;![CDATA[ document.write('&lt;input type="hidden" name="js" value="1" /&gt;'); //]]&gt; &lt;/script&gt; &lt;/form&gt;
  • Dimrix пишет:

    Бред, но когда убрал из строки адресс букву с (не https:// a http://) Авторизация как я понимаю проходит. Теперь буду разбираться как считывать параметры…

  • Vlad пишет:

    Dimrix, не бред. Просто для httpS в Synapse надо подключать модуль ssl_openssl. Если не подключали, то вот вам и 500 ошибка (дефолтная при ошибочно составленном запросе). Может ещё пригодится http://www.webdelphi.ru/2011/07/biblioteka-synapse-rabota-s-modulem-httpsend-pas/ последний и самый большой пост про Synapse в этом блоге.

  • Dimrix пишет:

    Фишка заключается именно в том, что я подключил модуль (объявил его в юнитах), но результата не было. Ответ который я получаю с кодом 301 как раз тот, что высылается при положительной авторизации, ибо в противном случае должен получать код 200.
    ЗЫ: Так не охота рыться в процедурах, не подскажете как (если можно с примерами) мне считать необходимые данные со страницы, пусть даже весь код страницы, а там я уже сам сделаю выборку нужных мне данных.

  • Dimrix пишет:

    Факир был пьян и фокус не удался — нашёл баг — добавить то в юниты я не забыл, а вот длл положить в папочку забыл, и модель не работал. Только вложил длл сразу документ полностю скачался. Дальше дело техники. Всем спасибо :)
    ЗЫ: при успользовании модуля ssl_openssl не забывайте доложить длл-ки ибо без них дела не будет!

  • Vlad пишет:

    Dimrix, без DLL тоже работает иногда, например, при авторизации в Google, но вообще да — dll-ка нужна всегда, чтобы вдруг не напороться на неожиданности типа ответа 500

  • Steff пишет:

    Привет, Влад.

      Может поможешь «распутать» еще одну авторизацию ?
      Пытаюсь авторизоваться в интернет банке связного: https://ibank.svyaznoybank.ru/lite/app/pub/Login
      httpsend.HTTPMethod(‘post’,’https://ibank.svyaznoybank.ru/lite/app/pub/Login‘);
      получаю: 400 Bad Request. Your browser sent a request that this server could not understand
      SSL инициализирован корректно (SSLImplementation типа TSSLOpenSSL). В чем может быть проблема ?

      Пробовал через indy. Код страницы замечательно скачивается, парсится, но после перенаправления  получаю не ту страницу. Видимо корректные куки отправить не получается :(
      Хотел бы получить тот же результат через synapse, может здесь с куками проблем не будет… 

  • Vlad пишет:

    Steff, при авторизации рядом с программкой лежат необходимые dll-ки для работы с SSL? Если нет — положить и проверить авторизацию ещё раз — должно получиться

  • Steff пишет:

    Все на месте. Я изучил все твои статьи по synapse (кстати огромное спасибо тебе за твою работу)
    В том то и дело что я изначально думал на synapse сделать задачу, но первую же страничку скачать не смог. Потом решил проверить на indy. С indy получилось, но не все :(

  • Vlad пишет:

    Steff, хм..очень странно, что всё подключено и на месте и сходу 400 ошибка выпадает. Ок, давай тогда так : в комментах запаримся кодом бросаться — закинь, если можешь, на форум свой вопрос вместе с исходником + укажи какие библиотеки для SSL используешь и их размер. Не даю 100% гарантию, что смогу польностью разобраться с этой авторизацией, но попробую хотя бы разобраться откуда 400 ошибка получается.

  • steff пишет:

    Спасибо, Влад. Эта задачка у меня домашняя, т.ч. пишу только по вечерам.
    Создал новую тему на формуе 

  • Дмитрий пишет:

    Влад,  если не трудно, прдскажите, что в Synapse является аналогом   BasicAuthentification, который пристутсnвует в Indy?  То есть как корректно подключаться через proxy с использованием basicAuthentification?

  • Vlad пишет:

    Дмитрий, не знаю поможет ли Вам лично этот пример или нет http://www.webdelphi.ru/2010/03/twitter-api-v-delphi-rabota-so-spiskami-following-i-followers/ тут я рассматривал работу с Twitter API и использовал как раз ныне упраздненную BasicAuthentification (см. самый первый листинг). Попробуйте, может пригодится

  • Дмитрий пишет:

    ОК, спасибо, гляну

Ваш ответ

Внимание: Все комментарии модерируются, и это может вызвать задержку их публикации. Отправлять комментарий заново не требуется.

Пожалуйста, заключайте исходный код в тэги [code][/code].
Если код большой, то воспользуйтесь Вставкой кода на отдельной странице и оставьте в комментарии ссылку на исходник