-
Здравствуйте! Столкнулся с такой проблемой. Не получается авторизоваться программно в 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 На счет кнопки "Войти" думаю проблем не должно быть, но я до проверки работы клика на нее еще не дошел - у меня не получается ввести нужный текст в поля ввода. Вылазят ошибки.
-
На текущей машине нету Делфи, посмотреть не смогу, но в 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'; })();
-
Спасибо, Redmond, опробую твой код и напишу получилось или нет. Вопрос: бумарклет - это что? прям в браузере набивается что ли? через F12 ?
-
Я пока первую версию на основе 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".
-
Букмарклет это когда в браузере сначала делаешь вроде как закладку, но потом вместо URL указываешь протокол "javascript" а дальше код на JS: https://ru.wikipedia.org/wiki/БукмарклетИ если тыкать мышкой в закладку - тогда просто тот скрипт выполняется на текущей вкладке. > 2-й вариант ...Там же getElement s - список там возвращается, у списка разумеется нету метода "click". С: > Текст действительно вставляется в поля, но при нажатии на кнопку вылазит предупреждениеа... Вот про что речь. Иногда на элементах внутри FORM навешаны проверки вводимых данных, которые могут мешать (вернее не замечать что что-то изменилось). Видимо такой случай. Первое что стоит пытаться в таких случаях - сперва ставить фокус на элемент который будем заполнять. А вот "invalid variant operation" уже странно, на какой точно строке вылетает?
-
Ну вот я дома. Скопировал ваш код №1. У вас выдаёт "invalid variant operation" потому что в List ноль элементов. А вы оттуда взяли Node. И при обращении к Node... гм... Вообще мне казалось должно было вылетать ещё при попытке получить несуществующий элемент. Но как оказалось - оно молча возвращает NULL. Я же вам уже писал что как бы надо бы делать проверки "сколько элементов в списке" и на "пустоту". Как минимум точные место и причина ошибки будет видна как на ладонях.
Старайтесь что ли обходиться без каких-либо ":nth-child(n)", как правило подобное слишком непостоянно.
З.Ы.Node.focus(); Node.value:='...'; Doc.body.focus();
-
Ну как-то типа так:
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() почему-то не работает. Почему - хрен его знает...
-
Функция 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. Но это "костыли" все-таки )))
-
Да, всё верно сделали. Мне давно пора сделать модуль и куда-то выложить. Чтоб не писать по памяти, а то имена функций пишу как попало. :)
Нюанс в том, что даже если страница "официально полностью загрузилась" - это далеко не всегда обозначает что "пора делать свои дела". Например JS может ещё что-то не доделать. А к тому же в JS есть своё подобие таймера. Иногда "ждать" как ни странно оказывается самым простым и действенным способом. Главное не использовать Sleep с параметром больше нуля - оно не "ждёт", оно тупо замораживает поток.
-
Хотя не до конца верно выразился - если в программе много потоков, то в "не главном потоке" использовать Sleep можно. Это в однопоточных пауках не пройдёт.
А вот "минуту" это вы чёт многоватто. Ждём события WebBrowser "завершено" и с этого момента может ещё пол-секунды или может полторы секунды.
-
Минуту поставил чтоб наверняка - VPS слабенький, бывает за пару секунд страница грузится, а бывает и секунд 30 )))
-
А по идее же наверно можно проверку длины List и существования Node заменить одним блоком Try...Except...End. То есть если ошибок не возникло то выполняется один код, а если на каком то из этапов возникла - то другой. Вроде как и код проще получается. Или будут какие то недостатки этого метода?
-
И заодно не знать что и где произошло..?
-
Можно в блоке Except чтобы запись в журнал в Memo делать, хотя конечно будет грубо и непонятно где в List или в Node ошибка. Но это все-таки редкость и при следующем проходе снова определится и вероятно удачно.
|