веб-сайт Проблема входа в систему Подтверждение запроса с использованием WinHTTPrequest.5.1 / Microsoft.XMLHTTP в VBA

Я пытаюсь автоматизировать вход в систему и загружать данные для веб-сайта (https://indexes.nasdaqomx.com/ ). Мой код не проходит аутентификацию, в чем проблема, моя верхняя часть WinHttpReq.responseText говорит, как показано ниже:

 </header>
    <div class="container">
        <div class="row-fluid spacer">
    <div class="span12">
        <p class="textCenter">
            We're sorry your request could not be fulfilled. Rest assured we have been notifed and will resolve this issue shortly.
        </p>
    </div>
</div>

Мой код VBA выглядит следующим образом:

Public Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)

Sub DownloadFile()

Dim myuser As String
Dim MyPass As String
Dim sHTML As String
myuser = "xxxxxx"
MyPass = "xxxxxx"

Dim WinHttpReq As Object
Set WinHttpReq = CreateObject("Microsoft.XMLHTTP")

WinHttpReq.Open "POST", "https://indexes.nasdaqomx.com/Account/LogOn", True

WinHttpReq.SetRequestHeader "Content-type", "application/x-www-form-urlencoded"
WinHttpReq.SetRequestHeader "Connection", "keep-alive"
WinHttpReq.send "UserName=xxxxxx&Password=xxxxxxx"
Sleep (6000)
Debug.Print WinHttpReq.readyState
If WinHttpReq.readyState = 4 Then
sHTML = WinHttpReq.responseText
'this below line result shows We're sorry your request could not be fulfilled
Debug.Print sHTML
End If
Sleep (5000) ' delay 4 second

WinHttpReq.Open "GET", "https://indexes.nasdaqomx.com/Index/ExportWeightings/NDX?tradeDate=2015-08-19T00:00:00.000&timeOfDay=SOD", True
Debug.Print WinHttpReq.readyState
WinHttpReq.SetRequestHeader "Connection", "keep-alive"
WinHttpReq.send
Sleep (5000) ' delay 4 second
Debug.Print WinHttpReq.readyState

MyURL = WinHttpReq.responseBody
If WinHttpReq.Status = 200 Then
    Set oStream = CreateObject("ADODB.Stream")
    oStream.Open
    oStream.Type = 1
    oStream.Write WinHttpReq.responseBody
    ' 1 = no overwrite, 2 = overwrite
    oStream.SaveToFile "D:\Visual Basic Programming\Macro\nasdaqomx\SODWeightings_20150819_NDX.xlsx", 2
    oStream.Close
End If

End Sub

Так в чем же проблема? У меня есть действительные учетные данные для этого, так как ручной вход работает нормально. Ниже приведен снимок экрана с html-кодом этой страницы. Он показывает какой-то код подтверждения запроса, но каждый раз, когда я замечаю, он меняется. Может ли кто-нибудь сказать мне, как программно выполнить вход на веб-страницу?

снимок экрана html страницы входа


person pmr    schedule 22.08.2015    source источник
comment
Вы не читаете скрытый элемент ввода для токена и не передаете его обратно в строке отправки. Иногда вам нужно передать назад, казалось бы, безобидные элементы ввода, такие как submit. Лучше всего использовать такой инструмент, как Fiddler, чтобы проверить, какая строка POST передается и куда при ручном входе в систему.   -  person    schedule 23.08.2015
comment
Я подозревал это .... не могли бы вы опубликовать код, как прочитать скрытый элемент ввода для токена и отправить его обратно   -  person pmr    schedule 23.08.2015


Ответы (1)


Я не могу опубликовать «код», но могу опубликовать некоторую структуру. Если у вас возникли проблемы с этим, используйте Fiddler, чтобы проверить скрытую строку POST при успешном входе в систему и продублировать ее. .

Метод состоит в том, чтобы сначала ПОЛУЧИТЬ страницу и прочитать токен. Добавьте токен и любые другие случайные элементы формы ‹input› в строку отправки и отправьте сообщение POST.

Я сделал некоторые вары общедоступными, так как они могут использоваться в других процедурах. Убедитесь, что у вас нет двух объявлений Option Explicit в верхней части листа модуля.

Option Explicit

Public pUSR As String
Public pPWD As String
'you might need this elsewhere; make it a public string
Public pTOKENID As String
'you might need one of these too
Public pJSESSIONID As String
'you want to go here
Public Const csLOGINpg = "https://indexes.nasdaqomx.com/Account/LogOn"
Public Const csTOKENnm = "__RequestVerificationToken"

Sub mcr_XML_LogIn()
    Dim htmlBDY As New MSHTML.HTMLDocument, xmlHTTP As New MSXML2.ServerXMLHTTP60

    Dim iEL As Long, xmlSend As String

    On Error GoTo bm_Err_Report

    pJSESSIONID = vbNullString
    pTOKENID = vbNullString
    pUSR = "xxxxxx"
    pPWD = "xxxxxxx"

    With xmlHTTP
        .Open "GET", csLOGINpg, False
        .SetRequestHeader "Content-Type", "text/html;charset=UTF-8"
        .SetRequestHeader "Connection", "keep-alive"
        .send

        htmlBDY.body.innerHTML = .responseText

        If CBool(htmlBDY.getElementsByTagName("form").Length) Then
            With htmlBDY.getElementsByTagName("form")(0)
                For iEL = 0 To (.getElementsByTagName("input").Length - 1)
                    If htmlBDY.getElementsByTagName("input")(iEL).Name = csTOKENnm Then
                        pTOKENID = htmlBDY.getElementsByTagName("input")(iEL).Value
                        Exit For
                    End If
                Next iEL
            End With
        End If

        .Open "POST", csLOGINpg, False
        .SetRequestHeader "Content-type", "application/x-www-form-urlencoded"
        .SetRequestHeader "Connection", "keep-alive"
        'you may need to send a JSESSIONID cookie; Fiddler will tell you this and other stuff
        '.SetRequestHeader "Cookie", "JSESSIONID=" & pJSESSIONID
        xmlSend = csTOKENnm & Chr(61) & pTOKENID & "&RememberMe=false&UserName=" & pUSR & "&Password=" & pPWD
        Debug.Print xmlSend

        .send xmlSend
        htmlBDY.body.innerHTML = .responseText
    End With  'done with the xmlHTTP object for now

    'do something with what you received here (maybe check for a successful log-in)
    Debug.Print Left(htmlBDY.body.innerHTML, 1024)

    GoTo bm_Safe_Exit

