2014-01-24 2 views
4

Я свободно признаю, что я не слишком разбираюсь в библиотеке объектов HTML.VBA: Несогласованная ошибка 91 в цикле с ссылкой на IE.doc

У меня есть таблица с идентификационными номерами работодателей IRS, которые я должен идентифицировать как находящиеся в моей базе данных или нет. У меня есть только веб-доступ к этой базе данных, к которой некоторые другие люди пишут HTML и управляют базой данных. Я считаю, что их методы устарели, а их проектная практика невелика; но я не в конечном счете менеджер базы данных, так что я знаю? Таким образом, нормальная практика на моем конце - это ввести EIN на странице поиска и отметить результат.

My Excel макрос предназначен для

  1. Войдите на сайт, веб-запросов к базе данных.

  2. шлейф через Eins, отметив, которые EINS найдены

Однако, у меня есть следующие проблемы:

  • A. Часть Войти работает хорошо, но с одной причудой: Я должен оставить «If Then Else», который проверяет, что логин был успешным (или нет) , а не сбой входа. Учитывая, что после «входа в систему» ​​появляется «If Then Else» , это совершенно непонятно.
  • B. Единственный способ узнать, есть ли EIN в базе данных, это посмотреть на внутренний текст и посмотреть, возникает ли EIN на странице в результате запроса . Это не работает, т. Е. Я получаю только положительный результат, когда (при тестировании) Я запрашиваю одну и ту же EIN дважды подряд. (Я получаю удар на второй EIN.)
  • C. В цикле я получаю несогласованные ошибки 91 (переменная объекта не ). Иногда цикл завершается; иногда он висит, но никогда в на том же месте.

Мой код выглядит следующим образом (хотя я должен был изменить URL-адреса):

Option Explicit 
Sub FillFromWorkbookTest() 

On Error GoTo ErrHandler 

Const cURL = "https://www.someURL.com/LoginPage.jsp" 
Const cUsername = "myUSERNAME" 
Const cPassword = "myPASSWORD" 
Dim IE As Object 
Dim Doc As HTMLDocument 
Dim LoginForm As HTMLFormElement 
Dim UsernameInput As HTMLInputElement 
Dim PasswordInput As HTMLInputElement 
Dim LoginButton As HTMLInputButtonElement 
Dim SearchForm As HTMLFormElement 
Dim EINInput As HTMLInputElement 
Dim SearchButton As HTMLInputButtonElement 
Dim cEIN As String 
Dim BotRow As Long 
Dim EINRange As Range 
Dim c As Variant 
Dim i As Integer 
Dim EINCheck As String 
Dim EINCount As Integer 

'## Open Browser & go to Admin Module, and Login 
Set IE = CreateObject("InternetExplorer.Application") 
IE.Visible = True 
IE.Navigate cURL 

'## Wait for Adimn Module to load 
Do Until IE.ReadyState = 4 
    DoEvents 
Loop 

'## Get the HTML Document of Admin Module login page (cURL) 
Set Doc = IE.document 

'## Get Admin Module login form 
Set LoginForm = Doc.forms("f1") 

'## Get Username input field and populate it 
'## HTML: <input id=EIN type=text tabindex=3 size=9 maxlength=9 name=EIN title="Admin Code"> 
Set UsernameInput = LoginForm.elements("EIN") 
UsernameInput.Value = cUsername 

'## Get Password input field and populate it 
'## HTML: <input id=PIN type=password tabindex=4 size=8 maxlength=8 name=PIN title="PIN"> 
Set PasswordInput = LoginForm.elements("PIN") 
PasswordInput.Value = cPassword 

'## Submit LoginForm 
'## HTML: <input type=submit value=Login tabindex=5 title="Login"> (no onClick attribute; no element) 
LoginForm.submit 

Do Until IE.ReadyState = 4 
    DoEvents 
Loop 

'## Get the HTML Document of the new page 
Set Doc = IE.document 

'## Determine if login succeeded 
If InStr(Doc.body.innerText, "Invalid Login.") = 0 Then 
    MsgBox "Login successful." 
Else 
    MsgBox "Login failed." 
End If 

Debug.Print "Current URL: " & IE.LocationURL 

