Конференция "Сети" » Авторизация в Alpari через TWebBrowser или TChromium
 
  • TraderProg © (12.03.18 22:06) [0]
    Здравствуйте! Столкнулся с такой проблемой. Не получается авторизоваться программно в Alpari через браузеры-компоненты Delphi, такие как TWebBrowser или TChromium. Надо заполнить логин и пароль и нажать кнопку для подключения.

    Адрес страницы авторизации такой: https://alpari.com/ru/login/

    Внимание! После нескольких попыток входа в течение короткого промежутка времени - появляется окно для ввода капчи. Мне на окно ввода капчи "фиолетово", так как цель - авторизоваться с первой попытки раз в сутки, используя свой логин и пароль.

    Селектор DOM поля ввода текста для логина:
    #authorization_login
    либо такой:
    body > div.page__main > div > form > div > div.grid__row.form__section.s_p_0 > div.grid__col.grid__col_w_17 > div:nth-child(1) > div.grid__col.grid__col_w_10 > div.js-form-el-holder.input.grid__col_w_4.input_focus_yes

    Селектор DOM для пароля:
    #authorization_password
    либо такой:
    body > div.page__main > div > form > div > div.grid__row.form__section.s_p_0 > div.grid__col.grid__col_w_17 > div.js-form-el-field.field.grid__row.form__section.s_pb_9.field_active > div.grid__col.grid__col_w_10 > div.js-form-el-holder.input.grid__col_w_4.input_focus_yes

    Селектор кнопки "Войти":
    body > div.page__main > div > form > div > div.grid__row.form__section.s_p_0 > div.grid__col.grid__col_w_17 > div:nth-child(4) > div > button

    На счет кнопки "Войти" думаю проблем не должно быть, но я до проверки работы клика на нее еще не дошел - у меня не получается ввести нужный текст в поля ввода. Вылазят ошибки.
  • Redmond (13.03.18 18:30) [1]
    На текущей машине нету Делфи, посмотреть не смогу, но в Google Chrome вроде бы вполне работают такие букмарклеты:

    javascript:(function(){   document.getElementById('authorization_login').value='1234';   })();

    javascript:(function(){   document.getElementById('authorization_password').value='5678';   })();

    javascript:(function(){   document.getElementsByName('send')[0].style='border:solid red 6px';   })();
  • TraderProg © (13.03.18 19:32) [2]
    Спасибо, Redmond, опробую твой код и напишу получилось или нет. Вопрос: бумарклет - это что? прям в браузере набивается что ли? через F12 ?
  • TraderProg © (13.03.18 21:31) [3]
    Я пока первую версию на основе WebBrowser делаю, а на Хромиуме (где можно исполнять любой javascript код) завтра попробую.
    Пока попробовал такой код:
    WebBrowser1.OleObject.Document.GetElementById('authorization_login').value:='123 456';
    WebBrowser1.OleObject.Document.GetElementById('authorization_password').value:=' 789321';

    Текст действительно вставляется в поля, но при нажатии на кнопку вылазит предупреждение, что поля логин и пароль должны быть заполненными, НО!!! стоит только разок по любому из полей кликнуть мышкой, так сразу для системы текст в полях становится виден и запускается процесс входа в личный кабинет. В общем странный глюк. Хотя может быть каким-то таким же способом реализовать клик по полю, но мои попытки приводили только к ругани системы.

    По поводу кнопки дело еще хуже. Оба моих варианта кода приводят к сообщению об ошибке.
    1-й вариант:
     st:='body > div.page__main > div > form > div > div.grid__row.form__section.s_p_0 > div.grid__col.grid__col_w_17 > div:nth-child(4) > div > button';
     List:=Doc.querySelectorAll(st);
     Node:=List.item(0);
     Node.click;

    Приводит к сообщению "invalid variant operation". Кстати чтобы такое сообщение не вылазило при потере объекта DOM, достаточно код вставить в блок try..except или надо что-то другое?

    2-й вариант нажатия на кнопку:
    WebBrowser1.OleObject.Document.getElementsByName('send').click;

    Приводит к сообщению "Method 'click' not supported by automation object".
  • Redmond (13.03.18 22:44) [4]
    Букмарклет это когда в браузере сначала делаешь вроде как закладку, но потом вместо URL указываешь протокол "javascript" а дальше код на JS: https://ru.wikipedia.org/wiki/Букмарклет
    И если тыкать мышкой в закладку - тогда просто тот скрипт выполняется на текущей вкладке.

    > 2-й вариант ...

    Там же getElements - список там возвращается, у списка разумеется нету метода "click". С:

    > Текст действительно вставляется в поля, но при нажатии на кнопку вылазит предупреждение

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

    А вот "invalid variant operation" уже странно, на какой точно строке вылетает?
  • Redmond (14.03.18 01:04) [5]
    Ну вот я дома. Скопировал ваш код №1. У вас выдаёт "invalid variant operation" потому что в List ноль элементов. А вы оттуда взяли Node.
    И при обращении к Node... гм... Вообще мне казалось должно было вылетать ещё при попытке получить несуществующий элемент. Но как оказалось - оно молча возвращает NULL.
    Я же вам уже писал что как бы надо бы делать проверки "сколько элементов в списке" и на "пустоту". Как минимум точные место и причина ошибки будет видна как на ладонях.

    Старайтесь что ли обходиться без каких-либо ":nth-child(n)", как правило подобное слишком непостоянно.

    З.Ы.Node.focus();
    Node.value:='...';
    Doc.body.focus();
  • Redmond (14.03.18 03:17) [6]
    Ну как-то типа так:
    Procedure TForm1.ToolButton5Click(Sender: TObject);
    Var i: Integer; Doc, Node, List: Variant;
    Begin
    Doc:=WebBrowser1.Document;
    /////////////////////////////////////////////////////////////////////////////////// Login Input
    Node:=Doc.getElementById('authorization_login');
    If IsVariantNULL(Node) Then Raise Exception.Create('Input "Login" was not found!');
    Node.focus();
    Node.value:='login';
    Doc.body.focus();
    /////////////////////////////////////////////////////////////////////////////////// Password Input
    Node:=Doc.getElementById('authorization_password');
    If IsVariantNULL(Node) Then Raise Exception.Create('Input "Password" was not found!');
    Node.focus();
    Node.value:='password';
    Doc.body.focus();
    /////////////////////////////////////////////////////////////////////////////////// Captcha Input
    Node:=Doc.getElementById('captcha');
    If IsVariantNULL(Node) Then Raise Exception.Create('Input "Captcha" was not found!');
    Node.focus;
    Node.value:='12345';
    Doc.body.focus;
    /////////////////////////////////////////////////////////////////////////////////// Submit Button
    List:=Doc.getElementsByName('send');
    Node:=List.item(0);
    If IsVariantNULL(Node) Then Raise Exception.Create('Button "Submit" was not found!');
    Node.focus();
    Application.ProcessMessages();
    Node.click();
    ///////////////////////////////////////////////////////////////////////////////////
    End;

    мм... Без ProcessMessages() почему-то не работает. Почему - хрен его знает...
  • TraderProg © (14.03.18 09:41) [7]
    Функция IsVariantNULL не известна для Delphi. Это системная VarIsNull или переименованная функция CheckVariant из соседней смежной ветки форума?:

    Function CheckVariant(Variable: OleVariant): BooLean;
    Begin
    Result:=Not (VarIsNull(Variable) Or VarIsEmpty(Variable));
    End;

    В общем вставил я Ваш код в свой проект, определив IsVariantNULL как:
    Function IsVariantNULL(Variable: OleVariant): BooLean;
    Begin
    Result:=(VarIsNull(Variable) Or VarIsEmpty(Variable));
    End;

    Вроде как заработало. Спасибо большое!

    Redmond, немного не по теме еще вопрос. В инете нашел много способов понять загрузилась ли страница полностью в WebBrowser или нет. Но ни один из них не дожидается окончательной загрузки. С Хромиумом такой проблемы нет. Я пока просто поставил таймер и по прошествии минуты начинается работа с DOM. Но это "костыли" все-таки )))
  • Redmond (14.03.18 16:45) [8]
    Да, всё верно сделали. Мне давно пора сделать модуль и куда-то выложить. Чтоб не писать по памяти, а то имена функций пишу как попало. :)

    Нюанс в том, что даже если страница "официально полностью загрузилась" - это далеко не всегда обозначает что "пора делать свои дела".
    Например JS может ещё что-то не доделать. А к тому же в JS есть своё подобие таймера. Иногда "ждать" как ни странно оказывается самым простым и действенным способом.
    Главное не использовать Sleep с параметром больше нуля - оно не "ждёт", оно тупо замораживает поток.
  • Redmond (14.03.18 17:00) [9]
    Хотя не до конца верно выразился - если в программе много потоков, то в "не главном потоке" использовать Sleep можно. Это в однопоточных пауках не пройдёт.

    А вот "минуту" это вы чёт многоватто. Ждём события WebBrowser "завершено" и с этого момента может ещё пол-секунды или может полторы секунды.
  • TraderProg © (14.03.18 18:02) [10]
    Минуту поставил чтоб наверняка - VPS слабенький, бывает за пару секунд страница грузится, а бывает и секунд 30 )))
  • TraderProg © (15.03.18 07:50) [11]
    А по идее же наверно можно проверку длины List и существования Node заменить одним блоком Try...Except...End. То есть если ошибок не возникло то выполняется один код, а если на каком то из этапов возникла - то другой. Вроде как и код проще получается. Или будут какие то недостатки этого метода?
  • Redmond (15.03.18 15:30) [12]
    И заодно не знать что и где произошло..?
  • TraderProg © (15.03.18 15:38) [13]
    Можно в блоке Except чтобы запись в журнал в Memo делать, хотя конечно будет грубо и непонятно где в List или в Node ошибка. Но это все-таки редкость и при следующем проходе снова определится и вероятно удачно.
 
Конференция "Сети" » Авторизация в Alpari через TWebBrowser или TChromium
Есть новые Нет новых   [134427   +26][b:0][p:0.001]