bm_Err_Report:
    Debug.Print Err.Number & " - " & Err.Description

bm_Safe_Exit:
    Set htmlBDY = Nothing
    Set xmlHTTP = Nothing
End Sub

Да, это основано на объекте MSXML2.ServerXMLHTTP60, но это тот объект, который хранит IO и который можно легко отредактировать для публичного распространения.

Если вы используете этот код, не изменяя его на WinHTTP, вам потребуются справочные библиотеки Microsoft XML v6.0 и Microsoft Internet Controls, добавленные в Инструменты ► Справочники VBE.

Я просмотрел это, чтобы убедиться, что нахожусь на нужной странице. Строка xmlSend была,

 __RequestVerificationToken=RHr1FDomqqHEZQJPmMVqdwoFKVsK43uE3j1g+IWRF3nHqmxZGDyAxpUWqes2XCKgHVhHPnpLCcn3EOIKHJ30EoQbBOhV16IkS7oqPQm+3x5cex0GAWzfUYuzOGGYM35/Xa6jsXF7YsN78b3TzadIwS/8EENNdA6jSqtXgH7cDU/FNIRuMJQbO9dplwtglcg8&RememberMe=false&UserName=xxxxxx&Password=xxxxxxx

... так он получал токен. Первые 1024 символа .innerHTML были:

<HEADER id=headerContent class=spacer>
<DIV id=logoRow class=row-fluid>
<DIV class=container>
<DIV class=row-fluid>
<DIV class=span6><A class=noLinkExternal href="http://nasdaqomx.com/"><IMG id=Nasdaqlogo style="MARGIN-RIGHT: -3px" alt="Nasdaq logo" src="about:/Content/Images/nasdaq_logo.png"></A> <A href="about:/"><IMG id=logo alt="Nasdaq Global Indexes" src="about:/Content/Images/global_indexes.png"></A> </DIV>
<DIV class=span6>
<DIV class=floatRight>
<UL id=loginList class=hideListStyle>
<LI class=hidden-phone><A id=LoginLink class=noLinkExternal>Log In</A></LI>
<LI class=visible-phone><A href="about:/Account/LogOn">Log In</A></LI>
<LI><A href="about:/Home/IndexData">Register</A></LI></UL><INPUT id=siteSearch class=ui-autocomplete-input value=Search> </DIV></DIV></DIV></DIV></DIV>
<DIV id=menuContainer>
<DIV class=container>
<DIV class=row-fluid>
<DIV class=span12>
<DIV id=LoginPanel class=inputForm>
<FORM method=post action=/Account/LogOn><INPUT type=hidden value=EpSOScbAMNDv1lIjBnm8Xew4Rn

Надеюсь это поможет. Используйте Fiddler для решения любых проблем. Извините, но без действительных учетных данных я больше ничего не могу сделать.

person Community    schedule 23.08.2015
comment
Можете ли вы порекомендовать любую прикладную книгу, чтобы изучить технические детали механизма входа в Java на веб-сайте - person pmr; 23.08.2015
comment
Рад, что это было полезно. Извините, но у меня нет справочных материалов, которые можно было бы порекомендовать, кроме форума xmlHTTP здесь это хорошо, и я делаю свой вклад, когда могу. - person ; 23.08.2015
comment
не могли бы вы опубликовать структуру для выхода из системы на этой странице - person pmr; 23.08.2015
comment
Честно говоря, вам просто нужно уничтожить объект xmlHTTP. Если вы создадите новый сразу, в нем не будет отголосков первого. На практике, однако, я уважаю намерения веб-мастера и использую страницу выхода из системы в качестве URL-адреса в действии GET. - person ; 23.08.2015
comment
Привет! Я только что понял. Если вы хотите выйти из системы, значит, вы успешно вошли в систему! Отличная работа! - person ; 23.08.2015
comment
Не могли бы вы поделиться своим адресом электронной почты на [email protected], теперь помощь скрипачу, который я делаю .SetRequestHeader Cookie, ASP.NET_SessionId = & pJSESSIONID, но теперь опубликуйте журнал в запросе GET либо это фиктивные данные 2 col в excel (как если бы нет входа в систему) или xmlHTTP.responseText - -2147483638 - данные, необходимые для выполнения этой операции, пока недоступны. кажется, мне нужно дождаться xmlHTTP.Status = 200 ... так капризно - person pmr; 23.08.2015
comment
Если вы хотите, чтобы я попробовал эту процедуру с учетными данными, вы можете найти адрес электронной почты на странице моего профиля здесь. - person ; 23.08.2015
comment
Спасибо, сэр, в параллельных усилиях я использовал объекты IE, а затем структуру UIAutomationCore.dll для обработки предупреждений о всплывающих кадрах загрузки, так что на данный момент все в порядке ... но определенно я свяжусь с вами в этом подходе XML, потому что это много стабильнее и быстрее. - person pmr; 23.08.2015