Веб-сайт не распознает мои входы [как запустить IE dom event вручную из VBA]
Я хотел бы купить на gdax автоматически. Но мои данные в окне "Сумма" не распознаются. Я вижу, что на маленьком поле, которое говорит: Total (LTC) ≈ 0.00000000
Мой код:
Sub test()
Dim ObjIE As New InternetExplorer
Dim Ohtml As HTMLDocument
Dim HTMLtags As IHTMLElementCollection
Dim HTMLtag As IHTMLElement
Dim HTMLobjekt As IHTMLElement
Dim item_limit As Object
Dim y As Integer
With ObjIE
.Visible = True
.navigate "https://www.gdax.com/trade/LTC-EUR"
Do Until .readyState = READYSTATE_COMPLETE: Loop
Set Ohtml = .document
End With
'Amount
Do
Set HTMLtags = Ohtml.getElementsByClassName("OrderForm_input-box_XkGmi")
DoEvents
Loop While HTMLtags.Length = 0
For Each HTMLtag In HTMLtags
If HTMLtag.Children(1).innerText = "EUR" Then
Set HTMLobjekt = HTMLtag.Children(0)
HTMLobjekt.Value = 100 ' this is the part that i excanged
End If
Next HTMLtag
'get the Total(LTC) to cross check
Do
Set HTMLtags = Ohtml.getElementsByClassName("OrderForm_total_6EL8d")
DoEvents
Loop While HTMLtags.Length = 0
For Each HTMLtag In HTMLtags
Debug.Print HTMLtag.innerText & "Total(LTC)"
Next HTMLtag
End Sub
Это то, что веб-сайт говорит, когда код сделан:
и так оно и должно выглядеть, и выглядит, когда я набираю номер вручную:
Я также обмениваю отмеченную часть такими вещами, как:
HTMLobjekt.innerText = 100
или же
HTMLobjekt.innerText = "100"
или же
HTMLobjekt.Value = "100"
но ничего не получилось.
Ответы
Ответ 1
Вы должны убедиться, что страница полностью загружена, прежде чем предпринимать какие-либо инициативы. Я проверил наличие одного такого класса, созданного динамически OrderBookPanel_text_33dbp
. Затем я сделал все, что вы пытались сделать. Наконец, вам нужно Focus
цель, прежде чем поместить эту сумму в местозаполнитель. Применяя все вышесказанное, ваш сценарий должен выглядеть следующим образом:
Sub Get_Value()
Dim HTML As HTMLDocument, tags As Object
Dim tag As Object, ival As Object
With CreateObject("InternetExplorer.Application")
.Visible = True
.navigate "https://www.gdax.com/trade/LTC-EUR"
While .Busy = True Or .readyState < 4: DoEvents: Wend
Set HTML = .document
Do: Set tags = HTML.querySelector("[class^='OrderBookPanel_text_']"): DoEvents: Loop While tags Is Nothing
Do: Set tag = HTML.querySelector("input[name='amount']"): DoEvents: Loop While tag Is Nothing
tag.Focus
tag.innerText = 100
Set ival = HTML.querySelector("[class^='OrderForm_total_']")
[A1] = ival.innerText
.Quit
End With
End Sub
Выход на данный момент:
0.79139546
Ответ 2
Не полный ответ, просто направление. Откройте веб-страницу https://www.gdax.com/trade/LTC-EUR в браузере (например, Chrome). Нажмите, чтобы открыть контекстное меню целевого элемента (шаг 1 на скриншоте ниже), нажмите "Осмотреть" (2), от открытых инструментов разработчика справа вы увидите целевой элемент (3) и что есть куча прослушивателей событий для целевого объекта (4). Один из обработчиков input
на уровне узла document
. Фактически сумма обновляется этим обработчиком событий, когда событие помечено от узла <input>
. Вы можете легко проверить это, удалив все остальные обработчики событий (нажмите на их кнопки Remove). Но если вы удалите, в частности, этот обработчик input
(5), то обновления не будет (пока вы не перезагрузите веб-страницу).
Таким образом, чтобы имитировать активность пользователя, вам необходимо создать такой объект события input
и отправить его на целевой узел <input>
. Примечание. <input>
узел и управление input
- это совершенно разные вещи, имеющие одно и то же имя.
Выполнение обработчика событий трассировки в IE может выполняться в отладчике. Откройте инструменты разработчика IE (нажмите F12), перейдите на вкладку "Отладчик" (шаг 1 на снимке ниже), вкладку "Точки останова" (2), нажмите "Добавить точку останова" (3), выберите событие ввода (4). Теперь любое событие ввода приостанавливает выполнение кода и открывает окно отладчика (5).
Если вы попытаетесь ввести текстовое поле суммы на веб-странице, отладчик покажет код функции обработчика событий:
Вы можете возобновить выполнение (F5) или сделать шаг в/над/из. Чтобы просмотреть объект события, переданный функции, введите arguments
в консоли, после ввода вручную вы получите вывод для стандартного вызова обработчика событий:
Я проверил приведенный ниже тестовый код, чтобы инициировать это событие из VBA:
Sub Test()
Dim oEvt As Object
With CreateObject("InternetExplorer.Application")
.Visible = True
.Navigate "https://www.gdax.com/trade/LTC-EUR"
Do While .ReadyState < 4 Or .Busy
DoEvents
Loop
With .Document
Do While IsNull(.querySelector("div.OrderForm_input-box_XkGmi input"))
DoEvents
Loop
Set oEvt = .createEvent("Event")
oEvt.initEvent "input", True, False, .parentWindow, 1
With .querySelector("div.OrderForm_input-box_XkGmi input")
.Focus
.Value = "1000"
.dispatchEvent oEvt
Stop
End With
End With
End With
End Sub
В результате происходят абсолютно те же действия, что и при вводе суммы вручную. Он работает без ошибок. Но Total (LTC) не обновляется. Debugger также приостанавливает выполнение, а выход для объекта события выглядит следующим образом:
Единственное различие заключается в том, что свойство isTrusted
имеет значение True
для стандартного вызова и False
для вызова через VBA. Наверное, поэтому обновление пропускается где-то в коде обработчика. Я попытался проследить весь процесс выполнения кода до завершения обработчика событий, но, похоже, это огромная обратная инженерная работа, на которую я не могу выделить время на данный момент.
В настоящее время я застрял в своих исследованиях в этот момент.
Ответ 3
Извините, но не смог поработать, но подтолкнул проблему.
Мне удалось выяснить правильный синтаксис для создания и повышения события в более высоких версиях Internet Explorer (благодаря этому SO-ответу). Мне удалось поднять входное событие для поля ввода, которое следовало за omegastripes отличным результатом.
Таким образом, он работает для локального файла, который я даю ниже, который имеет ту же самую существенную структуру реальной страницы.
Но когда я запускаю код на реальной странице, он просто не работает, и я не знаю, почему.
По возможности я загружаю javascript в IE для его выполнения, чтобы имитировать проблемы с мостом совместимости VBA/COM/MSHTML. Я делаю это, вызывая window.execScript
передавая javascript как строку.
Я надеюсь, что кто-то сможет забрать этот мяч и запустить его по линии ворот. Для меня я дошел до конца.
Вот локальный файл html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
</head>
<body>
<input id="Button1" type="button" value="Programmatically write textbox value" onclick="TestAlert()" />
<form class="OrderForm_form_25r0u">
<ul class="OrderForm_trade-type_2QyK4">
<li class="OrderForm_trade-type-tab_uWGMp OrderForm_active_Di-9p">MARKET</li>
<li class="OrderForm_trade-type-tab_uWGMp">LIMIT</li>
<li class="OrderForm_trade-type-tab_uWGMp">STOP</li>
</ul>
<ul class="OrderForm_toggle_120Ka">
<li class="OrderForm_toggle-tab_bZZnC OrderForm_buy_38n5g OrderForm_active_Di-9p">BUY</li>
<li class="OrderForm_toggle-tab_bZZnC OrderForm_sell_3vYRQ">SELL</li>
</ul>
<div class="market-order">
<div class="OrderForm_section_2Znad">
<div class="OrderForm_section-header_fwFDB">Amount</div>
<div class="OrderForm_input-box_XkGmi">
<input type="number" step="0.01" min="0" name="amount" placeholder="0.00" value="" autocomplete="off" oninput="myOnInputHandler()">
<span>EUR</span>
</div>
</div>
</div>
<div class="OrderForm_order-total_3Mkdz">
<div>
<b>Total</b>
<span>(LTC)</span>
<b>≈</b>
</div>
<div class="OrderForm_total_6EL8d" >0.00000000</div>
</div>
</form>
<script language="javascript">
function myOnInputHandler() {
print_call_stack();
alert('you input something');
}
function print_call_stack() { console.trace(); }
function print_call_stack2() {
var stack = new Error().stack;
console.log("PRINTING CALL STACK");
console.log(stack);
}
function TestAlert() { setInputBox(document); }
function setInputBox() {
try {
var inputBox = document.querySelector('div.OrderForm_input-box_XkGmi input'); inputBox.value = 100; if (document.createEvent) { var event2 = document.createEvent("HTMLEvents"); event2.initEvent("input", true, true); event2.eventName = "input"; inputBox.dispatchEvent(event2); }
return ({ success: true });
}
catch (ex) {
return ({ exception: ex, myMsg: '#error in setInputBox!' });
}
}
</script>
</body>
</html>
Вот VBA
Option Explicit
'* Tools - References
'* MSHTML Microsoft HTML Object Library C:\Windows\SysWOW64\mshtml.tlb
'* SHDocVw Microsoft Internet Controls C:\Windows\SysWOW64\ieframe.dll
'* Shell32 Microsoft Shell Controls And Automation C:\Windows\SysWOW64\shell32.dll
Private Function ReacquireInternetExplorer(ByVal sMatch As String) As Object
Dim oShell As Shell32.Shell: Set oShell = New Shell32.Shell
Dim wins As Object: Set wins = oShell.Windows
Dim winLoop As Variant
For Each winLoop In oShell.Windows
If "C:\Program Files (x86)\Internet Explorer\IEXPLORE.EXE" = winLoop.FullName Then
Dim sFile2 As String
sFile2 = "file:///" & VBA.Replace(sMatch, "\", "/")
If StrComp(sFile2, winLoop.LocationURL, vbTextCompare) = 0 Then
Set ReacquireInternetExplorer = winLoop.Application
GoTo SingleExit
End If
End If
Next
SingleExit:
End Function
Sub test()
Dim objIE As InternetExplorer
Set objIE = New InternetExplorer
Dim oHtml As HTMLDocument
Dim HTMLtags As IHTMLElementCollection
Dim sUrl As String
sUrl = "C:\Users\Simon\source\repos\WebApplication2\WebApplication2\HtmlPage1.html"
'sUrl = "http://localhost:50367/HtmlPage1.html"
sUrl = "https://www.gdax.com/trade/LTC-EUR"
objIE.Visible = True
objIE.Navigate sUrl
If StrComp(Left(sUrl, 3), "C:\") = 0 Then
Stop '* give chance to clear the activex warning box for the local file
Set objIE = ReacquireInternetExplorer(sUrl)
End If
Do Until objIE.readyState = READYSTATE_COMPLETE: DoEvents: Loop
Set oHtml = objIE.Document
Do
'* wait for the input box to be ready
Set HTMLtags = oHtml.getElementsByClassName("OrderForm_input-box_XkGmi")
DoEvents
Loop While HTMLtags.Length = 0
Dim objWindow As MSHTML.HTMLWindow2
Set objWindow = objIE.Document.parentWindow
'* next line would be really useful if it worked because it prints the stack trace in the console window
'* and we would be able to see the needle in the haystack where te order total gets updated
'* works on local file but not on https://www.gdax.com/trade/LTC-EUR **sigh**
objWindow.execScript "var divTotal = document.querySelector('div.OrderForm_total_6EL8d'); divTotal.onchange = function() { console.trace(); }"
'* next line sets the input box and raises an event, works on local file but not on GDAX
objWindow.execScript "var inputBox = document.querySelector('div.OrderForm_input-box_XkGmi input'); inputBox.value = 100; if (document.createEvent) { var event2 = document.createEvent('HTMLEvents'); event2.initEvent('input', false, false); event2.eventName = 'input'; inputBox.dispatchEvent(event2); }"
'get the Total(LTC) to cross check
Do
'* wait for the order total div to be ready
Set HTMLtags = oHtml.getElementsByClassName("OrderForm_total_6EL8d")
DoEvents
Loop While HTMLtags.Length = 0
Dim divTotal As HTMLDivElement
Set divTotal = oHtml.querySelector("div.OrderForm_total_6EL8d")
Debug.Print divTotal.innerText & " Total(LTC)"
Stop
End Sub