'## Navigate to Global Change and reset HTML Document 
IE.Navigate "https://www.someURL.com/LOGGED_IN/SomePage.jsp" 

Do Until IE.ReadyState = 4 
    DoEvents 
Loop 

Set Doc = IE.document 

'## Find last row in spreadsheet 
BotRow = Worksheets("Sheet1").Range("A1").End(xlDown).Row 
Set EINRange = Range("A1:A" & BotRow) 

'## Set loop counter variable 
i = 0 

'## Cycle through IRS-identified EINs 
For Each c In EINRange.Cells 

    cEIN = c.Value 
    i = i + 1 

'## Get Admin Module login form 
    Set SearchForm = Doc.forms(0) 

'## Get EIN input field and populate it 
'## HTML: <input type="text" id=EIN name=EIN title="Enter charity EIN" maxlength=9 size=9 tabindex=11 > 
    Set EINInput = SearchForm.elements("EIN") 
    EINInput.Value = cEIN 

'## Submit SearchForm 
'## HTML: <input type="submit" value="Search" tabindex=15 title="Click here to search charity application" class="black_bold" 
'##  onclick="if (btn_OnClick(EIN,CODE)) {document.f1.action='SomeOther.jsp'; document.f1.submit(); return true;} else return false;" > 
'##  (has onClick attribute) 

    Set SearchButton = Doc.body.getElementsByTagName("table")(2). _ 
     getElementsByTagName("tr")(0). _ 
     getElementsByTagName("td")(0). _ 
     getElementsByTagName("input")(2) 
    SearchButton.Click 

    Do Until IE.ReadyState = 4 
     DoEvents 
    Loop 

'## Get the HTML Document of the new page 
    Set Doc = IE.document 

'## Find EIN string on resulting page; Some number if found; Null if not 
    EINCheck = Doc.body.getElementsByTagName("table")(3).innerText 
    EINCount = InStr(1, EINCheck, cEIN, 1) 
    MsgBox EINCount 

'## Determine which EINs are CFC charities 
    If InStr(1, EINCheck, cEIN, 1) = 0 Then 
     Worksheets("Sheet1").Range("F" & i).Value = "NO" 
    Else 
     Worksheets("Sheet1").Range("F" & i).Value = "YES" 
    End If 

Next c 

ErrHandler: 
'## Cleanup 
MsgBox "Error" & Err.Number & ": " & Err.Description 
Set IE = Nothing 
Set Doc = Nothing 
Set LoginForm = Nothing 
Set UsernameInput = Nothing 
Set PasswordInput = Nothing 
Set LoginButton = Nothing 
Set SearchForm = Nothing 
Set EINInput = Nothing 
Set SearchButton = Nothing 

End Sub 

Любые предложения?

ответ

9

Я нашел лучший успех, используя следующий за «ждать, пока IE не будет готов»

Public Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long) 
Public Function IEWait(p_ieExp As InternetExplorer) 

    'this should go from ready-busy-ready 
    Dim initialReadyState As Integer 
    initialReadyState = p_ieExp.ReadyState 

    'wait 250 ms until it's done 
    Do While p_ieExp.Busy Or p_ieExp.ReadyState <> READYSTATE_COMPLETE 
     Sleep 250 
    Loop 

End Function 

Вы бы назвали это как

IEWait IE 'your internet explorer is named "IE" 

я впадающей слишком много изворотливый ошибки с использованием только одного из условий для «готовности». После изменения моих «готовых» проверок на этот метод это почти на 100% ушло. Иногда состояние готовности не отражает состояние точно.

Что касается ваших первых вопросов, используя метод Sleep, о котором я упоминал выше, попробуйте добавить Sleep 1000 или около того перед каждой из ваших команд, чтобы проверить, что проблема в вашей логике, а не в загрузке IE слишком медленно. Или медленно переходите к отладчику.

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

+1

Enderland: Вы красивый человек. Это потрясающе! и работает как шарм. Это прояснило все проблемы, которые у меня были. Благодаря! – user3232254

+0

@ user3232254 рад помочь! – enderland

+1

FYI - Мне нужно было добавить ссылку на «Microsoft Internet Controls», чтобы это работало. –

Смежные вопросы